aboutsummaryrefslogtreecommitdiff
path: root/fesvr
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2019-03-31 00:49:57 -0700
committerAndrew Waterman <andrew@sifive.com>2019-03-31 00:50:15 -0700
commitf49618ca9d674ec7e596118f85027c4b503862ac (patch)
tree3b6ad73cbe8760309f930b743950a2853ad17668 /fesvr
parent61cb96df00067ba61cf3816c74c18aef5677197a (diff)
downloadriscv-isa-sim-f49618ca9d674ec7e596118f85027c4b503862ac.zip
riscv-isa-sim-f49618ca9d674ec7e596118f85027c4b503862ac.tar.gz
riscv-isa-sim-f49618ca9d674ec7e596118f85027c4b503862ac.tar.bz2
Add fesvr; only globally install fesvr headers/libsstatic-link
Diffstat (limited to 'fesvr')
-rw-r--r--fesvr/context.cc115
-rw-r--r--fesvr/context.h54
-rw-r--r--fesvr/debug_defines.h1418
-rw-r--r--fesvr/device.cc155
-rw-r--r--fesvr/device.h118
-rw-r--r--fesvr/dtm.cc642
-rw-r--r--fesvr/dtm.h115
-rw-r--r--fesvr/dummy.cc4
-rw-r--r--fesvr/elf.h121
-rw-r--r--fesvr/elf2hex.cc47
-rw-r--r--fesvr/elfloader.cc89
-rw-r--r--fesvr/elfloader.h13
-rw-r--r--fesvr/encoding.h1471
-rw-r--r--fesvr/fesvr.ac1
-rw-r--r--fesvr/fesvr.mk.in38
-rw-r--r--fesvr/fesvr.pc.in26
-rw-r--r--fesvr/htif.cc329
-rw-r--r--fesvr/htif.h114
-rw-r--r--fesvr/htif_hexwriter.cc76
-rw-r--r--fesvr/htif_hexwriter.h32
-rw-r--r--fesvr/htif_pthread.cc66
-rw-r--r--fesvr/htif_pthread.h38
-rw-r--r--fesvr/memif.cc183
-rw-r--r--fesvr/memif.h62
-rw-r--r--fesvr/option_parser.cc51
-rw-r--r--fesvr/option_parser.h31
-rw-r--r--fesvr/rfb.cc230
-rw-r--r--fesvr/rfb.h53
-rw-r--r--fesvr/syscall.cc394
-rw-r--r--fesvr/syscall.h72
-rw-r--r--fesvr/term.cc53
-rw-r--r--fesvr/term.h11
-rw-r--r--fesvr/tsi.cc115
-rw-r--r--fesvr/tsi.h57
34 files changed, 6394 insertions, 0 deletions
diff --git a/fesvr/context.cc b/fesvr/context.cc
new file mode 100644
index 0000000..ca73813
--- /dev/null
+++ b/fesvr/context.cc
@@ -0,0 +1,115 @@
+#include "context.h"
+#include <assert.h>
+#include <sched.h>
+#include <stdlib.h>
+
+static __thread context_t* cur;
+
+context_t::context_t()
+ : creator(NULL), func(NULL), arg(NULL),
+#ifndef USE_UCONTEXT
+ mutex(PTHREAD_MUTEX_INITIALIZER),
+ cond(PTHREAD_COND_INITIALIZER), flag(0)
+#else
+ context(new ucontext_t)
+#endif
+{
+}
+
+#ifdef USE_UCONTEXT
+#ifndef GLIBC_64BIT_PTR_BUG
+void context_t::wrapper(context_t* ctx)
+{
+#else
+void context_t::wrapper(unsigned int hi, unsigned int lo)
+{
+ context_t* ctx = reinterpret_cast<context_t*>(static_cast<unsigned long>(lo) | (static_cast<unsigned long>(hi) << 32));
+#endif
+ ctx->creator->switch_to();
+ ctx->func(ctx->arg);
+}
+#else
+void* context_t::wrapper(void* a)
+{
+ context_t* ctx = static_cast<context_t*>(a);
+ cur = ctx;
+ ctx->creator->switch_to();
+
+ ctx->func(ctx->arg);
+ return NULL;
+}
+#endif
+
+void context_t::init(void (*f)(void*), void* a)
+{
+ func = f;
+ arg = a;
+ creator = current();
+
+#ifdef USE_UCONTEXT
+ getcontext(context.get());
+ context->uc_link = creator->context.get();
+ context->uc_stack.ss_size = 64*1024;
+ context->uc_stack.ss_sp = new void*[context->uc_stack.ss_size/sizeof(void*)];
+#ifndef GLIBC_64BIT_PTR_BUG
+ makecontext(context.get(), (void(*)(void))&context_t::wrapper, 1, this);
+#else
+ unsigned int hi(reinterpret_cast<unsigned long>(this) >> 32);
+ unsigned int lo(reinterpret_cast<unsigned long>(this));
+ makecontext(context.get(), (void(*)(void))&context_t::wrapper, 2, hi, lo);
+#endif
+ switch_to();
+#else
+ assert(flag == 0);
+
+ pthread_mutex_lock(&creator->mutex);
+ creator->flag = 0;
+ if (pthread_create(&thread, NULL, &context_t::wrapper, this) != 0)
+ abort();
+ pthread_detach(thread);
+ while (!creator->flag)
+ pthread_cond_wait(&creator->cond, &creator->mutex);
+ pthread_mutex_unlock(&creator->mutex);
+#endif
+}
+
+context_t::~context_t()
+{
+ assert(this != cur);
+}
+
+void context_t::switch_to()
+{
+ assert(this != cur);
+#ifdef USE_UCONTEXT
+ context_t* prev = cur;
+ cur = this;
+ if (swapcontext(prev->context.get(), context.get()) != 0)
+ abort();
+#else
+ cur->flag = 0;
+ this->flag = 1;
+ pthread_mutex_lock(&this->mutex);
+ pthread_cond_signal(&this->cond);
+ pthread_mutex_unlock(&this->mutex);
+ pthread_mutex_lock(&cur->mutex);
+ while (!cur->flag)
+ pthread_cond_wait(&cur->cond, &cur->mutex);
+ pthread_mutex_unlock(&cur->mutex);
+#endif
+}
+
+context_t* context_t::current()
+{
+ if (cur == NULL)
+ {
+ cur = new context_t;
+#ifdef USE_UCONTEXT
+ getcontext(cur->context.get());
+#else
+ cur->thread = pthread_self();
+ cur->flag = 1;
+#endif
+ }
+ return cur;
+}
diff --git a/fesvr/context.h b/fesvr/context.h
new file mode 100644
index 0000000..18bf50e
--- /dev/null
+++ b/fesvr/context.h
@@ -0,0 +1,54 @@
+#ifndef _HTIF_CONTEXT_H
+#define _HTIF_CONTEXT_H
+
+// A replacement for ucontext.h, which is sadly deprecated.
+
+#include <pthread.h>
+
+#if defined(__GLIBC__)
+# undef USE_UCONTEXT
+# define USE_UCONTEXT
+# include <ucontext.h>
+# include <memory>
+#include <limits.h>
+
+#if (ULONG_MAX > UINT_MAX) // 64-bit systems only
+#if (100*GLIB_MAJOR_VERSION+GLIB_MINOR_VERSION < 208)
+#define GLIBC_64BIT_PTR_BUG
+static_assert (sizeof(unsigned int) == 4, "uint size doesn't match expected 32bit");
+static_assert (sizeof(unsigned long) == 8, "ulong size doesn't match expected 64bit");
+static_assert (sizeof(void*) == 8, "ptr size doesn't match expected 64bit");
+#endif
+#endif /* ULONG_MAX > UINT_MAX */
+
+#endif
+
+class context_t
+{
+ public:
+ context_t();
+ ~context_t();
+ void init(void (*func)(void*), void* arg);
+ void switch_to();
+ static context_t* current();
+ private:
+ context_t* creator;
+ void (*func)(void*);
+ void* arg;
+#ifdef USE_UCONTEXT
+ std::unique_ptr<ucontext_t> context;
+#ifndef GLIBC_64BIT_PTR_BUG
+ static void wrapper(context_t*);
+#else
+ static void wrapper(unsigned int, unsigned int);
+#endif
+#else
+ pthread_t thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ volatile int flag;
+ static void* wrapper(void*);
+#endif
+};
+
+#endif
diff --git a/fesvr/debug_defines.h b/fesvr/debug_defines.h
new file mode 100644
index 0000000..e5f9291
--- /dev/null
+++ b/fesvr/debug_defines.h
@@ -0,0 +1,1418 @@
+#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.13 (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 and \Faddress. (nop)
+*
+* Don't send anything over the DMI during Update-DR.
+* This operation should never result in a busy or error response.
+* The address and data reported in the following Capture-DR
+* are undefined.
+*
+* 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.
+*
+* 4: External debug support exists as it is described in this document.
+ */
+#define CSR_DCSR_XDEBUGVER_OFFSET 28
+#define CSR_DCSR_XDEBUGVER_LENGTH 4
+#define CSR_DCSR_XDEBUGVER (0xf << 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_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)
+/*
+* 0: There is no Debug Module present.
+*
+* 1: There is a Debug Module and it conforms to version 0.11 of this
+* specification.
+*
+* 2: There is a Debug Module and it conforms to version 0.13 of this
+* specification.
+ */
+#define DMI_DMSTATUS_VERSION_OFFSET 0
+#define DMI_DMSTATUS_VERSION_LENGTH 4
+#define DMI_DMSTATUS_VERSION (0xf << DMI_DMSTATUS_VERSION_OFFSET)
+#define DMI_DMCONTROL 0x10
+/*
+* Halt request signal for all currently selected harts. When set to
+* 1, each selected hart will halt if it is not currently halted.
+*
+* Writing 1 or 0 has no effect on a hart which is already halted, but
+* the bit should be cleared to 0 before the hart is resumed.
+* 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,
+* each selected 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 system reset the debugger writes 1,
+* and then writes 0
+* to deassert the reset. This bit must not reset the Debug Module
+* registers. What it does reset is platform-specific (it may
+* reset nothing).
+ */
+#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 may pulse this bit low to get the debug module into a
+* known state.
+*
+* 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,
+* \Rabstractcs, \Rabstractauto was written, or when one
+* of the {\tt data} or {\tt progbuf} registers was read or written.
+*
+* 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 - 12.
+ */
+#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 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}.
+* \Rdpc may be used as an alias for PC if this command is
+* supported on a non-halted hart.
+ */
+#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)
+#define VIRT_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 VIRT_PRIV_PRV_OFFSET 0
+#define VIRT_PRIV_PRV_LENGTH 2
+#define VIRT_PRIV_PRV (0x3 << VIRT_PRIV_PRV_OFFSET)
diff --git a/fesvr/device.cc b/fesvr/device.cc
new file mode 100644
index 0000000..3a4cc95
--- /dev/null
+++ b/fesvr/device.cc
@@ -0,0 +1,155 @@
+#include "device.h"
+#include "term.h"
+#include "memif.h"
+#include <cassert>
+#include <algorithm>
+#include <climits>
+#include <iostream>
+#include <thread>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+using namespace std::placeholders;
+
+device_t::device_t()
+ : command_handlers(command_t::MAX_COMMANDS),
+ command_names(command_t::MAX_COMMANDS)
+{
+ for (size_t cmd = 0; cmd < command_t::MAX_COMMANDS; cmd++)
+ register_command(cmd, std::bind(&device_t::handle_null_command, this, _1), "");
+ register_command(command_t::MAX_COMMANDS-1, std::bind(&device_t::handle_identify, this, _1), "identity");
+}
+
+void device_t::register_command(size_t cmd, command_func_t handler, const char* name)
+{
+ assert(cmd < command_t::MAX_COMMANDS);
+ assert(strlen(name) < IDENTITY_SIZE);
+ command_handlers[cmd] = handler;
+ command_names[cmd] = name;
+}
+
+void device_t::handle_command(command_t cmd)
+{
+ command_handlers[cmd.cmd()](cmd);
+}
+
+void device_t::handle_null_command(command_t cmd)
+{
+}
+
+void device_t::handle_identify(command_t cmd)
+{
+ size_t what = cmd.payload() % command_t::MAX_COMMANDS;
+ uint64_t addr = cmd.payload() / command_t::MAX_COMMANDS;
+ assert(addr % IDENTITY_SIZE == 0);
+
+ char id[IDENTITY_SIZE] = {0};
+ if (what == command_t::MAX_COMMANDS-1)
+ {
+ assert(strlen(identity()) < IDENTITY_SIZE);
+ strcpy(id, identity());
+ }
+ else
+ strcpy(id, command_names[what].c_str());
+
+ cmd.memif().write(addr, IDENTITY_SIZE, id);
+ cmd.respond(1);
+}
+
+bcd_t::bcd_t()
+{
+ register_command(0, std::bind(&bcd_t::handle_read, this, _1), "read");
+ register_command(1, std::bind(&bcd_t::handle_write, this, _1), "write");
+}
+
+void bcd_t::handle_read(command_t cmd)
+{
+ pending_reads.push(cmd);
+}
+
+void bcd_t::handle_write(command_t cmd)
+{
+ canonical_terminal_t::write(cmd.payload());
+}
+
+void bcd_t::tick()
+{
+ int ch;
+ if (!pending_reads.empty() && (ch = canonical_terminal_t::read()) != -1)
+ {
+ pending_reads.front().respond(0x100 | ch);
+ pending_reads.pop();
+ }
+}
+
+disk_t::disk_t(const char* fn)
+{
+ fd = ::open(fn, O_RDWR);
+ if (fd < 0)
+ throw std::runtime_error("could not open " + std::string(fn));
+
+ register_command(0, std::bind(&disk_t::handle_read, this, _1), "read");
+ register_command(1, std::bind(&disk_t::handle_write, this, _1), "write");
+
+ struct stat st;
+ if (fstat(fd, &st) < 0)
+ throw std::runtime_error("could not stat " + std::string(fn));
+
+ size = st.st_size;
+ id = "disk size=" + std::to_string(size);
+}
+
+disk_t::~disk_t()
+{
+ close(fd);
+}
+
+void disk_t::handle_read(command_t cmd)
+{
+ request_t req;
+ cmd.memif().read(cmd.payload(), sizeof(req), &req);
+
+ std::vector<uint8_t> buf(req.size);
+ if ((size_t)::pread(fd, &buf[0], buf.size(), req.offset) != req.size)
+ throw std::runtime_error("could not read " + id + " @ " + std::to_string(req.offset));
+
+ cmd.memif().write(req.addr, buf.size(), &buf[0]);
+ cmd.respond(req.tag);
+}
+
+void disk_t::handle_write(command_t cmd)
+{
+ request_t req;
+ cmd.memif().read(cmd.payload(), sizeof(req), &req);
+
+ std::vector<uint8_t> buf(req.size);
+ cmd.memif().read(req.addr, buf.size(), &buf[0]);
+
+ if ((size_t)::pwrite(fd, &buf[0], buf.size(), req.offset) != req.size)
+ throw std::runtime_error("could not write " + id + " @ " + std::to_string(req.offset));
+
+ cmd.respond(req.tag);
+}
+
+device_list_t::device_list_t()
+ : devices(command_t::MAX_COMMANDS, &null_device), num_devices(0)
+{
+}
+
+void device_list_t::register_device(device_t* dev)
+{
+ num_devices++;
+ assert(num_devices < command_t::MAX_DEVICES);
+ devices[num_devices-1] = dev;
+}
+
+void device_list_t::handle_command(command_t cmd)
+{
+ devices[cmd.device()]->handle_command(cmd);
+}
+
+void device_list_t::tick()
+{
+ for (size_t i = 0; i < num_devices; i++)
+ devices[i]->tick();
+}
diff --git a/fesvr/device.h b/fesvr/device.h
new file mode 100644
index 0000000..1387b74
--- /dev/null
+++ b/fesvr/device.h
@@ -0,0 +1,118 @@
+#ifndef _DEVICE_H
+#define _DEVICE_H
+
+#include <vector>
+#include <queue>
+#include <cstring>
+#include <string>
+#include <functional>
+
+class memif_t;
+
+class command_t
+{
+ public:
+ typedef std::function<void(uint64_t)> callback_t;
+ command_t(memif_t& memif, uint64_t tohost, callback_t cb)
+ : _memif(memif), tohost(tohost), cb(cb) {}
+
+ memif_t& memif() { return _memif; }
+ uint8_t device() { return tohost >> 56; }
+ uint8_t cmd() { return tohost >> 48; }
+ uint64_t payload() { return tohost << 16 >> 16; }
+ void respond(uint64_t resp) { cb((tohost >> 48 << 48) | (resp << 16 >> 16)); }
+
+ static const size_t MAX_COMMANDS = 256;
+ static const size_t MAX_DEVICES = 256;
+
+ private:
+ memif_t& _memif;
+ uint64_t tohost;
+ callback_t cb;
+};
+
+class device_t
+{
+ public:
+ device_t();
+ virtual ~device_t() {}
+ virtual const char* identity() = 0;
+ virtual void tick() {}
+
+ void handle_command(command_t cmd);
+
+ protected:
+ typedef std::function<void(command_t)> command_func_t;
+ void register_command(size_t, command_func_t, const char*);
+
+ private:
+ device_t& operator = (const device_t&); // disallow
+ device_t(const device_t&); // disallow
+
+ static const size_t IDENTITY_SIZE = 64;
+ void handle_null_command(command_t cmd);
+ void handle_identify(command_t cmd);
+
+ std::vector<command_func_t> command_handlers;
+ std::vector<std::string> command_names;
+};
+
+class bcd_t : public device_t
+{
+ public:
+ bcd_t();
+ const char* identity() { return "bcd"; }
+ void tick();
+
+ private:
+ void handle_read(command_t cmd);
+ void handle_write(command_t cmd);
+
+ std::queue<command_t> pending_reads;
+};
+
+class disk_t : public device_t
+{
+ public:
+ disk_t(const char* fn);
+ ~disk_t();
+ const char* identity() { return id.c_str(); }
+
+ private:
+ struct request_t
+ {
+ uint64_t addr;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t tag;
+ };
+
+ void handle_read(command_t cmd);
+ void handle_write(command_t cmd);
+
+ std::string id;
+ size_t size;
+ int fd;
+};
+
+class null_device_t : public device_t
+{
+ public:
+ const char* identity() { return ""; }
+};
+
+class device_list_t
+{
+ public:
+ device_list_t();
+ void register_device(device_t* dev);
+ void handle_command(command_t cmd);
+ void tick();
+
+ private:
+ std::vector<device_t*> devices;
+ null_device_t null_device;
+ size_t num_devices;
+};
+
+#endif
diff --git a/fesvr/dtm.cc b/fesvr/dtm.cc
new file mode 100644
index 0000000..5409321
--- /dev/null
+++ b/fesvr/dtm.cc
@@ -0,0 +1,642 @@
+#include "dtm.h"
+#include "debug_defines.h"
+#include "encoding.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <pthread.h>
+
+#define RV_X(x, s, n) \
+ (((x) >> (s)) & ((1 << (n)) - 1))
+#define ENCODE_ITYPE_IMM(x) \
+ (RV_X(x, 0, 12) << 20)
+#define ENCODE_STYPE_IMM(x) \
+ ((RV_X(x, 0, 5) << 7) | (RV_X(x, 5, 7) << 25))
+#define ENCODE_SBTYPE_IMM(x) \
+ ((RV_X(x, 1, 4) << 8) | (RV_X(x, 5, 6) << 25) | (RV_X(x, 11, 1) << 7) | (RV_X(x, 12, 1) << 31))
+#define ENCODE_UTYPE_IMM(x) \
+ (RV_X(x, 12, 20) << 12)
+#define ENCODE_UJTYPE_IMM(x) \
+ ((RV_X(x, 1, 10) << 21) | (RV_X(x, 11, 1) << 20) | (RV_X(x, 12, 8) << 12) | (RV_X(x, 20, 1) << 31))
+
+#define LOAD(xlen, dst, base, imm) \
+ (((xlen) == 64 ? 0x00003003 : 0x00002003) \
+ | ((dst) << 7) | ((base) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
+#define STORE(xlen, src, base, imm) \
+ (((xlen) == 64 ? 0x00003023 : 0x00002023) \
+ | ((src) << 20) | ((base) << 15) | (uint32_t)ENCODE_STYPE_IMM(imm))
+#define JUMP(there, here) (0x6f | (uint32_t)ENCODE_UJTYPE_IMM((there) - (here)))
+#define BNE(r1, r2, there, here) (0x1063 | ((r1) << 15) | ((r2) << 20) | (uint32_t)ENCODE_SBTYPE_IMM((there) - (here)))
+#define ADDI(dst, src, imm) (0x13 | ((dst) << 7) | ((src) << 15) | (uint32_t)ENCODE_ITYPE_IMM(imm))
+#define SRL(dst, src, sh) (0x5033 | ((dst) << 7) | ((src) << 15) | ((sh) << 20))
+#define FENCE_I 0x100f
+#define EBREAK 0x00100073
+#define X0 0
+#define S0 8
+#define S1 9
+
+#define AC_AR_REGNO(x) ((0x1000 | x) << AC_ACCESS_REGISTER_REGNO_OFFSET)
+#define AC_AR_SIZE(x) (((x == 128)? 4 : (x == 64 ? 3 : 2)) << AC_ACCESS_REGISTER_SIZE_OFFSET)
+
+#define WRITE 1
+#define SET 2
+#define CLEAR 3
+#define CSRRx(type, dst, csr, src) (0x73 | ((type) << 12) | ((dst) << 7) | ((src) << 15) | (uint32_t)((csr) << 20))
+
+#define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
+#define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
+
+#define RUN_AC_OR_DIE(a, b, c, d, e) { \
+ uint32_t cmderr = run_abstract_command(a, b, c, d, e); \
+ if (cmderr) { \
+ die(cmderr); \
+ } \
+ }
+
+uint32_t dtm_t::do_command(dtm_t::req r)
+{
+ req_buf = r;
+ target->switch_to();
+ assert(resp_buf.resp == 0);
+ return resp_buf.data;
+}
+
+uint32_t dtm_t::read(uint32_t addr)
+{
+ return do_command((req){addr, 1, 0});
+}
+
+uint32_t dtm_t::write(uint32_t addr, uint32_t data)
+{
+ return do_command((req){addr, 2, data});
+}
+
+void dtm_t::nop()
+{
+ do_command((req){0, 0, 0});
+}
+
+void dtm_t::select_hart(int hartsel) {
+ int dmcontrol = read(DMI_DMCONTROL);
+ write (DMI_DMCONTROL, set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel));
+ current_hart = hartsel;
+}
+
+int dtm_t::enumerate_harts() {
+ int max_hart = (1 << DMI_DMCONTROL_HARTSEL_LENGTH) - 1;
+ write(DMI_DMCONTROL, set_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL, max_hart));
+ read(DMI_DMSTATUS);
+ max_hart = get_field(read(DMI_DMCONTROL), DMI_DMCONTROL_HARTSEL);
+
+ int hartsel;
+ for (hartsel = 0; hartsel <= max_hart; hartsel++) {
+ select_hart(hartsel);
+ int dmstatus = read(DMI_DMSTATUS);
+ if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT))
+ break;
+ }
+ return hartsel;
+}
+
+void dtm_t::halt(int hartsel)
+{
+ if (running) {
+ write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
+ // Read dmstatus to avoid back-to-back writes to dmcontrol.
+ read(DMI_DMSTATUS);
+ }
+
+ int dmcontrol = DMI_DMCONTROL_HALTREQ | DMI_DMCONTROL_DMACTIVE;
+ dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
+ write(DMI_DMCONTROL, dmcontrol);
+ int dmstatus;
+ do {
+ dmstatus = read(DMI_DMSTATUS);
+ } while(get_field(dmstatus, DMI_DMSTATUS_ALLHALTED) == 0);
+ dmcontrol &= ~DMI_DMCONTROL_HALTREQ;
+ write(DMI_DMCONTROL, dmcontrol);
+ // Read dmstatus to avoid back-to-back writes to dmcontrol.
+ read(DMI_DMSTATUS);
+ current_hart = hartsel;
+}
+
+void dtm_t::resume(int hartsel)
+{
+ int dmcontrol = DMI_DMCONTROL_RESUMEREQ | DMI_DMCONTROL_DMACTIVE;
+ dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, hartsel);
+ write(DMI_DMCONTROL, dmcontrol);
+ int dmstatus;
+ do {
+ dmstatus = read(DMI_DMSTATUS);
+ } while (get_field(dmstatus, DMI_DMSTATUS_ALLRESUMEACK) == 0);
+ dmcontrol &= ~DMI_DMCONTROL_RESUMEREQ;
+ write(DMI_DMCONTROL, dmcontrol);
+ // Read dmstatus to avoid back-to-back writes to dmcontrol.
+ read(DMI_DMSTATUS);
+ current_hart = hartsel;
+
+ if (running) {
+ write(DMI_DMCONTROL, 0);
+ // Read dmstatus to avoid back-to-back writes to dmcontrol.
+ read(DMI_DMSTATUS);
+ }
+}
+
+uint64_t dtm_t::save_reg(unsigned regno)
+{
+ uint32_t data[xlen/(8*4)];
+ uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_SIZE(xlen) | AC_AR_REGNO(regno);
+ RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
+
+ uint64_t result = data[0];
+ if (xlen > 32) {
+ result |= ((uint64_t)data[1]) << 32;
+ }
+ return result;
+}
+
+void dtm_t::restore_reg(unsigned regno, uint64_t val)
+{
+ uint32_t data[xlen/(8*4)];
+ data[0] = (uint32_t) val;
+ if (xlen > 32) {
+ data[1] = (uint32_t) (val >> 32);
+ }
+
+ uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(regno);
+
+ RUN_AC_OR_DIE(command, 0, 0, data, xlen / (8*4));
+
+}
+
+uint32_t dtm_t::run_abstract_command(uint32_t command,
+ const uint32_t program[], size_t program_n,
+ uint32_t data[], size_t data_n)
+{
+ assert(program_n <= ram_words);
+ assert(data_n <= data_words);
+
+ for (size_t i = 0; i < program_n; i++) {
+ write(DMI_PROGBUF0 + i, program[i]);
+ }
+
+ if (get_field(command, AC_ACCESS_REGISTER_WRITE) &&
+ get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
+ for (size_t i = 0; i < data_n; i++) {
+ write(DMI_DATA0 + i, data[i]);
+ }
+ }
+
+ write(DMI_COMMAND, command);
+
+ // Wait for not busy and then check for error.
+ uint32_t abstractcs;
+ do {
+ abstractcs = read(DMI_ABSTRACTCS);
+ } while (abstractcs & DMI_ABSTRACTCS_BUSY);
+
+ if ((get_field(command, AC_ACCESS_REGISTER_WRITE) == 0) &&
+ get_field(command, AC_ACCESS_REGISTER_TRANSFER)) {
+ for (size_t i = 0; i < data_n; i++){
+ data[i] = read(DMI_DATA0 + i);
+ }
+ }
+
+ return get_field(abstractcs, DMI_ABSTRACTCS_CMDERR);
+
+}
+
+size_t dtm_t::chunk_align()
+{
+ return xlen / 8;
+}
+
+void dtm_t::read_chunk(uint64_t taddr, size_t len, void* dst)
+{
+ uint32_t prog[ram_words];
+ uint32_t data[data_words];
+
+ uint8_t * curr = (uint8_t*) dst;
+
+ halt(current_hart);
+
+ uint64_t s0 = save_reg(S0);
+ uint64_t s1 = save_reg(S1);
+
+ prog[0] = LOAD(xlen, S1, S0, 0);
+ prog[1] = ADDI(S0, S0, xlen/8);
+ prog[2] = EBREAK;
+
+ data[0] = (uint32_t) taddr;
+ if (xlen > 32) {
+ data[1] = (uint32_t) (taddr >> 32);
+ }
+
+ // Write s0 with the address, then execute program buffer.
+ // This will get S1 with the data and increment s0.
+ uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_ACCESS_REGISTER_POSTEXEC |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S0);
+
+ RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
+
+ // TODO: could use autoexec here.
+ for (size_t i = 0; i < (len * 8 / xlen); i++){
+ command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S1);
+ if ((i + 1) < (len * 8 / xlen)) {
+ command |= AC_ACCESS_REGISTER_POSTEXEC;
+ }
+
+ RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
+
+ memcpy(curr, data, xlen/8);
+ curr += xlen/8;
+ }
+
+ restore_reg(S0, s0);
+ restore_reg(S1, s1);
+
+ resume(current_hart);
+
+}
+
+void dtm_t::write_chunk(uint64_t taddr, size_t len, const void* src)
+{
+ uint32_t prog[ram_words];
+ uint32_t data[data_words];
+
+ const uint8_t * curr = (const uint8_t*) src;
+
+ halt(current_hart);
+
+ uint64_t s0 = save_reg(S0);
+ uint64_t s1 = save_reg(S1);
+
+ prog[0] = STORE(xlen, S1, S0, 0);
+ prog[1] = ADDI(S0, S0, xlen/8);
+ prog[2] = EBREAK;
+
+ data[0] = (uint32_t) taddr;
+ if (xlen > 32) {
+ data[1] = (uint32_t) (taddr >> 32);
+ }
+
+ // Write the program (not used yet).
+ // Write s0 with the address.
+ uint32_t command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S0);
+
+ RUN_AC_OR_DIE(command, prog, 3, data, xlen/(4*8));
+
+ // Use Autoexec for more than one word of transfer.
+ // Write S1 with data, then execution stores S1 to
+ // 0(S0) and increments S0.
+ // Each time we write XLEN bits.
+ memcpy(data, curr, xlen/8);
+ curr += xlen/8;
+
+ command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_POSTEXEC |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S1);
+
+ RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
+
+ uint32_t abstractcs;
+ for (size_t i = 1; i < (len * 8 / xlen); i++){
+ if (i == 1) {
+ write(DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET);
+ }
+ memcpy(data, curr, xlen/8);
+ curr += xlen/8;
+ if (xlen == 64) {
+ write(DMI_DATA0 + 1, data[1]);
+ }
+ write(DMI_DATA0, data[0]); //Triggers a command w/ autoexec.
+
+ do {
+ abstractcs = read(DMI_ABSTRACTCS);
+ } while (abstractcs & DMI_ABSTRACTCS_BUSY);
+ if ( get_field(abstractcs, DMI_ABSTRACTCS_CMDERR)) {
+ die(get_field(abstractcs, DMI_ABSTRACTCS_CMDERR));
+ }
+ }
+ if ((len * 8 / xlen) > 1) {
+ write(DMI_ABSTRACTAUTO, 0);
+ }
+
+ restore_reg(S0, s0);
+ restore_reg(S1, s1);
+ resume(current_hart);
+}
+
+void dtm_t::die(uint32_t cmderr)
+{
+ const char * codes[] = {
+ "OK",
+ "BUSY",
+ "NOT_SUPPORTED",
+ "EXCEPTION",
+ "HALT/RESUME"
+ };
+ const char * msg;
+ if (cmderr < (sizeof(codes) / sizeof(*codes))){
+ msg = codes[cmderr];
+ } else {
+ msg = "OTHER";
+ }
+ //throw std::runtime_error("Debug Abstract Command Error #" + std::to_string(cmderr) + "(" + msg + ")");
+ printf("ERROR: %s:%d, Debug Abstract Command Error #%d (%s)", __FILE__, __LINE__, cmderr, msg);
+ printf("ERROR: %s:%d, Should die, but allowing simulation to continue and fail.", __FILE__, __LINE__);
+ write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
+
+}
+
+void dtm_t::clear_chunk(uint64_t taddr, size_t len)
+{
+ uint32_t prog[ram_words];
+ uint32_t data[data_words];
+
+ halt(current_hart);
+ uint64_t s0 = save_reg(S0);
+ uint64_t s1 = save_reg(S1);
+
+ uint32_t command;
+
+ // S0 = Addr
+ data[0] = (uint32_t) taddr;
+ data[1] = (uint32_t) (taddr >> 32);
+ command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S0);
+ RUN_AC_OR_DIE(command, 0, 0, data, xlen/(4*8));
+
+ // S1 = Addr + len, loop until S0 = S1
+ prog[0] = STORE(xlen, X0, S0, 0);
+ prog[1] = ADDI(S0, S0, xlen/8);
+ prog[2] = BNE(S0, S1, 0*4, 2*4);
+ prog[3] = EBREAK;
+
+ data[0] = (uint32_t) (taddr + len);
+ data[1] = (uint32_t) ((taddr + len) >> 32);
+ command = AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(S1) |
+ AC_ACCESS_REGISTER_POSTEXEC;
+ RUN_AC_OR_DIE(command, prog, 4, data, xlen/(4*8));
+
+ restore_reg(S0, s0);
+ restore_reg(S1, s1);
+
+ resume(current_hart);
+}
+
+uint64_t dtm_t::write_csr(unsigned which, uint64_t data)
+{
+ return modify_csr(which, data, WRITE);
+}
+
+uint64_t dtm_t::set_csr(unsigned which, uint64_t data)
+{
+ return modify_csr(which, data, SET);
+}
+
+uint64_t dtm_t::clear_csr(unsigned which, uint64_t data)
+{
+ return modify_csr(which, data, CLEAR);
+}
+
+uint64_t dtm_t::read_csr(unsigned which)
+{
+ return set_csr(which, 0);
+}
+
+uint64_t dtm_t::modify_csr(unsigned which, uint64_t data, uint32_t type)
+{
+ halt(current_hart);
+
+ // This code just uses DSCRATCH to save S0
+ // and data_base to do the transfer so we don't
+ // need to run more commands to save and restore
+ // S0.
+ uint32_t prog[] = {
+ CSRRx(WRITE, S0, CSR_DSCRATCH, S0),
+ LOAD(xlen, S0, X0, data_base),
+ CSRRx(type, S0, which, S0),
+ STORE(xlen, S0, X0, data_base),
+ CSRRx(WRITE, S0, CSR_DSCRATCH, S0),
+ EBREAK
+ };
+
+ //TODO: Use transfer = 0. For now both HW and OpenOCD
+ // ignore transfer bit, so use "store to X0" NOOP.
+ // We sort of need this anyway because run_abstract_command
+ // needs the DATA to be written so may as well use the WRITE flag.
+
+ uint32_t adata[] = {(uint32_t) data,
+ (uint32_t) (data >> 32)};
+
+ uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
+ AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(X0);
+
+ RUN_AC_OR_DIE(command, prog, sizeof(prog) / sizeof(*prog), adata, xlen/(4*8));
+
+ uint64_t res = read(DMI_DATA0);//adata[0];
+ if (xlen == 64)
+ res |= read(DMI_DATA0 + 1);//((uint64_t) adata[1]) << 32;
+
+ resume(current_hart);
+ return res;
+}
+
+size_t dtm_t::chunk_max_size()
+{
+ // Arbitrary choice. 4k Page size seems reasonable.
+ return 4096;
+}
+
+uint32_t dtm_t::get_xlen()
+{
+ // Attempt to read S0 to find out what size it is.
+ // You could also attempt to run code, but you need to save registers
+ // to do that anyway. If what you really want to do is figure out
+ // the size of S0 so you can save it later, then do that.
+ uint32_t command = AC_ACCESS_REGISTER_TRANSFER | AC_AR_REGNO(S0);
+ uint32_t cmderr;
+
+ const uint32_t prog[] = {};
+ uint32_t data[] = {};
+
+ cmderr = run_abstract_command(command | AC_AR_SIZE(128), prog, 0, data, 0);
+ if (cmderr == 0){
+ throw std::runtime_error("FESVR DTM Does not support 128-bit");
+ abort();
+ return 128;
+ }
+ write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
+
+ cmderr = run_abstract_command(command | AC_AR_SIZE(64), prog, 0, data, 0);
+ if (cmderr == 0){
+ return 64;
+ }
+ write(DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR);
+
+ cmderr = run_abstract_command(command | AC_AR_SIZE(32), prog, 0, data, 0);
+ if (cmderr == 0){
+ return 32;
+ }
+
+ throw std::runtime_error("FESVR DTM can't determine XLEN. Aborting");
+}
+
+void dtm_t::fence_i()
+{
+ halt(current_hart);
+
+ const uint32_t prog[] = {
+ FENCE_I,
+ EBREAK
+ };
+
+ //TODO: Use the transfer = 0.
+ uint32_t command = AC_ACCESS_REGISTER_POSTEXEC |
+ AC_ACCESS_REGISTER_TRANSFER |
+ AC_ACCESS_REGISTER_WRITE |
+ AC_AR_SIZE(xlen) |
+ AC_AR_REGNO(X0);
+
+ RUN_AC_OR_DIE(command, prog, sizeof(prog)/sizeof(*prog), 0, 0);
+
+ resume(current_hart);
+
+}
+
+void host_thread_main(void* arg)
+{
+ ((dtm_t*)arg)->producer_thread();
+}
+
+void dtm_t::reset()
+{
+ for (int hartsel = 0; hartsel < num_harts; hartsel ++ ){
+ select_hart(hartsel);
+ // this command also does a halt and resume
+ fence_i();
+ // after this command, the hart will run from _start.
+ write_csr(0x7b1, get_entry_point());
+ }
+ // In theory any hart can handle the memory accesses,
+ // this will enforce that hart 0 handles them.
+ select_hart(0);
+ read(DMI_DMSTATUS);
+}
+
+void dtm_t::idle()
+{
+ for (int idle_cycles = 0; idle_cycles < max_idle_cycles; idle_cycles++)
+ nop();
+}
+
+void dtm_t::producer_thread()
+{
+ // Learn about the Debug Module and assert things we
+ // depend on in this code.
+
+ // These are checked every time we run an abstract command.
+ uint32_t abstractcs = read(DMI_ABSTRACTCS);
+ ram_words = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE);
+ data_words = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT);
+
+ // These things are only needed for the 'modify_csr' function.
+ // That could be re-written to not use these at some performance
+ // overhead.
+ uint32_t hartinfo = read(DMI_HARTINFO);
+ assert(get_field(hartinfo, DMI_HARTINFO_NSCRATCH) > 0);
+ assert(get_field(hartinfo, DMI_HARTINFO_DATAACCESS));
+
+ data_base = get_field(hartinfo, DMI_HARTINFO_DATAADDR);
+
+ // Enable the debugger.
+ write(DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE);
+
+ num_harts = enumerate_harts();
+ halt(0);
+ // Note: We don't support systems with heterogeneous XLEN.
+ // It's possible to do this at the cost of extra cycles.
+ xlen = get_xlen();
+ resume(0);
+
+ running = true;
+
+ htif_t::run();
+
+ while (true)
+ nop();
+}
+
+void dtm_t::start_host_thread()
+{
+ req_wait = false;
+ resp_wait = false;
+
+ target = context_t::current();
+ host.init(host_thread_main, this);
+ host.switch_to();
+}
+
+dtm_t::dtm_t(int argc, char** argv)
+ : htif_t(argc, argv), running(false)
+{
+ start_host_thread();
+}
+
+dtm_t::~dtm_t()
+{
+}
+
+void dtm_t::tick(
+ bool req_ready,
+ bool resp_valid,
+ resp resp_bits)
+{
+ if (!resp_wait) {
+ if (!req_wait) {
+ req_wait = true;
+ } else if (req_ready) {
+ req_wait = false;
+ resp_wait = true;
+ }
+ }
+
+ if (resp_valid) {
+ assert(resp_wait);
+ resp_wait = false;
+
+ resp_buf = resp_bits;
+ // update the target with the current context
+ target = context_t::current();
+ host.switch_to();
+ }
+}
+
+void dtm_t::return_resp(resp resp_bits){
+ resp_buf = resp_bits;
+ target = context_t::current();
+ host.switch_to();
+}
diff --git a/fesvr/dtm.h b/fesvr/dtm.h
new file mode 100644
index 0000000..fbf161e
--- /dev/null
+++ b/fesvr/dtm.h
@@ -0,0 +1,115 @@
+#ifndef _ROCKET_DTM_H
+#define _ROCKET_DTM_H
+
+#include "htif.h"
+#include "context.h"
+#include <stdint.h>
+#include <queue>
+#include <semaphore.h>
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+// abstract debug transport module
+class dtm_t : public htif_t
+{
+ public:
+ dtm_t(int argc, char**argv);
+ ~dtm_t();
+
+ struct req {
+ uint32_t addr;
+ uint32_t op;
+ uint32_t data;
+ };
+
+ struct resp {
+ uint32_t resp;
+ uint32_t data;
+ };
+
+ void tick(
+ bool req_ready,
+ bool resp_valid,
+ resp resp_bits
+ );
+ // Akin to tick, but the target thread returns a response on every invocation
+ void return_resp(
+ resp resp_bits
+ );
+
+
+ bool req_valid() { return req_wait; }
+ req req_bits() { return req_buf; }
+ bool resp_ready() { return true; }
+
+ uint32_t read(uint32_t addr);
+ uint32_t write(uint32_t addr, uint32_t data);
+ void nop();
+
+ uint64_t read_csr(unsigned which);
+ uint64_t write_csr(unsigned which, uint64_t data);
+ uint64_t clear_csr(unsigned which, uint64_t data);
+ uint64_t set_csr(unsigned which, uint64_t data);
+ void fence_i();
+
+ void producer_thread();
+
+ protected:
+ virtual void read_chunk(addr_t taddr, size_t len, void* dst) override;
+ virtual void write_chunk(addr_t taddr, size_t len, const void* src) override;
+ virtual void clear_chunk(addr_t taddr, size_t len) override;
+ virtual size_t chunk_align() override;
+ virtual size_t chunk_max_size() override;
+ virtual void reset() override;
+ virtual void idle() override;
+
+ private:
+ context_t host;
+ context_t* target;
+ pthread_t producer;
+ sem_t req_produce;
+ sem_t req_consume;
+ sem_t resp_produce;
+ sem_t resp_consume;
+ req req_buf;
+ resp resp_buf;
+ bool running;
+
+ uint32_t run_abstract_command(uint32_t command, const uint32_t program[], size_t program_n,
+ uint32_t data[], size_t data_n);
+
+ void die(uint32_t cmderr);
+ void halt(int);
+ int enumerate_harts();
+ void select_hart(int);
+ void resume(int);
+ uint64_t save_reg(unsigned regno);
+ void restore_reg(unsigned regno, uint64_t val);
+
+ uint64_t modify_csr(unsigned which, uint64_t data, uint32_t type);
+
+ bool req_wait;
+ bool resp_wait;
+ uint32_t data_base;
+
+ uint32_t xlen;
+
+ static const int max_idle_cycles = 10000;
+
+ size_t ram_words;
+ size_t data_words;
+ int num_harts;
+ int current_hart;
+
+ uint32_t get_xlen();
+ uint32_t do_command(dtm_t::req r);
+
+ void parse_args(const std::vector<std::string>& args);
+ void register_devices();
+ void start_host_thread();
+
+ friend class memif_t;
+};
+
+#endif
diff --git a/fesvr/dummy.cc b/fesvr/dummy.cc
new file mode 100644
index 0000000..a155d3e
--- /dev/null
+++ b/fesvr/dummy.cc
@@ -0,0 +1,4 @@
+// See LICENSE for license details.
+
+// help out poor, C-centric autoconf
+extern "C" void libfesvr_is_present() {}
diff --git a/fesvr/elf.h b/fesvr/elf.h
new file mode 100644
index 0000000..b66038d
--- /dev/null
+++ b/fesvr/elf.h
@@ -0,0 +1,121 @@
+// See LICENSE for details.
+
+#ifndef _ELF_H
+#define _ELF_H
+
+#include <stdint.h>
+
+#define IS_ELF(hdr) \
+ ((hdr).e_ident[0] == 0x7f && (hdr).e_ident[1] == 'E' && \
+ (hdr).e_ident[2] == 'L' && (hdr).e_ident[3] == 'F')
+
+#define IS_ELF32(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 1)
+#define IS_ELF64(hdr) (IS_ELF(hdr) && (hdr).e_ident[4] == 2)
+
+#define PT_LOAD 1
+
+#define SHT_NOBITS 8
+
+typedef struct {
+ uint8_t e_ident[16];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint32_t e_entry;
+ uint32_t e_phoff;
+ uint32_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct {
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint32_t sh_flags;
+ uint32_t sh_addr;
+ uint32_t sh_offset;
+ uint32_t sh_size;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ uint32_t sh_addralign;
+ uint32_t sh_entsize;
+} Elf32_Shdr;
+
+typedef struct
+{
+ uint32_t p_type;
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+} Elf32_Phdr;
+
+typedef struct
+{
+ uint32_t st_name;
+ uint32_t st_value;
+ uint32_t st_size;
+ uint8_t st_info;
+ uint8_t st_other;
+ uint16_t st_shndx;
+} Elf32_Sym;
+
+typedef struct {
+ uint8_t e_ident[16];
+ uint16_t e_type;
+ uint16_t e_machine;
+ uint32_t e_version;
+ uint64_t e_entry;
+ uint64_t e_phoff;
+ uint64_t e_shoff;
+ uint32_t e_flags;
+ uint16_t e_ehsize;
+ uint16_t e_phentsize;
+ uint16_t e_phnum;
+ uint16_t e_shentsize;
+ uint16_t e_shnum;
+ uint16_t e_shstrndx;
+} Elf64_Ehdr;
+
+typedef struct {
+ uint32_t sh_name;
+ uint32_t sh_type;
+ uint64_t sh_flags;
+ uint64_t sh_addr;
+ uint64_t sh_offset;
+ uint64_t sh_size;
+ uint32_t sh_link;
+ uint32_t sh_info;
+ uint64_t sh_addralign;
+ uint64_t sh_entsize;
+} Elf64_Shdr;
+
+typedef struct {
+ uint32_t p_type;
+ uint32_t p_flags;
+ uint64_t p_offset;
+ uint64_t p_vaddr;
+ uint64_t p_paddr;
+ uint64_t p_filesz;
+ uint64_t p_memsz;
+ uint64_t p_align;
+} Elf64_Phdr;
+
+typedef struct {
+ uint32_t st_name;
+ uint8_t st_info;
+ uint8_t st_other;
+ uint16_t st_shndx;
+ uint64_t st_value;
+ uint64_t st_size;
+} Elf64_Sym;
+
+#endif
diff --git a/fesvr/elf2hex.cc b/fesvr/elf2hex.cc
new file mode 100644
index 0000000..327cf2d
--- /dev/null
+++ b/fesvr/elf2hex.cc
@@ -0,0 +1,47 @@
+// See LICENSE for license details.
+
+#include <iostream>
+#include "htif_hexwriter.h"
+#include "memif.h"
+#include "elfloader.h"
+
+int main(int argc, char** argv)
+{
+ if(argc < 4 || argc > 5)
+ {
+ std::cerr << "Usage: " << argv[0] << " <width> <depth> <elf_file> [base]" << std::endl;
+ return 1;
+ }
+
+ unsigned width = atoi(argv[1]);
+ if(width == 0 || (width & (width-1)))
+ {
+ std::cerr << "width must be a power of 2" << std::endl;
+ return 1;
+ }
+
+ unsigned long long int base = 0;
+ if(argc==5) {
+ base = atoll(argv[4]);
+ if(base & (width-1))
+ {
+ std::cerr << "base must be divisible by width" << std::endl;
+ return 1;
+ }
+ }
+
+ unsigned depth = atoi(argv[2]);
+ if(depth == 0 || (depth & (depth-1)))
+ {
+ std::cerr << "depth must be a power of 2" << std::endl;
+ return 1;
+ }
+
+ htif_hexwriter_t htif(base, width, depth);
+ memif_t memif(&htif);
+ reg_t entry;
+ load_elf(argv[3], &memif, &entry);
+ std::cout << htif;
+
+ return 0;
+}
diff --git a/fesvr/elfloader.cc b/fesvr/elfloader.cc
new file mode 100644
index 0000000..3042f54
--- /dev/null
+++ b/fesvr/elfloader.cc
@@ -0,0 +1,89 @@
+// See LICENSE for license details.
+
+#include "elf.h"
+#include "memif.h"
+#include <cstring>
+#include <string>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <vector>
+#include <map>
+
+std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry)
+{
+ int fd = open(fn, O_RDONLY);
+ struct stat s;
+ assert(fd != -1);
+ if (fstat(fd, &s) < 0)
+ abort();
+ size_t size = s.st_size;
+
+ char* buf = (char*)mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ assert(buf != MAP_FAILED);
+ close(fd);
+
+ assert(size >= sizeof(Elf64_Ehdr));
+ const Elf64_Ehdr* eh64 = (const Elf64_Ehdr*)buf;
+ assert(IS_ELF32(*eh64) || IS_ELF64(*eh64));
+
+ std::vector<uint8_t> zeros;
+ std::map<std::string, uint64_t> symbols;
+
+ #define LOAD_ELF(ehdr_t, phdr_t, shdr_t, sym_t) do { \
+ ehdr_t* eh = (ehdr_t*)buf; \
+ phdr_t* ph = (phdr_t*)(buf + eh->e_phoff); \
+ *entry = eh->e_entry; \
+ assert(size >= eh->e_phoff + eh->e_phnum*sizeof(*ph)); \
+ for (unsigned i = 0; i < eh->e_phnum; i++) { \
+ if(ph[i].p_type == PT_LOAD && ph[i].p_memsz) { \
+ if (ph[i].p_filesz) { \
+ assert(size >= ph[i].p_offset + ph[i].p_filesz); \
+ memif->write(ph[i].p_paddr, ph[i].p_filesz, (uint8_t*)buf + ph[i].p_offset); \
+ } \
+ zeros.resize(ph[i].p_memsz - ph[i].p_filesz); \
+ memif->write(ph[i].p_paddr + ph[i].p_filesz, ph[i].p_memsz - ph[i].p_filesz, &zeros[0]); \
+ } \
+ } \
+ shdr_t* sh = (shdr_t*)(buf + eh->e_shoff); \
+ assert(size >= eh->e_shoff + eh->e_shnum*sizeof(*sh)); \
+ assert(eh->e_shstrndx < eh->e_shnum); \
+ assert(size >= sh[eh->e_shstrndx].sh_offset + sh[eh->e_shstrndx].sh_size); \
+ char *shstrtab = buf + sh[eh->e_shstrndx].sh_offset; \
+ unsigned strtabidx = 0, symtabidx = 0; \
+ for (unsigned i = 0; i < eh->e_shnum; i++) { \
+ unsigned max_len = sh[eh->e_shstrndx].sh_size - sh[i].sh_name; \
+ assert(sh[i].sh_name < sh[eh->e_shstrndx].sh_size); \
+ assert(strnlen(shstrtab + sh[i].sh_name, max_len) < max_len); \
+ if (sh[i].sh_type & SHT_NOBITS) continue; \
+ assert(size >= sh[i].sh_offset + sh[i].sh_size); \
+ if (strcmp(shstrtab + sh[i].sh_name, ".strtab") == 0) \
+ strtabidx = i; \
+ if (strcmp(shstrtab + sh[i].sh_name, ".symtab") == 0) \
+ symtabidx = i; \
+ } \
+ if (strtabidx && symtabidx) { \
+ char* strtab = buf + sh[strtabidx].sh_offset; \
+ sym_t* sym = (sym_t*)(buf + sh[symtabidx].sh_offset); \
+ for (unsigned i = 0; i < sh[symtabidx].sh_size/sizeof(sym_t); i++) { \
+ unsigned max_len = sh[strtabidx].sh_size - sym[i].st_name; \
+ assert(sym[i].st_name < sh[strtabidx].sh_size); \
+ assert(strnlen(strtab + sym[i].st_name, max_len) < max_len); \
+ symbols[strtab + sym[i].st_name] = sym[i].st_value; \
+ } \
+ } \
+ } while(0)
+
+ if (IS_ELF32(*eh64))
+ LOAD_ELF(Elf32_Ehdr, Elf32_Phdr, Elf32_Shdr, Elf32_Sym);
+ else
+ LOAD_ELF(Elf64_Ehdr, Elf64_Phdr, Elf64_Shdr, Elf64_Sym);
+
+ munmap(buf, size);
+
+ return symbols;
+}
diff --git a/fesvr/elfloader.h b/fesvr/elfloader.h
new file mode 100644
index 0000000..696ef47
--- /dev/null
+++ b/fesvr/elfloader.h
@@ -0,0 +1,13 @@
+// See LICENSE for license details.
+
+#ifndef _ELFLOADER_H
+#define _ELFLOADER_H
+
+#include "elf.h"
+#include <map>
+#include <string>
+
+class memif_t;
+std::map<std::string, uint64_t> load_elf(const char* fn, memif_t* memif, reg_t* entry);
+
+#endif
diff --git a/fesvr/encoding.h b/fesvr/encoding.h
new file mode 100644
index 0000000..c109ce1
--- /dev/null
+++ b/fesvr/encoding.h
@@ -0,0 +1,1471 @@
+// See LICENSE for license details.
+
+#ifndef RISCV_CSR_ENCODING_H
+#define RISCV_CSR_ENCODING_H
+
+#define MSTATUS_UIE 0x00000001
+#define MSTATUS_SIE 0x00000002
+#define MSTATUS_HIE 0x00000004
+#define MSTATUS_MIE 0x00000008
+#define MSTATUS_UPIE 0x00000010
+#define MSTATUS_SPIE 0x00000020
+#define MSTATUS_HPIE 0x00000040
+#define MSTATUS_MPIE 0x00000080
+#define MSTATUS_SPP 0x00000100
+#define MSTATUS_HPP 0x00000600
+#define MSTATUS_MPP 0x00001800
+#define MSTATUS_FS 0x00006000
+#define MSTATUS_XS 0x00018000
+#define MSTATUS_MPRV 0x00020000
+#define MSTATUS_SUM 0x00040000
+#define MSTATUS_MXR 0x00080000
+#define MSTATUS_TVM 0x00100000
+#define MSTATUS_TW 0x00200000
+#define MSTATUS_TSR 0x00400000
+#define MSTATUS32_SD 0x80000000
+#define MSTATUS_UXL 0x0000000300000000
+#define MSTATUS_SXL 0x0000000C00000000
+#define MSTATUS64_SD 0x8000000000000000
+
+#define SSTATUS_UIE 0x00000001
+#define SSTATUS_SIE 0x00000002
+#define SSTATUS_UPIE 0x00000010
+#define SSTATUS_SPIE 0x00000020
+#define SSTATUS_SPP 0x00000100
+#define SSTATUS_FS 0x00006000
+#define SSTATUS_XS 0x00018000
+#define SSTATUS_SUM 0x00040000
+#define SSTATUS_MXR 0x00080000
+#define SSTATUS32_SD 0x80000000
+#define SSTATUS_UXL 0x0000000300000000
+#define SSTATUS64_SD 0x8000000000000000
+
+#define DCSR_XDEBUGVER (3U<<30)
+#define DCSR_NDRESET (1<<29)
+#define DCSR_FULLRESET (1<<28)
+#define DCSR_EBREAKM (1<<15)
+#define DCSR_EBREAKH (1<<14)
+#define DCSR_EBREAKS (1<<13)
+#define DCSR_EBREAKU (1<<12)
+#define DCSR_STOPCYCLE (1<<10)
+#define DCSR_STOPTIME (1<<9)
+#define DCSR_CAUSE (7<<6)
+#define DCSR_DEBUGINT (1<<5)
+#define DCSR_HALT (1<<3)
+#define DCSR_STEP (1<<2)
+#define DCSR_PRV (3<<0)
+
+#define DCSR_CAUSE_NONE 0
+#define DCSR_CAUSE_SWBP 1
+#define DCSR_CAUSE_HWBP 2
+#define DCSR_CAUSE_DEBUGINT 3
+#define DCSR_CAUSE_STEP 4
+#define DCSR_CAUSE_HALT 5
+
+#define MCONTROL_TYPE(xlen) (0xfULL<<((xlen)-4))
+#define MCONTROL_DMODE(xlen) (1ULL<<((xlen)-5))
+#define MCONTROL_MASKMAX(xlen) (0x3fULL<<((xlen)-11))
+
+#define MCONTROL_SELECT (1<<19)
+#define MCONTROL_TIMING (1<<18)
+#define MCONTROL_ACTION (0x3f<<12)
+#define MCONTROL_CHAIN (1<<11)
+#define MCONTROL_MATCH (0xf<<7)
+#define MCONTROL_M (1<<6)
+#define MCONTROL_H (1<<5)
+#define MCONTROL_S (1<<4)
+#define MCONTROL_U (1<<3)
+#define MCONTROL_EXECUTE (1<<2)
+#define MCONTROL_STORE (1<<1)
+#define MCONTROL_LOAD (1<<0)
+
+#define MCONTROL_TYPE_NONE 0
+#define MCONTROL_TYPE_MATCH 2
+
+#define MCONTROL_ACTION_DEBUG_EXCEPTION 0
+#define MCONTROL_ACTION_DEBUG_MODE 1
+#define MCONTROL_ACTION_TRACE_START 2
+#define MCONTROL_ACTION_TRACE_STOP 3
+#define MCONTROL_ACTION_TRACE_EMIT 4
+
+#define MCONTROL_MATCH_EQUAL 0
+#define MCONTROL_MATCH_NAPOT 1
+#define MCONTROL_MATCH_GE 2
+#define MCONTROL_MATCH_LT 3
+#define MCONTROL_MATCH_MASK_LOW 4
+#define MCONTROL_MATCH_MASK_HIGH 5
+
+#define MIP_SSIP (1 << IRQ_S_SOFT)
+#define MIP_HSIP (1 << IRQ_H_SOFT)
+#define MIP_MSIP (1 << IRQ_M_SOFT)
+#define MIP_STIP (1 << IRQ_S_TIMER)
+#define MIP_HTIP (1 << IRQ_H_TIMER)
+#define MIP_MTIP (1 << IRQ_M_TIMER)
+#define MIP_SEIP (1 << IRQ_S_EXT)
+#define MIP_HEIP (1 << IRQ_H_EXT)
+#define MIP_MEIP (1 << IRQ_M_EXT)
+
+#define SIP_SSIP MIP_SSIP
+#define SIP_STIP MIP_STIP
+
+#define PRV_U 0
+#define PRV_S 1
+#define PRV_H 2
+#define PRV_M 3
+
+#define SATP32_MODE 0x80000000
+#define SATP32_ASID 0x7FC00000
+#define SATP32_PPN 0x003FFFFF
+#define SATP64_MODE 0xF000000000000000
+#define SATP64_ASID 0x0FFFF00000000000
+#define SATP64_PPN 0x00000FFFFFFFFFFF
+
+#define SATP_MODE_OFF 0
+#define SATP_MODE_SV32 1
+#define SATP_MODE_SV39 8
+#define SATP_MODE_SV48 9
+#define SATP_MODE_SV57 10
+#define SATP_MODE_SV64 11
+
+#define PMP_R 0x01
+#define PMP_W 0x02
+#define PMP_X 0x04
+#define PMP_A 0x18
+#define PMP_L 0x80
+#define PMP_SHIFT 2
+
+#define PMP_TOR 0x08
+#define PMP_NA4 0x10
+#define PMP_NAPOT 0x18
+
+#define IRQ_S_SOFT 1
+#define IRQ_H_SOFT 2
+#define IRQ_M_SOFT 3
+#define IRQ_S_TIMER 5
+#define IRQ_H_TIMER 6
+#define IRQ_M_TIMER 7
+#define IRQ_S_EXT 9
+#define IRQ_H_EXT 10
+#define IRQ_M_EXT 11
+#define IRQ_COP 12
+#define IRQ_HOST 13
+
+#define DEFAULT_RSTVEC 0x00001000
+#define CLINT_BASE 0x02000000
+#define CLINT_SIZE 0x000c0000
+#define EXT_IO_BASE 0x40000000
+#define DRAM_BASE 0x80000000
+
+// page table entry (PTE) fields
+#define PTE_V 0x001 // Valid
+#define PTE_R 0x002 // Read
+#define PTE_W 0x004 // Write
+#define PTE_X 0x008 // Execute
+#define PTE_U 0x010 // User
+#define PTE_G 0x020 // Global
+#define PTE_A 0x040 // Accessed
+#define PTE_D 0x080 // Dirty
+#define PTE_SOFT 0x300 // Reserved for Software
+
+#define PTE_PPN_SHIFT 10
+
+#define PTE_TABLE(PTE) (((PTE) & (PTE_V | PTE_R | PTE_W | PTE_X)) == PTE_V)
+
+#ifdef __riscv
+
+#if __riscv_xlen == 64
+# define MSTATUS_SD MSTATUS64_SD
+# define SSTATUS_SD SSTATUS64_SD
+# define RISCV_PGLEVEL_BITS 9
+# define SATP_MODE SATP64_MODE
+#else
+# define MSTATUS_SD MSTATUS32_SD
+# define SSTATUS_SD SSTATUS32_SD
+# define RISCV_PGLEVEL_BITS 10
+# define SATP_MODE SATP32_MODE
+#endif
+#define RISCV_PGSHIFT 12
+#define RISCV_PGSIZE (1 << RISCV_PGSHIFT)
+
+#ifndef __ASSEMBLER__
+
+#ifdef __GNUC__
+
+#define read_csr(reg) ({ unsigned long __tmp; \
+ asm volatile ("csrr %0, " #reg : "=r"(__tmp)); \
+ __tmp; })
+
+#define write_csr(reg, val) ({ \
+ asm volatile ("csrw " #reg ", %0" :: "rK"(val)); })
+
+#define swap_csr(reg, val) ({ unsigned long __tmp; \
+ asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \
+ __tmp; })
+
+#define set_csr(reg, bit) ({ unsigned long __tmp; \
+ asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
+ __tmp; })
+
+#define clear_csr(reg, bit) ({ unsigned long __tmp; \
+ asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \
+ __tmp; })
+
+#define rdtime() read_csr(time)
+#define rdcycle() read_csr(cycle)
+#define rdinstret() read_csr(instret)
+
+#endif
+
+#endif
+
+#endif
+
+#endif
+/* Automatically generated by parse-opcodes. */
+#ifndef RISCV_ENCODING_H
+#define RISCV_ENCODING_H
+#define MATCH_BEQ 0x63
+#define MASK_BEQ 0x707f
+#define MATCH_BNE 0x1063
+#define MASK_BNE 0x707f
+#define MATCH_BLT 0x4063
+#define MASK_BLT 0x707f
+#define MATCH_BGE 0x5063
+#define MASK_BGE 0x707f
+#define MATCH_BLTU 0x6063
+#define MASK_BLTU 0x707f
+#define MATCH_BGEU 0x7063
+#define MASK_BGEU 0x707f
+#define MATCH_JALR 0x67
+#define MASK_JALR 0x707f
+#define MATCH_JAL 0x6f
+#define MASK_JAL 0x7f
+#define MATCH_LUI 0x37
+#define MASK_LUI 0x7f
+#define MATCH_AUIPC 0x17
+#define MASK_AUIPC 0x7f
+#define MATCH_ADDI 0x13
+#define MASK_ADDI 0x707f
+#define MATCH_SLLI 0x1013
+#define MASK_SLLI 0xfc00707f
+#define MATCH_SLTI 0x2013
+#define MASK_SLTI 0x707f
+#define MATCH_SLTIU 0x3013
+#define MASK_SLTIU 0x707f
+#define MATCH_XORI 0x4013
+#define MASK_XORI 0x707f
+#define MATCH_SRLI 0x5013
+#define MASK_SRLI 0xfc00707f
+#define MATCH_SRAI 0x40005013
+#define MASK_SRAI 0xfc00707f
+#define MATCH_ORI 0x6013
+#define MASK_ORI 0x707f
+#define MATCH_ANDI 0x7013
+#define MASK_ANDI 0x707f
+#define MATCH_ADD 0x33
+#define MASK_ADD 0xfe00707f
+#define MATCH_SUB 0x40000033
+#define MASK_SUB 0xfe00707f
+#define MATCH_SLL 0x1033
+#define MASK_SLL 0xfe00707f
+#define MATCH_SLT 0x2033
+#define MASK_SLT 0xfe00707f
+#define MATCH_SLTU 0x3033
+#define MASK_SLTU 0xfe00707f
+#define MATCH_XOR 0x4033
+#define MASK_XOR 0xfe00707f
+#define MATCH_SRL 0x5033
+#define MASK_SRL 0xfe00707f
+#define MATCH_SRA 0x40005033
+#define MASK_SRA 0xfe00707f
+#define MATCH_OR 0x6033
+#define MASK_OR 0xfe00707f
+#define MATCH_AND 0x7033
+#define MASK_AND 0xfe00707f
+#define MATCH_ADDIW 0x1b
+#define MASK_ADDIW 0x707f
+#define MATCH_SLLIW 0x101b
+#define MASK_SLLIW 0xfe00707f
+#define MATCH_SRLIW 0x501b
+#define MASK_SRLIW 0xfe00707f
+#define MATCH_SRAIW 0x4000501b
+#define MASK_SRAIW 0xfe00707f
+#define MATCH_ADDW 0x3b
+#define MASK_ADDW 0xfe00707f
+#define MATCH_SUBW 0x4000003b
+#define MASK_SUBW 0xfe00707f
+#define MATCH_SLLW 0x103b
+#define MASK_SLLW 0xfe00707f
+#define MATCH_SRLW 0x503b
+#define MASK_SRLW 0xfe00707f
+#define MATCH_SRAW 0x4000503b
+#define MASK_SRAW 0xfe00707f
+#define MATCH_LB 0x3
+#define MASK_LB 0x707f
+#define MATCH_LH 0x1003
+#define MASK_LH 0x707f
+#define MATCH_LW 0x2003
+#define MASK_LW 0x707f
+#define MATCH_LD 0x3003
+#define MASK_LD 0x707f
+#define MATCH_LBU 0x4003
+#define MASK_LBU 0x707f
+#define MATCH_LHU 0x5003
+#define MASK_LHU 0x707f
+#define MATCH_LWU 0x6003
+#define MASK_LWU 0x707f
+#define MATCH_SB 0x23
+#define MASK_SB 0x707f
+#define MATCH_SH 0x1023
+#define MASK_SH 0x707f
+#define MATCH_SW 0x2023
+#define MASK_SW 0x707f
+#define MATCH_SD 0x3023
+#define MASK_SD 0x707f
+#define MATCH_FENCE 0xf
+#define MASK_FENCE 0x707f
+#define MATCH_FENCE_I 0x100f
+#define MASK_FENCE_I 0x707f
+#define MATCH_MUL 0x2000033
+#define MASK_MUL 0xfe00707f
+#define MATCH_MULH 0x2001033
+#define MASK_MULH 0xfe00707f
+#define MATCH_MULHSU 0x2002033
+#define MASK_MULHSU 0xfe00707f
+#define MATCH_MULHU 0x2003033
+#define MASK_MULHU 0xfe00707f
+#define MATCH_DIV 0x2004033
+#define MASK_DIV 0xfe00707f
+#define MATCH_DIVU 0x2005033
+#define MASK_DIVU 0xfe00707f
+#define MATCH_REM 0x2006033
+#define MASK_REM 0xfe00707f
+#define MATCH_REMU 0x2007033
+#define MASK_REMU 0xfe00707f
+#define MATCH_MULW 0x200003b
+#define MASK_MULW 0xfe00707f
+#define MATCH_DIVW 0x200403b
+#define MASK_DIVW 0xfe00707f
+#define MATCH_DIVUW 0x200503b
+#define MASK_DIVUW 0xfe00707f
+#define MATCH_REMW 0x200603b
+#define MASK_REMW 0xfe00707f
+#define MATCH_REMUW 0x200703b
+#define MASK_REMUW 0xfe00707f
+#define MATCH_AMOADD_W 0x202f
+#define MASK_AMOADD_W 0xf800707f
+#define MATCH_AMOXOR_W 0x2000202f
+#define MASK_AMOXOR_W 0xf800707f
+#define MATCH_AMOOR_W 0x4000202f
+#define MASK_AMOOR_W 0xf800707f
+#define MATCH_AMOAND_W 0x6000202f
+#define MASK_AMOAND_W 0xf800707f
+#define MATCH_AMOMIN_W 0x8000202f
+#define MASK_AMOMIN_W 0xf800707f
+#define MATCH_AMOMAX_W 0xa000202f
+#define MASK_AMOMAX_W 0xf800707f
+#define MATCH_AMOMINU_W 0xc000202f
+#define MASK_AMOMINU_W 0xf800707f
+#define MATCH_AMOMAXU_W 0xe000202f
+#define MASK_AMOMAXU_W 0xf800707f
+#define MATCH_AMOSWAP_W 0x800202f
+#define MASK_AMOSWAP_W 0xf800707f
+#define MATCH_LR_W 0x1000202f
+#define MASK_LR_W 0xf9f0707f
+#define MATCH_SC_W 0x1800202f
+#define MASK_SC_W 0xf800707f
+#define MATCH_AMOADD_D 0x302f
+#define MASK_AMOADD_D 0xf800707f
+#define MATCH_AMOXOR_D 0x2000302f
+#define MASK_AMOXOR_D 0xf800707f
+#define MATCH_AMOOR_D 0x4000302f
+#define MASK_AMOOR_D 0xf800707f
+#define MATCH_AMOAND_D 0x6000302f
+#define MASK_AMOAND_D 0xf800707f
+#define MATCH_AMOMIN_D 0x8000302f
+#define MASK_AMOMIN_D 0xf800707f
+#define MATCH_AMOMAX_D 0xa000302f
+#define MASK_AMOMAX_D 0xf800707f
+#define MATCH_AMOMINU_D 0xc000302f
+#define MASK_AMOMINU_D 0xf800707f
+#define MATCH_AMOMAXU_D 0xe000302f
+#define MASK_AMOMAXU_D 0xf800707f
+#define MATCH_AMOSWAP_D 0x800302f
+#define MASK_AMOSWAP_D 0xf800707f
+#define MATCH_LR_D 0x1000302f
+#define MASK_LR_D 0xf9f0707f
+#define MATCH_SC_D 0x1800302f
+#define MASK_SC_D 0xf800707f
+#define MATCH_ECALL 0x73
+#define MASK_ECALL 0xffffffff
+#define MATCH_EBREAK 0x100073
+#define MASK_EBREAK 0xffffffff
+#define MATCH_URET 0x200073
+#define MASK_URET 0xffffffff
+#define MATCH_SRET 0x10200073
+#define MASK_SRET 0xffffffff
+#define MATCH_MRET 0x30200073
+#define MASK_MRET 0xffffffff
+#define MATCH_DRET 0x7b200073
+#define MASK_DRET 0xffffffff
+#define MATCH_SFENCE_VMA 0x12000073
+#define MASK_SFENCE_VMA 0xfe007fff
+#define MATCH_WFI 0x10500073
+#define MASK_WFI 0xffffffff
+#define MATCH_CSRRW 0x1073
+#define MASK_CSRRW 0x707f
+#define MATCH_CSRRS 0x2073
+#define MASK_CSRRS 0x707f
+#define MATCH_CSRRC 0x3073
+#define MASK_CSRRC 0x707f
+#define MATCH_CSRRWI 0x5073
+#define MASK_CSRRWI 0x707f
+#define MATCH_CSRRSI 0x6073
+#define MASK_CSRRSI 0x707f
+#define MATCH_CSRRCI 0x7073
+#define MASK_CSRRCI 0x707f
+#define MATCH_FADD_S 0x53
+#define MASK_FADD_S 0xfe00007f
+#define MATCH_FSUB_S 0x8000053
+#define MASK_FSUB_S 0xfe00007f
+#define MATCH_FMUL_S 0x10000053
+#define MASK_FMUL_S 0xfe00007f
+#define MATCH_FDIV_S 0x18000053
+#define MASK_FDIV_S 0xfe00007f
+#define MATCH_FSGNJ_S 0x20000053
+#define MASK_FSGNJ_S 0xfe00707f
+#define MATCH_FSGNJN_S 0x20001053
+#define MASK_FSGNJN_S 0xfe00707f
+#define MATCH_FSGNJX_S 0x20002053
+#define MASK_FSGNJX_S 0xfe00707f
+#define MATCH_FMIN_S 0x28000053
+#define MASK_FMIN_S 0xfe00707f
+#define MATCH_FMAX_S 0x28001053
+#define MASK_FMAX_S 0xfe00707f
+#define MATCH_FSQRT_S 0x58000053
+#define MASK_FSQRT_S 0xfff0007f
+#define MATCH_FADD_D 0x2000053
+#define MASK_FADD_D 0xfe00007f
+#define MATCH_FSUB_D 0xa000053
+#define MASK_FSUB_D 0xfe00007f
+#define MATCH_FMUL_D 0x12000053
+#define MASK_FMUL_D 0xfe00007f
+#define MATCH_FDIV_D 0x1a000053
+#define MASK_FDIV_D 0xfe00007f
+#define MATCH_FSGNJ_D 0x22000053
+#define MASK_FSGNJ_D 0xfe00707f
+#define MATCH_FSGNJN_D 0x22001053
+#define MASK_FSGNJN_D 0xfe00707f
+#define MATCH_FSGNJX_D 0x22002053
+#define MASK_FSGNJX_D 0xfe00707f
+#define MATCH_FMIN_D 0x2a000053
+#define MASK_FMIN_D 0xfe00707f
+#define MATCH_FMAX_D 0x2a001053
+#define MASK_FMAX_D 0xfe00707f
+#define MATCH_FCVT_S_D 0x40100053
+#define MASK_FCVT_S_D 0xfff0007f
+#define MATCH_FCVT_D_S 0x42000053
+#define MASK_FCVT_D_S 0xfff0007f
+#define MATCH_FSQRT_D 0x5a000053
+#define MASK_FSQRT_D 0xfff0007f
+#define MATCH_FADD_Q 0x6000053
+#define MASK_FADD_Q 0xfe00007f
+#define MATCH_FSUB_Q 0xe000053
+#define MASK_FSUB_Q 0xfe00007f
+#define MATCH_FMUL_Q 0x16000053
+#define MASK_FMUL_Q 0xfe00007f
+#define MATCH_FDIV_Q 0x1e000053
+#define MASK_FDIV_Q 0xfe00007f
+#define MATCH_FSGNJ_Q 0x26000053
+#define MASK_FSGNJ_Q 0xfe00707f
+#define MATCH_FSGNJN_Q 0x26001053
+#define MASK_FSGNJN_Q 0xfe00707f
+#define MATCH_FSGNJX_Q 0x26002053
+#define MASK_FSGNJX_Q 0xfe00707f
+#define MATCH_FMIN_Q 0x2e000053
+#define MASK_FMIN_Q 0xfe00707f
+#define MATCH_FMAX_Q 0x2e001053
+#define MASK_FMAX_Q 0xfe00707f
+#define MATCH_FCVT_S_Q 0x40300053
+#define MASK_FCVT_S_Q 0xfff0007f
+#define MATCH_FCVT_Q_S 0x46000053
+#define MASK_FCVT_Q_S 0xfff0007f
+#define MATCH_FCVT_D_Q 0x42300053
+#define MASK_FCVT_D_Q 0xfff0007f
+#define MATCH_FCVT_Q_D 0x46100053
+#define MASK_FCVT_Q_D 0xfff0007f
+#define MATCH_FSQRT_Q 0x5e000053
+#define MASK_FSQRT_Q 0xfff0007f
+#define MATCH_FLE_S 0xa0000053
+#define MASK_FLE_S 0xfe00707f
+#define MATCH_FLT_S 0xa0001053
+#define MASK_FLT_S 0xfe00707f
+#define MATCH_FEQ_S 0xa0002053
+#define MASK_FEQ_S 0xfe00707f
+#define MATCH_FLE_D 0xa2000053
+#define MASK_FLE_D 0xfe00707f
+#define MATCH_FLT_D 0xa2001053
+#define MASK_FLT_D 0xfe00707f
+#define MATCH_FEQ_D 0xa2002053
+#define MASK_FEQ_D 0xfe00707f
+#define MATCH_FLE_Q 0xa6000053
+#define MASK_FLE_Q 0xfe00707f
+#define MATCH_FLT_Q 0xa6001053
+#define MASK_FLT_Q 0xfe00707f
+#define MATCH_FEQ_Q 0xa6002053
+#define MASK_FEQ_Q 0xfe00707f
+#define MATCH_FCVT_W_S 0xc0000053
+#define MASK_FCVT_W_S 0xfff0007f
+#define MATCH_FCVT_WU_S 0xc0100053
+#define MASK_FCVT_WU_S 0xfff0007f
+#define MATCH_FCVT_L_S 0xc0200053
+#define MASK_FCVT_L_S 0xfff0007f
+#define MATCH_FCVT_LU_S 0xc0300053
+#define MASK_FCVT_LU_S 0xfff0007f
+#define MATCH_FMV_X_W 0xe0000053
+#define MASK_FMV_X_W 0xfff0707f
+#define MATCH_FCLASS_S 0xe0001053
+#define MASK_FCLASS_S 0xfff0707f
+#define MATCH_FCVT_W_D 0xc2000053
+#define MASK_FCVT_W_D 0xfff0007f
+#define MATCH_FCVT_WU_D 0xc2100053
+#define MASK_FCVT_WU_D 0xfff0007f
+#define MATCH_FCVT_L_D 0xc2200053
+#define MASK_FCVT_L_D 0xfff0007f
+#define MATCH_FCVT_LU_D 0xc2300053
+#define MASK_FCVT_LU_D 0xfff0007f
+#define MATCH_FMV_X_D 0xe2000053
+#define MASK_FMV_X_D 0xfff0707f
+#define MATCH_FCLASS_D 0xe2001053
+#define MASK_FCLASS_D 0xfff0707f
+#define MATCH_FCVT_W_Q 0xc6000053
+#define MASK_FCVT_W_Q 0xfff0007f
+#define MATCH_FCVT_WU_Q 0xc6100053
+#define MASK_FCVT_WU_Q 0xfff0007f
+#define MATCH_FCVT_L_Q 0xc6200053
+#define MASK_FCVT_L_Q 0xfff0007f
+#define MATCH_FCVT_LU_Q 0xc6300053
+#define MASK_FCVT_LU_Q 0xfff0007f
+#define MATCH_FMV_X_Q 0xe6000053
+#define MASK_FMV_X_Q 0xfff0707f
+#define MATCH_FCLASS_Q 0xe6001053
+#define MASK_FCLASS_Q 0xfff0707f
+#define MATCH_FCVT_S_W 0xd0000053
+#define MASK_FCVT_S_W 0xfff0007f
+#define MATCH_FCVT_S_WU 0xd0100053
+#define MASK_FCVT_S_WU 0xfff0007f
+#define MATCH_FCVT_S_L 0xd0200053
+#define MASK_FCVT_S_L 0xfff0007f
+#define MATCH_FCVT_S_LU 0xd0300053
+#define MASK_FCVT_S_LU 0xfff0007f
+#define MATCH_FMV_W_X 0xf0000053
+#define MASK_FMV_W_X 0xfff0707f
+#define MATCH_FCVT_D_W 0xd2000053
+#define MASK_FCVT_D_W 0xfff0007f
+#define MATCH_FCVT_D_WU 0xd2100053
+#define MASK_FCVT_D_WU 0xfff0007f
+#define MATCH_FCVT_D_L 0xd2200053
+#define MASK_FCVT_D_L 0xfff0007f
+#define MATCH_FCVT_D_LU 0xd2300053
+#define MASK_FCVT_D_LU 0xfff0007f
+#define MATCH_FMV_D_X 0xf2000053
+#define MASK_FMV_D_X 0xfff0707f
+#define MATCH_FCVT_Q_W 0xd6000053
+#define MASK_FCVT_Q_W 0xfff0007f
+#define MATCH_FCVT_Q_WU 0xd6100053
+#define MASK_FCVT_Q_WU 0xfff0007f
+#define MATCH_FCVT_Q_L 0xd6200053
+#define MASK_FCVT_Q_L 0xfff0007f
+#define MATCH_FCVT_Q_LU 0xd6300053
+#define MASK_FCVT_Q_LU 0xfff0007f
+#define MATCH_FMV_Q_X 0xf6000053
+#define MASK_FMV_Q_X 0xfff0707f
+#define MATCH_FLW 0x2007
+#define MASK_FLW 0x707f
+#define MATCH_FLD 0x3007
+#define MASK_FLD 0x707f
+#define MATCH_FLQ 0x4007
+#define MASK_FLQ 0x707f
+#define MATCH_FSW 0x2027
+#define MASK_FSW 0x707f
+#define MATCH_FSD 0x3027
+#define MASK_FSD 0x707f
+#define MATCH_FSQ 0x4027
+#define MASK_FSQ 0x707f
+#define MATCH_FMADD_S 0x43
+#define MASK_FMADD_S 0x600007f
+#define MATCH_FMSUB_S 0x47
+#define MASK_FMSUB_S 0x600007f
+#define MATCH_FNMSUB_S 0x4b
+#define MASK_FNMSUB_S 0x600007f
+#define MATCH_FNMADD_S 0x4f
+#define MASK_FNMADD_S 0x600007f
+#define MATCH_FMADD_D 0x2000043
+#define MASK_FMADD_D 0x600007f
+#define MATCH_FMSUB_D 0x2000047
+#define MASK_FMSUB_D 0x600007f
+#define MATCH_FNMSUB_D 0x200004b
+#define MASK_FNMSUB_D 0x600007f
+#define MATCH_FNMADD_D 0x200004f
+#define MASK_FNMADD_D 0x600007f
+#define MATCH_FMADD_Q 0x6000043
+#define MASK_FMADD_Q 0x600007f
+#define MATCH_FMSUB_Q 0x6000047
+#define MASK_FMSUB_Q 0x600007f
+#define MATCH_FNMSUB_Q 0x600004b
+#define MASK_FNMSUB_Q 0x600007f
+#define MATCH_FNMADD_Q 0x600004f
+#define MASK_FNMADD_Q 0x600007f
+#define MATCH_C_NOP 0x1
+#define MASK_C_NOP 0xffff
+#define MATCH_C_ADDI16SP 0x6101
+#define MASK_C_ADDI16SP 0xef83
+#define MATCH_C_JR 0x8002
+#define MASK_C_JR 0xf07f
+#define MATCH_C_JALR 0x9002
+#define MASK_C_JALR 0xf07f
+#define MATCH_C_EBREAK 0x9002
+#define MASK_C_EBREAK 0xffff
+#define MATCH_C_LD 0x6000
+#define MASK_C_LD 0xe003
+#define MATCH_C_SD 0xe000
+#define MASK_C_SD 0xe003
+#define MATCH_C_ADDIW 0x2001
+#define MASK_C_ADDIW 0xe003
+#define MATCH_C_LDSP 0x6002
+#define MASK_C_LDSP 0xe003
+#define MATCH_C_SDSP 0xe002
+#define MASK_C_SDSP 0xe003
+#define MATCH_C_ADDI4SPN 0x0
+#define MASK_C_ADDI4SPN 0xe003
+#define MATCH_C_FLD 0x2000
+#define MASK_C_FLD 0xe003
+#define MATCH_C_LW 0x4000
+#define MASK_C_LW 0xe003
+#define MATCH_C_FLW 0x6000
+#define MASK_C_FLW 0xe003
+#define MATCH_C_FSD 0xa000
+#define MASK_C_FSD 0xe003
+#define MATCH_C_SW 0xc000
+#define MASK_C_SW 0xe003
+#define MATCH_C_FSW 0xe000
+#define MASK_C_FSW 0xe003
+#define MATCH_C_ADDI 0x1
+#define MASK_C_ADDI 0xe003
+#define MATCH_C_JAL 0x2001
+#define MASK_C_JAL 0xe003
+#define MATCH_C_LI 0x4001
+#define MASK_C_LI 0xe003
+#define MATCH_C_LUI 0x6001
+#define MASK_C_LUI 0xe003
+#define MATCH_C_SRLI 0x8001
+#define MASK_C_SRLI 0xec03
+#define MATCH_C_SRAI 0x8401
+#define MASK_C_SRAI 0xec03
+#define MATCH_C_ANDI 0x8801
+#define MASK_C_ANDI 0xec03
+#define MATCH_C_SUB 0x8c01
+#define MASK_C_SUB 0xfc63
+#define MATCH_C_XOR 0x8c21
+#define MASK_C_XOR 0xfc63
+#define MATCH_C_OR 0x8c41
+#define MASK_C_OR 0xfc63
+#define MATCH_C_AND 0x8c61
+#define MASK_C_AND 0xfc63
+#define MATCH_C_SUBW 0x9c01
+#define MASK_C_SUBW 0xfc63
+#define MATCH_C_ADDW 0x9c21
+#define MASK_C_ADDW 0xfc63
+#define MATCH_C_J 0xa001
+#define MASK_C_J 0xe003
+#define MATCH_C_BEQZ 0xc001
+#define MASK_C_BEQZ 0xe003
+#define MATCH_C_BNEZ 0xe001
+#define MASK_C_BNEZ 0xe003
+#define MATCH_C_SLLI 0x2
+#define MASK_C_SLLI 0xe003
+#define MATCH_C_FLDSP 0x2002
+#define MASK_C_FLDSP 0xe003
+#define MATCH_C_LWSP 0x4002
+#define MASK_C_LWSP 0xe003
+#define MATCH_C_FLWSP 0x6002
+#define MASK_C_FLWSP 0xe003
+#define MATCH_C_MV 0x8002
+#define MASK_C_MV 0xf003
+#define MATCH_C_ADD 0x9002
+#define MASK_C_ADD 0xf003
+#define MATCH_C_FSDSP 0xa002
+#define MASK_C_FSDSP 0xe003
+#define MATCH_C_SWSP 0xc002
+#define MASK_C_SWSP 0xe003
+#define MATCH_C_FSWSP 0xe002
+#define MASK_C_FSWSP 0xe003
+#define MATCH_CUSTOM0 0xb
+#define MASK_CUSTOM0 0x707f
+#define MATCH_CUSTOM0_RS1 0x200b
+#define MASK_CUSTOM0_RS1 0x707f
+#define MATCH_CUSTOM0_RS1_RS2 0x300b
+#define MASK_CUSTOM0_RS1_RS2 0x707f
+#define MATCH_CUSTOM0_RD 0x400b
+#define MASK_CUSTOM0_RD 0x707f
+#define MATCH_CUSTOM0_RD_RS1 0x600b
+#define MASK_CUSTOM0_RD_RS1 0x707f
+#define MATCH_CUSTOM0_RD_RS1_RS2 0x700b
+#define MASK_CUSTOM0_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM1 0x2b
+#define MASK_CUSTOM1 0x707f
+#define MATCH_CUSTOM1_RS1 0x202b
+#define MASK_CUSTOM1_RS1 0x707f
+#define MATCH_CUSTOM1_RS1_RS2 0x302b
+#define MASK_CUSTOM1_RS1_RS2 0x707f
+#define MATCH_CUSTOM1_RD 0x402b
+#define MASK_CUSTOM1_RD 0x707f
+#define MATCH_CUSTOM1_RD_RS1 0x602b
+#define MASK_CUSTOM1_RD_RS1 0x707f
+#define MATCH_CUSTOM1_RD_RS1_RS2 0x702b
+#define MASK_CUSTOM1_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM2 0x5b
+#define MASK_CUSTOM2 0x707f
+#define MATCH_CUSTOM2_RS1 0x205b
+#define MASK_CUSTOM2_RS1 0x707f
+#define MATCH_CUSTOM2_RS1_RS2 0x305b
+#define MASK_CUSTOM2_RS1_RS2 0x707f
+#define MATCH_CUSTOM2_RD 0x405b
+#define MASK_CUSTOM2_RD 0x707f
+#define MATCH_CUSTOM2_RD_RS1 0x605b
+#define MASK_CUSTOM2_RD_RS1 0x707f
+#define MATCH_CUSTOM2_RD_RS1_RS2 0x705b
+#define MASK_CUSTOM2_RD_RS1_RS2 0x707f
+#define MATCH_CUSTOM3 0x7b
+#define MASK_CUSTOM3 0x707f
+#define MATCH_CUSTOM3_RS1 0x207b
+#define MASK_CUSTOM3_RS1 0x707f
+#define MATCH_CUSTOM3_RS1_RS2 0x307b
+#define MASK_CUSTOM3_RS1_RS2 0x707f
+#define MATCH_CUSTOM3_RD 0x407b
+#define MASK_CUSTOM3_RD 0x707f
+#define MATCH_CUSTOM3_RD_RS1 0x607b
+#define MASK_CUSTOM3_RD_RS1 0x707f
+#define MATCH_CUSTOM3_RD_RS1_RS2 0x707b
+#define MASK_CUSTOM3_RD_RS1_RS2 0x707f
+#define CSR_FFLAGS 0x1
+#define CSR_FRM 0x2
+#define CSR_FCSR 0x3
+#define CSR_CYCLE 0xc00
+#define CSR_TIME 0xc01
+#define CSR_INSTRET 0xc02
+#define CSR_HPMCOUNTER3 0xc03
+#define CSR_HPMCOUNTER4 0xc04
+#define CSR_HPMCOUNTER5 0xc05
+#define CSR_HPMCOUNTER6 0xc06
+#define CSR_HPMCOUNTER7 0xc07
+#define CSR_HPMCOUNTER8 0xc08
+#define CSR_HPMCOUNTER9 0xc09
+#define CSR_HPMCOUNTER10 0xc0a
+#define CSR_HPMCOUNTER11 0xc0b
+#define CSR_HPMCOUNTER12 0xc0c
+#define CSR_HPMCOUNTER13 0xc0d
+#define CSR_HPMCOUNTER14 0xc0e
+#define CSR_HPMCOUNTER15 0xc0f
+#define CSR_HPMCOUNTER16 0xc10
+#define CSR_HPMCOUNTER17 0xc11
+#define CSR_HPMCOUNTER18 0xc12
+#define CSR_HPMCOUNTER19 0xc13
+#define CSR_HPMCOUNTER20 0xc14
+#define CSR_HPMCOUNTER21 0xc15
+#define CSR_HPMCOUNTER22 0xc16
+#define CSR_HPMCOUNTER23 0xc17
+#define CSR_HPMCOUNTER24 0xc18
+#define CSR_HPMCOUNTER25 0xc19
+#define CSR_HPMCOUNTER26 0xc1a
+#define CSR_HPMCOUNTER27 0xc1b
+#define CSR_HPMCOUNTER28 0xc1c
+#define CSR_HPMCOUNTER29 0xc1d
+#define CSR_HPMCOUNTER30 0xc1e
+#define CSR_HPMCOUNTER31 0xc1f
+#define CSR_SSTATUS 0x100
+#define CSR_SIE 0x104
+#define CSR_STVEC 0x105
+#define CSR_SCOUNTEREN 0x106
+#define CSR_SSCRATCH 0x140
+#define CSR_SEPC 0x141
+#define CSR_SCAUSE 0x142
+#define CSR_STVAL 0x143
+#define CSR_SIP 0x144
+#define CSR_SATP 0x180
+#define CSR_MSTATUS 0x300
+#define CSR_MISA 0x301
+#define CSR_MEDELEG 0x302
+#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_MTVAL 0x343
+#define CSR_MIP 0x344
+#define CSR_PMPCFG0 0x3a0
+#define CSR_PMPCFG1 0x3a1
+#define CSR_PMPCFG2 0x3a2
+#define CSR_PMPCFG3 0x3a3
+#define CSR_PMPADDR0 0x3b0
+#define CSR_PMPADDR1 0x3b1
+#define CSR_PMPADDR2 0x3b2
+#define CSR_PMPADDR3 0x3b3
+#define CSR_PMPADDR4 0x3b4
+#define CSR_PMPADDR5 0x3b5
+#define CSR_PMPADDR6 0x3b6
+#define CSR_PMPADDR7 0x3b7
+#define CSR_PMPADDR8 0x3b8
+#define CSR_PMPADDR9 0x3b9
+#define CSR_PMPADDR10 0x3ba
+#define CSR_PMPADDR11 0x3bb
+#define CSR_PMPADDR12 0x3bc
+#define CSR_PMPADDR13 0x3bd
+#define CSR_PMPADDR14 0x3be
+#define CSR_PMPADDR15 0x3bf
+#define CSR_TSELECT 0x7a0
+#define CSR_TDATA1 0x7a1
+#define CSR_TDATA2 0x7a2
+#define CSR_TDATA3 0x7a3
+#define CSR_DCSR 0x7b0
+#define CSR_DPC 0x7b1
+#define CSR_DSCRATCH 0x7b2
+#define CSR_MCYCLE 0xb00
+#define CSR_MINSTRET 0xb02
+#define CSR_MHPMCOUNTER3 0xb03
+#define CSR_MHPMCOUNTER4 0xb04
+#define CSR_MHPMCOUNTER5 0xb05
+#define CSR_MHPMCOUNTER6 0xb06
+#define CSR_MHPMCOUNTER7 0xb07
+#define CSR_MHPMCOUNTER8 0xb08
+#define CSR_MHPMCOUNTER9 0xb09
+#define CSR_MHPMCOUNTER10 0xb0a
+#define CSR_MHPMCOUNTER11 0xb0b
+#define CSR_MHPMCOUNTER12 0xb0c
+#define CSR_MHPMCOUNTER13 0xb0d
+#define CSR_MHPMCOUNTER14 0xb0e
+#define CSR_MHPMCOUNTER15 0xb0f
+#define CSR_MHPMCOUNTER16 0xb10
+#define CSR_MHPMCOUNTER17 0xb11
+#define CSR_MHPMCOUNTER18 0xb12
+#define CSR_MHPMCOUNTER19 0xb13
+#define CSR_MHPMCOUNTER20 0xb14
+#define CSR_MHPMCOUNTER21 0xb15
+#define CSR_MHPMCOUNTER22 0xb16
+#define CSR_MHPMCOUNTER23 0xb17
+#define CSR_MHPMCOUNTER24 0xb18
+#define CSR_MHPMCOUNTER25 0xb19
+#define CSR_MHPMCOUNTER26 0xb1a
+#define CSR_MHPMCOUNTER27 0xb1b
+#define CSR_MHPMCOUNTER28 0xb1c
+#define CSR_MHPMCOUNTER29 0xb1d
+#define CSR_MHPMCOUNTER30 0xb1e
+#define CSR_MHPMCOUNTER31 0xb1f
+#define CSR_MHPMEVENT3 0x323
+#define CSR_MHPMEVENT4 0x324
+#define CSR_MHPMEVENT5 0x325
+#define CSR_MHPMEVENT6 0x326
+#define CSR_MHPMEVENT7 0x327
+#define CSR_MHPMEVENT8 0x328
+#define CSR_MHPMEVENT9 0x329
+#define CSR_MHPMEVENT10 0x32a
+#define CSR_MHPMEVENT11 0x32b
+#define CSR_MHPMEVENT12 0x32c
+#define CSR_MHPMEVENT13 0x32d
+#define CSR_MHPMEVENT14 0x32e
+#define CSR_MHPMEVENT15 0x32f
+#define CSR_MHPMEVENT16 0x330
+#define CSR_MHPMEVENT17 0x331
+#define CSR_MHPMEVENT18 0x332
+#define CSR_MHPMEVENT19 0x333
+#define CSR_MHPMEVENT20 0x334
+#define CSR_MHPMEVENT21 0x335
+#define CSR_MHPMEVENT22 0x336
+#define CSR_MHPMEVENT23 0x337
+#define CSR_MHPMEVENT24 0x338
+#define CSR_MHPMEVENT25 0x339
+#define CSR_MHPMEVENT26 0x33a
+#define CSR_MHPMEVENT27 0x33b
+#define CSR_MHPMEVENT28 0x33c
+#define CSR_MHPMEVENT29 0x33d
+#define CSR_MHPMEVENT30 0x33e
+#define CSR_MHPMEVENT31 0x33f
+#define CSR_MVENDORID 0xf11
+#define CSR_MARCHID 0xf12
+#define CSR_MIMPID 0xf13
+#define CSR_MHARTID 0xf14
+#define CSR_CYCLEH 0xc80
+#define CSR_TIMEH 0xc81
+#define CSR_INSTRETH 0xc82
+#define CSR_HPMCOUNTER3H 0xc83
+#define CSR_HPMCOUNTER4H 0xc84
+#define CSR_HPMCOUNTER5H 0xc85
+#define CSR_HPMCOUNTER6H 0xc86
+#define CSR_HPMCOUNTER7H 0xc87
+#define CSR_HPMCOUNTER8H 0xc88
+#define CSR_HPMCOUNTER9H 0xc89
+#define CSR_HPMCOUNTER10H 0xc8a
+#define CSR_HPMCOUNTER11H 0xc8b
+#define CSR_HPMCOUNTER12H 0xc8c
+#define CSR_HPMCOUNTER13H 0xc8d
+#define CSR_HPMCOUNTER14H 0xc8e
+#define CSR_HPMCOUNTER15H 0xc8f
+#define CSR_HPMCOUNTER16H 0xc90
+#define CSR_HPMCOUNTER17H 0xc91
+#define CSR_HPMCOUNTER18H 0xc92
+#define CSR_HPMCOUNTER19H 0xc93
+#define CSR_HPMCOUNTER20H 0xc94
+#define CSR_HPMCOUNTER21H 0xc95
+#define CSR_HPMCOUNTER22H 0xc96
+#define CSR_HPMCOUNTER23H 0xc97
+#define CSR_HPMCOUNTER24H 0xc98
+#define CSR_HPMCOUNTER25H 0xc99
+#define CSR_HPMCOUNTER26H 0xc9a
+#define CSR_HPMCOUNTER27H 0xc9b
+#define CSR_HPMCOUNTER28H 0xc9c
+#define CSR_HPMCOUNTER29H 0xc9d
+#define CSR_HPMCOUNTER30H 0xc9e
+#define CSR_HPMCOUNTER31H 0xc9f
+#define CSR_MCYCLEH 0xb80
+#define CSR_MINSTRETH 0xb82
+#define CSR_MHPMCOUNTER3H 0xb83
+#define CSR_MHPMCOUNTER4H 0xb84
+#define CSR_MHPMCOUNTER5H 0xb85
+#define CSR_MHPMCOUNTER6H 0xb86
+#define CSR_MHPMCOUNTER7H 0xb87
+#define CSR_MHPMCOUNTER8H 0xb88
+#define CSR_MHPMCOUNTER9H 0xb89
+#define CSR_MHPMCOUNTER10H 0xb8a
+#define CSR_MHPMCOUNTER11H 0xb8b
+#define CSR_MHPMCOUNTER12H 0xb8c
+#define CSR_MHPMCOUNTER13H 0xb8d
+#define CSR_MHPMCOUNTER14H 0xb8e
+#define CSR_MHPMCOUNTER15H 0xb8f
+#define CSR_MHPMCOUNTER16H 0xb90
+#define CSR_MHPMCOUNTER17H 0xb91
+#define CSR_MHPMCOUNTER18H 0xb92
+#define CSR_MHPMCOUNTER19H 0xb93
+#define CSR_MHPMCOUNTER20H 0xb94
+#define CSR_MHPMCOUNTER21H 0xb95
+#define CSR_MHPMCOUNTER22H 0xb96
+#define CSR_MHPMCOUNTER23H 0xb97
+#define CSR_MHPMCOUNTER24H 0xb98
+#define CSR_MHPMCOUNTER25H 0xb99
+#define CSR_MHPMCOUNTER26H 0xb9a
+#define CSR_MHPMCOUNTER27H 0xb9b
+#define CSR_MHPMCOUNTER28H 0xb9c
+#define CSR_MHPMCOUNTER29H 0xb9d
+#define CSR_MHPMCOUNTER30H 0xb9e
+#define CSR_MHPMCOUNTER31H 0xb9f
+#define CAUSE_MISALIGNED_FETCH 0x0
+#define CAUSE_FETCH_ACCESS 0x1
+#define CAUSE_ILLEGAL_INSTRUCTION 0x2
+#define CAUSE_BREAKPOINT 0x3
+#define CAUSE_MISALIGNED_LOAD 0x4
+#define CAUSE_LOAD_ACCESS 0x5
+#define CAUSE_MISALIGNED_STORE 0x6
+#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)
+DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
+DECLARE_INSN(blt, MATCH_BLT, MASK_BLT)
+DECLARE_INSN(bge, MATCH_BGE, MASK_BGE)
+DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
+DECLARE_INSN(bgeu, MATCH_BGEU, MASK_BGEU)
+DECLARE_INSN(jalr, MATCH_JALR, MASK_JALR)
+DECLARE_INSN(jal, MATCH_JAL, MASK_JAL)
+DECLARE_INSN(lui, MATCH_LUI, MASK_LUI)
+DECLARE_INSN(auipc, MATCH_AUIPC, MASK_AUIPC)
+DECLARE_INSN(addi, MATCH_ADDI, MASK_ADDI)
+DECLARE_INSN(slli, MATCH_SLLI, MASK_SLLI)
+DECLARE_INSN(slti, MATCH_SLTI, MASK_SLTI)
+DECLARE_INSN(sltiu, MATCH_SLTIU, MASK_SLTIU)
+DECLARE_INSN(xori, MATCH_XORI, MASK_XORI)
+DECLARE_INSN(srli, MATCH_SRLI, MASK_SRLI)
+DECLARE_INSN(srai, MATCH_SRAI, MASK_SRAI)
+DECLARE_INSN(ori, MATCH_ORI, MASK_ORI)
+DECLARE_INSN(andi, MATCH_ANDI, MASK_ANDI)
+DECLARE_INSN(add, MATCH_ADD, MASK_ADD)
+DECLARE_INSN(sub, MATCH_SUB, MASK_SUB)
+DECLARE_INSN(sll, MATCH_SLL, MASK_SLL)
+DECLARE_INSN(slt, MATCH_SLT, MASK_SLT)
+DECLARE_INSN(sltu, MATCH_SLTU, MASK_SLTU)
+DECLARE_INSN(xor, MATCH_XOR, MASK_XOR)
+DECLARE_INSN(srl, MATCH_SRL, MASK_SRL)
+DECLARE_INSN(sra, MATCH_SRA, MASK_SRA)
+DECLARE_INSN(or, MATCH_OR, MASK_OR)
+DECLARE_INSN(and, MATCH_AND, MASK_AND)
+DECLARE_INSN(addiw, MATCH_ADDIW, MASK_ADDIW)
+DECLARE_INSN(slliw, MATCH_SLLIW, MASK_SLLIW)
+DECLARE_INSN(srliw, MATCH_SRLIW, MASK_SRLIW)
+DECLARE_INSN(sraiw, MATCH_SRAIW, MASK_SRAIW)
+DECLARE_INSN(addw, MATCH_ADDW, MASK_ADDW)
+DECLARE_INSN(subw, MATCH_SUBW, MASK_SUBW)
+DECLARE_INSN(sllw, MATCH_SLLW, MASK_SLLW)
+DECLARE_INSN(srlw, MATCH_SRLW, MASK_SRLW)
+DECLARE_INSN(sraw, MATCH_SRAW, MASK_SRAW)
+DECLARE_INSN(lb, MATCH_LB, MASK_LB)
+DECLARE_INSN(lh, MATCH_LH, MASK_LH)
+DECLARE_INSN(lw, MATCH_LW, MASK_LW)
+DECLARE_INSN(ld, MATCH_LD, MASK_LD)
+DECLARE_INSN(lbu, MATCH_LBU, MASK_LBU)
+DECLARE_INSN(lhu, MATCH_LHU, MASK_LHU)
+DECLARE_INSN(lwu, MATCH_LWU, MASK_LWU)
+DECLARE_INSN(sb, MATCH_SB, MASK_SB)
+DECLARE_INSN(sh, MATCH_SH, MASK_SH)
+DECLARE_INSN(sw, MATCH_SW, MASK_SW)
+DECLARE_INSN(sd, MATCH_SD, MASK_SD)
+DECLARE_INSN(fence, MATCH_FENCE, MASK_FENCE)
+DECLARE_INSN(fence_i, MATCH_FENCE_I, MASK_FENCE_I)
+DECLARE_INSN(mul, MATCH_MUL, MASK_MUL)
+DECLARE_INSN(mulh, MATCH_MULH, MASK_MULH)
+DECLARE_INSN(mulhsu, MATCH_MULHSU, MASK_MULHSU)
+DECLARE_INSN(mulhu, MATCH_MULHU, MASK_MULHU)
+DECLARE_INSN(div, MATCH_DIV, MASK_DIV)
+DECLARE_INSN(divu, MATCH_DIVU, MASK_DIVU)
+DECLARE_INSN(rem, MATCH_REM, MASK_REM)
+DECLARE_INSN(remu, MATCH_REMU, MASK_REMU)
+DECLARE_INSN(mulw, MATCH_MULW, MASK_MULW)
+DECLARE_INSN(divw, MATCH_DIVW, MASK_DIVW)
+DECLARE_INSN(divuw, MATCH_DIVUW, MASK_DIVUW)
+DECLARE_INSN(remw, MATCH_REMW, MASK_REMW)
+DECLARE_INSN(remuw, MATCH_REMUW, MASK_REMUW)
+DECLARE_INSN(amoadd_w, MATCH_AMOADD_W, MASK_AMOADD_W)
+DECLARE_INSN(amoxor_w, MATCH_AMOXOR_W, MASK_AMOXOR_W)
+DECLARE_INSN(amoor_w, MATCH_AMOOR_W, MASK_AMOOR_W)
+DECLARE_INSN(amoand_w, MATCH_AMOAND_W, MASK_AMOAND_W)
+DECLARE_INSN(amomin_w, MATCH_AMOMIN_W, MASK_AMOMIN_W)
+DECLARE_INSN(amomax_w, MATCH_AMOMAX_W, MASK_AMOMAX_W)
+DECLARE_INSN(amominu_w, MATCH_AMOMINU_W, MASK_AMOMINU_W)
+DECLARE_INSN(amomaxu_w, MATCH_AMOMAXU_W, MASK_AMOMAXU_W)
+DECLARE_INSN(amoswap_w, MATCH_AMOSWAP_W, MASK_AMOSWAP_W)
+DECLARE_INSN(lr_w, MATCH_LR_W, MASK_LR_W)
+DECLARE_INSN(sc_w, MATCH_SC_W, MASK_SC_W)
+DECLARE_INSN(amoadd_d, MATCH_AMOADD_D, MASK_AMOADD_D)
+DECLARE_INSN(amoxor_d, MATCH_AMOXOR_D, MASK_AMOXOR_D)
+DECLARE_INSN(amoor_d, MATCH_AMOOR_D, MASK_AMOOR_D)
+DECLARE_INSN(amoand_d, MATCH_AMOAND_D, MASK_AMOAND_D)
+DECLARE_INSN(amomin_d, MATCH_AMOMIN_D, MASK_AMOMIN_D)
+DECLARE_INSN(amomax_d, MATCH_AMOMAX_D, MASK_AMOMAX_D)
+DECLARE_INSN(amominu_d, MATCH_AMOMINU_D, MASK_AMOMINU_D)
+DECLARE_INSN(amomaxu_d, MATCH_AMOMAXU_D, MASK_AMOMAXU_D)
+DECLARE_INSN(amoswap_d, MATCH_AMOSWAP_D, MASK_AMOSWAP_D)
+DECLARE_INSN(lr_d, MATCH_LR_D, MASK_LR_D)
+DECLARE_INSN(sc_d, MATCH_SC_D, MASK_SC_D)
+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(mret, MATCH_MRET, MASK_MRET)
+DECLARE_INSN(dret, MATCH_DRET, MASK_DRET)
+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)
+DECLARE_INSN(csrrc, MATCH_CSRRC, MASK_CSRRC)
+DECLARE_INSN(csrrwi, MATCH_CSRRWI, MASK_CSRRWI)
+DECLARE_INSN(csrrsi, MATCH_CSRRSI, MASK_CSRRSI)
+DECLARE_INSN(csrrci, MATCH_CSRRCI, MASK_CSRRCI)
+DECLARE_INSN(fadd_s, MATCH_FADD_S, MASK_FADD_S)
+DECLARE_INSN(fsub_s, MATCH_FSUB_S, MASK_FSUB_S)
+DECLARE_INSN(fmul_s, MATCH_FMUL_S, MASK_FMUL_S)
+DECLARE_INSN(fdiv_s, MATCH_FDIV_S, MASK_FDIV_S)
+DECLARE_INSN(fsgnj_s, MATCH_FSGNJ_S, MASK_FSGNJ_S)
+DECLARE_INSN(fsgnjn_s, MATCH_FSGNJN_S, MASK_FSGNJN_S)
+DECLARE_INSN(fsgnjx_s, MATCH_FSGNJX_S, MASK_FSGNJX_S)
+DECLARE_INSN(fmin_s, MATCH_FMIN_S, MASK_FMIN_S)
+DECLARE_INSN(fmax_s, MATCH_FMAX_S, MASK_FMAX_S)
+DECLARE_INSN(fsqrt_s, MATCH_FSQRT_S, MASK_FSQRT_S)
+DECLARE_INSN(fadd_d, MATCH_FADD_D, MASK_FADD_D)
+DECLARE_INSN(fsub_d, MATCH_FSUB_D, MASK_FSUB_D)
+DECLARE_INSN(fmul_d, MATCH_FMUL_D, MASK_FMUL_D)
+DECLARE_INSN(fdiv_d, MATCH_FDIV_D, MASK_FDIV_D)
+DECLARE_INSN(fsgnj_d, MATCH_FSGNJ_D, MASK_FSGNJ_D)
+DECLARE_INSN(fsgnjn_d, MATCH_FSGNJN_D, MASK_FSGNJN_D)
+DECLARE_INSN(fsgnjx_d, MATCH_FSGNJX_D, MASK_FSGNJX_D)
+DECLARE_INSN(fmin_d, MATCH_FMIN_D, MASK_FMIN_D)
+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_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)
+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_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)
+DECLARE_INSN(fnmadd_s, MATCH_FNMADD_S, MASK_FNMADD_S)
+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)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
+DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN)
+DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
+DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
+DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
+DECLARE_INSN(c_fsd, MATCH_C_FSD, MASK_C_FSD)
+DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
+DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
+DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
+DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI)
+DECLARE_INSN(c_srli, MATCH_C_SRLI, MASK_C_SRLI)
+DECLARE_INSN(c_srai, MATCH_C_SRAI, MASK_C_SRAI)
+DECLARE_INSN(c_andi, MATCH_C_ANDI, MASK_C_ANDI)
+DECLARE_INSN(c_sub, MATCH_C_SUB, MASK_C_SUB)
+DECLARE_INSN(c_xor, MATCH_C_XOR, MASK_C_XOR)
+DECLARE_INSN(c_or, MATCH_C_OR, MASK_C_OR)
+DECLARE_INSN(c_and, MATCH_C_AND, MASK_C_AND)
+DECLARE_INSN(c_subw, MATCH_C_SUBW, MASK_C_SUBW)
+DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW)
+DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
+DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
+DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
+DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP)
+DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
+DECLARE_INSN(c_flwsp, MATCH_C_FLWSP, MASK_C_FLWSP)
+DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV)
+DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
+DECLARE_INSN(c_fsdsp, MATCH_C_FSDSP, MASK_C_FSDSP)
+DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
+DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
+DECLARE_INSN(custom0, MATCH_CUSTOM0, MASK_CUSTOM0)
+DECLARE_INSN(custom0_rs1, MATCH_CUSTOM0_RS1, MASK_CUSTOM0_RS1)
+DECLARE_INSN(custom0_rs1_rs2, MATCH_CUSTOM0_RS1_RS2, MASK_CUSTOM0_RS1_RS2)
+DECLARE_INSN(custom0_rd, MATCH_CUSTOM0_RD, MASK_CUSTOM0_RD)
+DECLARE_INSN(custom0_rd_rs1, MATCH_CUSTOM0_RD_RS1, MASK_CUSTOM0_RD_RS1)
+DECLARE_INSN(custom0_rd_rs1_rs2, MATCH_CUSTOM0_RD_RS1_RS2, MASK_CUSTOM0_RD_RS1_RS2)
+DECLARE_INSN(custom1, MATCH_CUSTOM1, MASK_CUSTOM1)
+DECLARE_INSN(custom1_rs1, MATCH_CUSTOM1_RS1, MASK_CUSTOM1_RS1)
+DECLARE_INSN(custom1_rs1_rs2, MATCH_CUSTOM1_RS1_RS2, MASK_CUSTOM1_RS1_RS2)
+DECLARE_INSN(custom1_rd, MATCH_CUSTOM1_RD, MASK_CUSTOM1_RD)
+DECLARE_INSN(custom1_rd_rs1, MATCH_CUSTOM1_RD_RS1, MASK_CUSTOM1_RD_RS1)
+DECLARE_INSN(custom1_rd_rs1_rs2, MATCH_CUSTOM1_RD_RS1_RS2, MASK_CUSTOM1_RD_RS1_RS2)
+DECLARE_INSN(custom2, MATCH_CUSTOM2, MASK_CUSTOM2)
+DECLARE_INSN(custom2_rs1, MATCH_CUSTOM2_RS1, MASK_CUSTOM2_RS1)
+DECLARE_INSN(custom2_rs1_rs2, MATCH_CUSTOM2_RS1_RS2, MASK_CUSTOM2_RS1_RS2)
+DECLARE_INSN(custom2_rd, MATCH_CUSTOM2_RD, MASK_CUSTOM2_RD)
+DECLARE_INSN(custom2_rd_rs1, MATCH_CUSTOM2_RD_RS1, MASK_CUSTOM2_RD_RS1)
+DECLARE_INSN(custom2_rd_rs1_rs2, MATCH_CUSTOM2_RD_RS1_RS2, MASK_CUSTOM2_RD_RS1_RS2)
+DECLARE_INSN(custom3, MATCH_CUSTOM3, MASK_CUSTOM3)
+DECLARE_INSN(custom3_rs1, MATCH_CUSTOM3_RS1, MASK_CUSTOM3_RS1)
+DECLARE_INSN(custom3_rs1_rs2, MATCH_CUSTOM3_RS1_RS2, MASK_CUSTOM3_RS1_RS2)
+DECLARE_INSN(custom3_rd, MATCH_CUSTOM3_RD, MASK_CUSTOM3_RD)
+DECLARE_INSN(custom3_rd_rs1, MATCH_CUSTOM3_RD_RS1, MASK_CUSTOM3_RD_RS1)
+DECLARE_INSN(custom3_rd_rs1_rs2, MATCH_CUSTOM3_RD_RS1_RS2, MASK_CUSTOM3_RD_RS1_RS2)
+#endif
+#ifdef DECLARE_CSR
+DECLARE_CSR(fflags, CSR_FFLAGS)
+DECLARE_CSR(frm, CSR_FRM)
+DECLARE_CSR(fcsr, CSR_FCSR)
+DECLARE_CSR(cycle, CSR_CYCLE)
+DECLARE_CSR(time, CSR_TIME)
+DECLARE_CSR(instret, CSR_INSTRET)
+DECLARE_CSR(hpmcounter3, CSR_HPMCOUNTER3)
+DECLARE_CSR(hpmcounter4, CSR_HPMCOUNTER4)
+DECLARE_CSR(hpmcounter5, CSR_HPMCOUNTER5)
+DECLARE_CSR(hpmcounter6, CSR_HPMCOUNTER6)
+DECLARE_CSR(hpmcounter7, CSR_HPMCOUNTER7)
+DECLARE_CSR(hpmcounter8, CSR_HPMCOUNTER8)
+DECLARE_CSR(hpmcounter9, CSR_HPMCOUNTER9)
+DECLARE_CSR(hpmcounter10, CSR_HPMCOUNTER10)
+DECLARE_CSR(hpmcounter11, CSR_HPMCOUNTER11)
+DECLARE_CSR(hpmcounter12, CSR_HPMCOUNTER12)
+DECLARE_CSR(hpmcounter13, CSR_HPMCOUNTER13)
+DECLARE_CSR(hpmcounter14, CSR_HPMCOUNTER14)
+DECLARE_CSR(hpmcounter15, CSR_HPMCOUNTER15)
+DECLARE_CSR(hpmcounter16, CSR_HPMCOUNTER16)
+DECLARE_CSR(hpmcounter17, CSR_HPMCOUNTER17)
+DECLARE_CSR(hpmcounter18, CSR_HPMCOUNTER18)
+DECLARE_CSR(hpmcounter19, CSR_HPMCOUNTER19)
+DECLARE_CSR(hpmcounter20, CSR_HPMCOUNTER20)
+DECLARE_CSR(hpmcounter21, CSR_HPMCOUNTER21)
+DECLARE_CSR(hpmcounter22, CSR_HPMCOUNTER22)
+DECLARE_CSR(hpmcounter23, CSR_HPMCOUNTER23)
+DECLARE_CSR(hpmcounter24, CSR_HPMCOUNTER24)
+DECLARE_CSR(hpmcounter25, CSR_HPMCOUNTER25)
+DECLARE_CSR(hpmcounter26, CSR_HPMCOUNTER26)
+DECLARE_CSR(hpmcounter27, CSR_HPMCOUNTER27)
+DECLARE_CSR(hpmcounter28, CSR_HPMCOUNTER28)
+DECLARE_CSR(hpmcounter29, CSR_HPMCOUNTER29)
+DECLARE_CSR(hpmcounter30, CSR_HPMCOUNTER30)
+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)
+DECLARE_CSR(stval, CSR_STVAL)
+DECLARE_CSR(sip, CSR_SIP)
+DECLARE_CSR(satp, CSR_SATP)
+DECLARE_CSR(mstatus, CSR_MSTATUS)
+DECLARE_CSR(misa, CSR_MISA)
+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(mtval, CSR_MTVAL)
+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)
+DECLARE_CSR(tdata3, CSR_TDATA3)
+DECLARE_CSR(dcsr, CSR_DCSR)
+DECLARE_CSR(dpc, CSR_DPC)
+DECLARE_CSR(dscratch, CSR_DSCRATCH)
+DECLARE_CSR(mcycle, CSR_MCYCLE)
+DECLARE_CSR(minstret, CSR_MINSTRET)
+DECLARE_CSR(mhpmcounter3, CSR_MHPMCOUNTER3)
+DECLARE_CSR(mhpmcounter4, CSR_MHPMCOUNTER4)
+DECLARE_CSR(mhpmcounter5, CSR_MHPMCOUNTER5)
+DECLARE_CSR(mhpmcounter6, CSR_MHPMCOUNTER6)
+DECLARE_CSR(mhpmcounter7, CSR_MHPMCOUNTER7)
+DECLARE_CSR(mhpmcounter8, CSR_MHPMCOUNTER8)
+DECLARE_CSR(mhpmcounter9, CSR_MHPMCOUNTER9)
+DECLARE_CSR(mhpmcounter10, CSR_MHPMCOUNTER10)
+DECLARE_CSR(mhpmcounter11, CSR_MHPMCOUNTER11)
+DECLARE_CSR(mhpmcounter12, CSR_MHPMCOUNTER12)
+DECLARE_CSR(mhpmcounter13, CSR_MHPMCOUNTER13)
+DECLARE_CSR(mhpmcounter14, CSR_MHPMCOUNTER14)
+DECLARE_CSR(mhpmcounter15, CSR_MHPMCOUNTER15)
+DECLARE_CSR(mhpmcounter16, CSR_MHPMCOUNTER16)
+DECLARE_CSR(mhpmcounter17, CSR_MHPMCOUNTER17)
+DECLARE_CSR(mhpmcounter18, CSR_MHPMCOUNTER18)
+DECLARE_CSR(mhpmcounter19, CSR_MHPMCOUNTER19)
+DECLARE_CSR(mhpmcounter20, CSR_MHPMCOUNTER20)
+DECLARE_CSR(mhpmcounter21, CSR_MHPMCOUNTER21)
+DECLARE_CSR(mhpmcounter22, CSR_MHPMCOUNTER22)
+DECLARE_CSR(mhpmcounter23, CSR_MHPMCOUNTER23)
+DECLARE_CSR(mhpmcounter24, CSR_MHPMCOUNTER24)
+DECLARE_CSR(mhpmcounter25, CSR_MHPMCOUNTER25)
+DECLARE_CSR(mhpmcounter26, CSR_MHPMCOUNTER26)
+DECLARE_CSR(mhpmcounter27, CSR_MHPMCOUNTER27)
+DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28)
+DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29)
+DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30)
+DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31)
+DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3)
+DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4)
+DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5)
+DECLARE_CSR(mhpmevent6, CSR_MHPMEVENT6)
+DECLARE_CSR(mhpmevent7, CSR_MHPMEVENT7)
+DECLARE_CSR(mhpmevent8, CSR_MHPMEVENT8)
+DECLARE_CSR(mhpmevent9, CSR_MHPMEVENT9)
+DECLARE_CSR(mhpmevent10, CSR_MHPMEVENT10)
+DECLARE_CSR(mhpmevent11, CSR_MHPMEVENT11)
+DECLARE_CSR(mhpmevent12, CSR_MHPMEVENT12)
+DECLARE_CSR(mhpmevent13, CSR_MHPMEVENT13)
+DECLARE_CSR(mhpmevent14, CSR_MHPMEVENT14)
+DECLARE_CSR(mhpmevent15, CSR_MHPMEVENT15)
+DECLARE_CSR(mhpmevent16, CSR_MHPMEVENT16)
+DECLARE_CSR(mhpmevent17, CSR_MHPMEVENT17)
+DECLARE_CSR(mhpmevent18, CSR_MHPMEVENT18)
+DECLARE_CSR(mhpmevent19, CSR_MHPMEVENT19)
+DECLARE_CSR(mhpmevent20, CSR_MHPMEVENT20)
+DECLARE_CSR(mhpmevent21, CSR_MHPMEVENT21)
+DECLARE_CSR(mhpmevent22, CSR_MHPMEVENT22)
+DECLARE_CSR(mhpmevent23, CSR_MHPMEVENT23)
+DECLARE_CSR(mhpmevent24, CSR_MHPMEVENT24)
+DECLARE_CSR(mhpmevent25, CSR_MHPMEVENT25)
+DECLARE_CSR(mhpmevent26, CSR_MHPMEVENT26)
+DECLARE_CSR(mhpmevent27, CSR_MHPMEVENT27)
+DECLARE_CSR(mhpmevent28, CSR_MHPMEVENT28)
+DECLARE_CSR(mhpmevent29, CSR_MHPMEVENT29)
+DECLARE_CSR(mhpmevent30, CSR_MHPMEVENT30)
+DECLARE_CSR(mhpmevent31, CSR_MHPMEVENT31)
+DECLARE_CSR(mvendorid, CSR_MVENDORID)
+DECLARE_CSR(marchid, CSR_MARCHID)
+DECLARE_CSR(mimpid, CSR_MIMPID)
+DECLARE_CSR(mhartid, CSR_MHARTID)
+DECLARE_CSR(cycleh, CSR_CYCLEH)
+DECLARE_CSR(timeh, CSR_TIMEH)
+DECLARE_CSR(instreth, CSR_INSTRETH)
+DECLARE_CSR(hpmcounter3h, CSR_HPMCOUNTER3H)
+DECLARE_CSR(hpmcounter4h, CSR_HPMCOUNTER4H)
+DECLARE_CSR(hpmcounter5h, CSR_HPMCOUNTER5H)
+DECLARE_CSR(hpmcounter6h, CSR_HPMCOUNTER6H)
+DECLARE_CSR(hpmcounter7h, CSR_HPMCOUNTER7H)
+DECLARE_CSR(hpmcounter8h, CSR_HPMCOUNTER8H)
+DECLARE_CSR(hpmcounter9h, CSR_HPMCOUNTER9H)
+DECLARE_CSR(hpmcounter10h, CSR_HPMCOUNTER10H)
+DECLARE_CSR(hpmcounter11h, CSR_HPMCOUNTER11H)
+DECLARE_CSR(hpmcounter12h, CSR_HPMCOUNTER12H)
+DECLARE_CSR(hpmcounter13h, CSR_HPMCOUNTER13H)
+DECLARE_CSR(hpmcounter14h, CSR_HPMCOUNTER14H)
+DECLARE_CSR(hpmcounter15h, CSR_HPMCOUNTER15H)
+DECLARE_CSR(hpmcounter16h, CSR_HPMCOUNTER16H)
+DECLARE_CSR(hpmcounter17h, CSR_HPMCOUNTER17H)
+DECLARE_CSR(hpmcounter18h, CSR_HPMCOUNTER18H)
+DECLARE_CSR(hpmcounter19h, CSR_HPMCOUNTER19H)
+DECLARE_CSR(hpmcounter20h, CSR_HPMCOUNTER20H)
+DECLARE_CSR(hpmcounter21h, CSR_HPMCOUNTER21H)
+DECLARE_CSR(hpmcounter22h, CSR_HPMCOUNTER22H)
+DECLARE_CSR(hpmcounter23h, CSR_HPMCOUNTER23H)
+DECLARE_CSR(hpmcounter24h, CSR_HPMCOUNTER24H)
+DECLARE_CSR(hpmcounter25h, CSR_HPMCOUNTER25H)
+DECLARE_CSR(hpmcounter26h, CSR_HPMCOUNTER26H)
+DECLARE_CSR(hpmcounter27h, CSR_HPMCOUNTER27H)
+DECLARE_CSR(hpmcounter28h, CSR_HPMCOUNTER28H)
+DECLARE_CSR(hpmcounter29h, CSR_HPMCOUNTER29H)
+DECLARE_CSR(hpmcounter30h, CSR_HPMCOUNTER30H)
+DECLARE_CSR(hpmcounter31h, CSR_HPMCOUNTER31H)
+DECLARE_CSR(mcycleh, CSR_MCYCLEH)
+DECLARE_CSR(minstreth, CSR_MINSTRETH)
+DECLARE_CSR(mhpmcounter3h, CSR_MHPMCOUNTER3H)
+DECLARE_CSR(mhpmcounter4h, CSR_MHPMCOUNTER4H)
+DECLARE_CSR(mhpmcounter5h, CSR_MHPMCOUNTER5H)
+DECLARE_CSR(mhpmcounter6h, CSR_MHPMCOUNTER6H)
+DECLARE_CSR(mhpmcounter7h, CSR_MHPMCOUNTER7H)
+DECLARE_CSR(mhpmcounter8h, CSR_MHPMCOUNTER8H)
+DECLARE_CSR(mhpmcounter9h, CSR_MHPMCOUNTER9H)
+DECLARE_CSR(mhpmcounter10h, CSR_MHPMCOUNTER10H)
+DECLARE_CSR(mhpmcounter11h, CSR_MHPMCOUNTER11H)
+DECLARE_CSR(mhpmcounter12h, CSR_MHPMCOUNTER12H)
+DECLARE_CSR(mhpmcounter13h, CSR_MHPMCOUNTER13H)
+DECLARE_CSR(mhpmcounter14h, CSR_MHPMCOUNTER14H)
+DECLARE_CSR(mhpmcounter15h, CSR_MHPMCOUNTER15H)
+DECLARE_CSR(mhpmcounter16h, CSR_MHPMCOUNTER16H)
+DECLARE_CSR(mhpmcounter17h, CSR_MHPMCOUNTER17H)
+DECLARE_CSR(mhpmcounter18h, CSR_MHPMCOUNTER18H)
+DECLARE_CSR(mhpmcounter19h, CSR_MHPMCOUNTER19H)
+DECLARE_CSR(mhpmcounter20h, CSR_MHPMCOUNTER20H)
+DECLARE_CSR(mhpmcounter21h, CSR_MHPMCOUNTER21H)
+DECLARE_CSR(mhpmcounter22h, CSR_MHPMCOUNTER22H)
+DECLARE_CSR(mhpmcounter23h, CSR_MHPMCOUNTER23H)
+DECLARE_CSR(mhpmcounter24h, CSR_MHPMCOUNTER24H)
+DECLARE_CSR(mhpmcounter25h, CSR_MHPMCOUNTER25H)
+DECLARE_CSR(mhpmcounter26h, CSR_MHPMCOUNTER26H)
+DECLARE_CSR(mhpmcounter27h, CSR_MHPMCOUNTER27H)
+DECLARE_CSR(mhpmcounter28h, CSR_MHPMCOUNTER28H)
+DECLARE_CSR(mhpmcounter29h, CSR_MHPMCOUNTER29H)
+DECLARE_CSR(mhpmcounter30h, CSR_MHPMCOUNTER30H)
+DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H)
+#endif
+#ifdef DECLARE_CAUSE
+DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_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("load access", CAUSE_LOAD_ACCESS)
+DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_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/fesvr/fesvr.ac b/fesvr/fesvr.ac
new file mode 100644
index 0000000..60e6c57
--- /dev/null
+++ b/fesvr/fesvr.ac
@@ -0,0 +1 @@
+AC_CHECK_LIB(pthread, pthread_create, [], [AC_MSG_ERROR([libpthread is required])])
diff --git a/fesvr/fesvr.mk.in b/fesvr/fesvr.mk.in
new file mode 100644
index 0000000..cad3387
--- /dev/null
+++ b/fesvr/fesvr.mk.in
@@ -0,0 +1,38 @@
+fesvr_hdrs = \
+ elf.h \
+ elfloader.h \
+ htif.h \
+ dtm.h \
+ memif.h \
+ syscall.h \
+ context.h \
+ htif_pthread.h \
+ htif_hexwriter.h \
+ option_parser.h \
+ term.h \
+ device.h \
+ rfb.h \
+ tsi.h \
+
+fesvr_install_hdrs = $(fesvr_hdrs)
+
+fesvr_install_lib = yes
+
+fesvr_srcs = \
+ elfloader.cc \
+ htif.cc \
+ memif.cc \
+ dtm.cc \
+ syscall.cc \
+ device.cc \
+ rfb.cc \
+ context.cc \
+ htif_pthread.cc \
+ htif_hexwriter.cc \
+ dummy.cc \
+ option_parser.cc \
+ term.cc \
+ tsi.cc \
+
+fesvr_install_prog_srcs = \
+ elf2hex.cc \
diff --git a/fesvr/fesvr.pc.in b/fesvr/fesvr.pc.in
new file mode 100644
index 0000000..f2d1256
--- /dev/null
+++ b/fesvr/fesvr.pc.in
@@ -0,0 +1,26 @@
+#=========================================================================
+# Modular C++ Build System Subproject Package Config
+#=========================================================================
+# Please read the documenation in 'mcppbs-uguide.txt' for more details
+# on how the Modular C++ Build System works.
+
+#-------------------------------------------------------------------------
+# Generic variables
+#-------------------------------------------------------------------------
+
+prefix=@prefix@
+include_dir=${prefix}/include/fesvr
+lib_dir=${prefix}/lib
+
+#-------------------------------------------------------------------------
+# Keywords
+#-------------------------------------------------------------------------
+
+Name : fesvr
+Version : @PACKAGE_VERSION@
+Description : Frontend Server C/C++ API
+Requires : @fesvr_pkcdeps@
+Cflags : -I${include_dir} @CPPFLAGS@ @fesvr_extra_cppflags@
+Libs : -L${lib_dir} @LDFLAGS@ @fesvr_extra_ldflags@ \
+ -lfesvr @fesvr_extra_libs@
+
diff --git a/fesvr/htif.cc b/fesvr/htif.cc
new file mode 100644
index 0000000..d9ff341
--- /dev/null
+++ b/fesvr/htif.cc
@@ -0,0 +1,329 @@
+// See LICENSE for license details.
+
+#include "htif.h"
+#include "rfb.h"
+#include "elfloader.h"
+#include "encoding.h"
+#include <algorithm>
+#include <assert.h>
+#include <vector>
+#include <queue>
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <getopt.h>
+
+/* Attempt to determine the execution prefix automatically. autoconf
+ * sets PREFIX, and pconfigure sets __PCONFIGURE__PREFIX. */
+#if !defined(PREFIX) && defined(__PCONFIGURE__PREFIX)
+# define PREFIX __PCONFIGURE__PREFIX
+#endif
+
+#ifndef TARGET_ARCH
+# define TARGET_ARCH "riscv64-unknown-elf"
+#endif
+
+#ifndef TARGET_DIR
+# define TARGET_DIR "/" TARGET_ARCH "/bin/"
+#endif
+
+static volatile bool signal_exit = false;
+static void handle_signal(int sig)
+{
+ if (sig == SIGABRT || signal_exit) // someone set up us the bomb!
+ exit(-1);
+ signal_exit = true;
+ signal(sig, &handle_signal);
+}
+
+htif_t::htif_t()
+ : mem(this), entry(DRAM_BASE), sig_addr(0), sig_len(0),
+ tohost_addr(0), fromhost_addr(0), exitcode(0), stopped(false),
+ syscall_proxy(this)
+{
+ signal(SIGINT, &handle_signal);
+ signal(SIGTERM, &handle_signal);
+ signal(SIGABRT, &handle_signal); // we still want to call static destructors
+}
+
+htif_t::htif_t(int argc, char** argv) : htif_t()
+{
+ parse_arguments(argc, argv);
+ register_devices();
+}
+
+htif_t::htif_t(const std::vector<std::string>& args) : htif_t()
+{
+ int argc = args.size() + 1;
+ char * argv[argc];
+ argv[0] = (char *) "htif";
+ for (unsigned int i = 0; i < args.size(); i++) {
+ argv[i+1] = (char *) args[i].c_str();
+ }
+
+ parse_arguments(argc, argv);
+ register_devices();
+}
+
+htif_t::~htif_t()
+{
+ for (auto d : dynamic_devices)
+ delete d;
+}
+
+void htif_t::start()
+{
+ if (!targs.empty() && targs[0] != "none")
+ load_program();
+
+ reset();
+}
+
+void htif_t::load_program()
+{
+ std::string path;
+ if (access(targs[0].c_str(), F_OK) == 0)
+ path = targs[0];
+ else if (targs[0].find('/') == std::string::npos)
+ {
+ std::string test_path = PREFIX TARGET_DIR + targs[0];
+ if (access(test_path.c_str(), F_OK) == 0)
+ path = test_path;
+ }
+
+ if (path.empty())
+ throw std::runtime_error(
+ "could not open " + targs[0] +
+ " (did you misspell it? If VCS, did you forget +permissive/+permissive-off?)");
+
+ // temporarily construct a memory interface that skips writing bytes
+ // that have already been preloaded through a sideband
+ class preload_aware_memif_t : public memif_t {
+ public:
+ preload_aware_memif_t(htif_t* htif) : memif_t(htif), htif(htif) {}
+
+ void write(addr_t taddr, size_t len, const void* src) override
+ {
+ if (!htif->is_address_preloaded(taddr, len))
+ memif_t::write(taddr, len, src);
+ }
+
+ private:
+ htif_t* htif;
+ } preload_aware_memif(this);
+
+ std::map<std::string, uint64_t> symbols = load_elf(path.c_str(), &preload_aware_memif, &entry);
+
+ if (symbols.count("tohost") && symbols.count("fromhost")) {
+ tohost_addr = symbols["tohost"];
+ fromhost_addr = symbols["fromhost"];
+ } else {
+ fprintf(stderr, "warning: tohost and fromhost symbols not in ELF; can't communicate with target\n");
+ }
+
+ // detect torture tests so we can print the memory signature at the end
+ if (symbols.count("begin_signature") && symbols.count("end_signature"))
+ {
+ sig_addr = symbols["begin_signature"];
+ sig_len = symbols["end_signature"] - sig_addr;
+ }
+}
+
+void htif_t::stop()
+{
+ if (!sig_file.empty() && sig_len) // print final torture test signature
+ {
+ std::vector<uint8_t> buf(sig_len);
+ mem.read(sig_addr, sig_len, &buf[0]);
+
+ std::ofstream sigs(sig_file);
+ assert(sigs && "can't open signature file!");
+ sigs << std::setfill('0') << std::hex;
+
+ const addr_t incr = 16;
+ assert(sig_len % incr == 0);
+ for (addr_t i = 0; i < sig_len; i += incr)
+ {
+ for (addr_t j = incr; j > 0; j--)
+ sigs << std::setw(2) << (uint16_t)buf[i+j-1];
+ sigs << '\n';
+ }
+
+ sigs.close();
+ }
+
+ stopped = true;
+}
+
+void htif_t::clear_chunk(addr_t taddr, size_t len)
+{
+ char zeros[chunk_max_size()];
+ memset(zeros, 0, chunk_max_size());
+
+ for (size_t pos = 0; pos < len; pos += chunk_max_size())
+ write_chunk(taddr + pos, std::min(len - pos, chunk_max_size()), zeros);
+}
+
+int htif_t::run()
+{
+ start();
+
+ auto enq_func = [](std::queue<reg_t>* q, uint64_t x) { q->push(x); };
+ std::queue<reg_t> fromhost_queue;
+ std::function<void(reg_t)> fromhost_callback =
+ std::bind(enq_func, &fromhost_queue, std::placeholders::_1);
+
+ if (tohost_addr == 0) {
+ while (true)
+ idle();
+ }
+
+ while (!signal_exit && exitcode == 0)
+ {
+ if (auto tohost = mem.read_uint64(tohost_addr)) {
+ mem.write_uint64(tohost_addr, 0);
+ command_t cmd(mem, tohost, fromhost_callback);
+ device_list.handle_command(cmd);
+ } else {
+ idle();
+ }
+
+ device_list.tick();
+
+ if (!fromhost_queue.empty() && mem.read_uint64(fromhost_addr) == 0) {
+ mem.write_uint64(fromhost_addr, fromhost_queue.front());
+ fromhost_queue.pop();
+ }
+ }
+
+ stop();
+
+ return exit_code();
+}
+
+bool htif_t::done()
+{
+ return stopped;
+}
+
+int htif_t::exit_code()
+{
+ return exitcode >> 1;
+}
+
+void htif_t::parse_arguments(int argc, char ** argv)
+{
+ optind = 0; // reset optind as HTIF may run getopt _after_ others
+ while (1) {
+ static struct option long_options[] = { HTIF_LONG_OPTIONS };
+ int option_index = 0;
+ int c = getopt_long(argc, argv, "-h", long_options, &option_index);
+
+ if (c == -1) break;
+ retry:
+ switch (c) {
+ case 'h': usage(argv[0]);
+ throw std::invalid_argument("User quered htif_t help text");
+ case HTIF_LONG_OPTIONS_OPTIND:
+ if (optarg) dynamic_devices.push_back(new rfb_t(atoi(optarg)));
+ else dynamic_devices.push_back(new rfb_t);
+ break;
+ case HTIF_LONG_OPTIONS_OPTIND + 1:
+ // [TODO] Remove once disks are supported again
+ throw std::invalid_argument("--disk/+disk unsupported (use a ramdisk)");
+ dynamic_devices.push_back(new disk_t(optarg));
+ break;
+ case HTIF_LONG_OPTIONS_OPTIND + 2:
+ sig_file = optarg;
+ break;
+ case HTIF_LONG_OPTIONS_OPTIND + 3:
+ syscall_proxy.set_chroot(optarg);
+ break;
+ case '?':
+ if (!opterr)
+ break;
+ throw std::invalid_argument("Unknown argument (did you mean to enable +permissive parsing?)");
+ case 1: {
+ std::string arg = optarg;
+ if (arg == "+rfb") {
+ c = HTIF_LONG_OPTIONS_OPTIND;
+ optarg = nullptr;
+ }
+ else if (arg.find("+rfb=") == 0) {
+ c = HTIF_LONG_OPTIONS_OPTIND;
+ optarg = optarg + 5;
+ }
+ else if (arg.find("+disk=") == 0) {
+ c = HTIF_LONG_OPTIONS_OPTIND + 1;
+ optarg = optarg + 6;
+ }
+ else if (arg.find("+signature=") == 0) {
+ c = HTIF_LONG_OPTIONS_OPTIND + 2;
+ optarg = optarg + 11;
+ }
+ else if (arg.find("+chroot=") == 0) {
+ c = HTIF_LONG_OPTIONS_OPTIND + 3;
+ optarg = optarg + 8;
+ }
+ else if (arg.find("+permissive-off") == 0) {
+ if (opterr)
+ throw std::invalid_argument("Found +permissive-off when not parsing permissively");
+ opterr = 1;
+ break;
+ }
+ else if (arg.find("+permissive") == 0) {
+ if (!opterr)
+ throw std::invalid_argument("Found +permissive when already parsing permissively");
+ opterr = 0;
+ break;
+ }
+ else {
+ if (!opterr)
+ break;
+ else {
+ optind--;
+ goto done_processing;
+ }
+ }
+ goto retry;
+ }
+ }
+ }
+
+done_processing:
+ while (optind < argc)
+ targs.push_back(argv[optind++]);
+ if (!targs.size()) {
+ usage(argv[0]);
+ throw std::invalid_argument("No binary specified (Did you forget it? Did you forget '+permissive-off' if running with +permissive?)");
+ }
+}
+
+void htif_t::register_devices()
+{
+ device_list.register_device(&syscall_proxy);
+ device_list.register_device(&bcd);
+ for (auto d : dynamic_devices)
+ device_list.register_device(d);
+}
+
+void htif_t::usage(const char * program_name)
+{
+ printf("Usage: %s [EMULATOR OPTION]... [VERILOG PLUSARG]... [HOST OPTION]... BINARY [TARGET OPTION]...\n ",
+ program_name);
+ fputs("\
+Run a BINARY on the Rocket Chip emulator.\n\
+\n\
+Mandatory arguments to long options are mandatory for short options too.\n\
+\n\
+EMULATOR OPTIONS\n\
+ Consult emulator.cc if using Verilator or VCS documentation if using VCS\n\
+ for available options.\n\
+EMUALTOR VERILOG PLUSARGS\n\
+ Consult generated-src*/*.plusArgs for available options\n\
+", stdout);
+ fputs("\n" HTIF_USAGE_OPTIONS, stdout);
+}
diff --git a/fesvr/htif.h b/fesvr/htif.h
new file mode 100644
index 0000000..d312c77
--- /dev/null
+++ b/fesvr/htif.h
@@ -0,0 +1,114 @@
+// See LICENSE for license details.
+
+#ifndef __HTIF_H
+#define __HTIF_H
+
+#include "memif.h"
+#include "syscall.h"
+#include "device.h"
+#include <string.h>
+#include <vector>
+
+class htif_t : public chunked_memif_t
+{
+ public:
+ htif_t();
+ htif_t(int argc, char** argv);
+ htif_t(const std::vector<std::string>& args);
+ virtual ~htif_t();
+
+ virtual void start();
+ virtual void stop();
+
+ int run();
+ bool done();
+ int exit_code();
+
+ virtual memif_t& memif() { return mem; }
+
+ protected:
+ virtual void reset() = 0;
+
+ virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0;
+ virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0;
+ virtual void clear_chunk(addr_t taddr, size_t len);
+
+ virtual size_t chunk_align() = 0;
+ virtual size_t chunk_max_size() = 0;
+
+ virtual void load_program();
+ virtual void idle() {}
+
+ const std::vector<std::string>& host_args() { return hargs; }
+
+ reg_t get_entry_point() { return entry; }
+
+ // indicates that the initial program load can skip writing this address
+ // range to memory, because it has already been loaded through a sideband
+ virtual bool is_address_preloaded(addr_t taddr, size_t len) { return false; }
+
+ private:
+ void parse_arguments(int argc, char ** argv);
+ void register_devices();
+ void usage(const char * program_name);
+
+ memif_t mem;
+ reg_t entry;
+ bool writezeros;
+ std::vector<std::string> hargs;
+ std::vector<std::string> targs;
+ std::string sig_file;
+ addr_t sig_addr; // torture
+ addr_t sig_len; // torture
+ addr_t tohost_addr;
+ addr_t fromhost_addr;
+ int exitcode;
+ bool stopped;
+
+ device_list_t device_list;
+ syscall_t syscall_proxy;
+ bcd_t bcd;
+ std::vector<device_t*> dynamic_devices;
+
+ const std::vector<std::string>& target_args() { return targs; }
+
+ friend class memif_t;
+ friend class syscall_t;
+};
+
+/* Alignment guide for emulator.cc options:
+ -x, --long-option Description with max 80 characters --------------->\n\
+ +plus-arg-equivalent\n\
+ */
+#define HTIF_USAGE_OPTIONS \
+"HOST OPTIONS\n\
+ -h, --help Display this help and exit\n\
+ +permissive The host will ignore any unparsed options up until\n\
+ +permissive-off (Only needed for VCS)\n\
+ +permissive-off Stop ignoring options. This is mandatory if using\n\
+ +permissive (Only needed for VCS)\n\
+ --rfb=DISPLAY Add new remote frame buffer on display DISPLAY\n\
+ +rfb=DISPLAY to be accessible on 5900 + DISPLAY (default = 0)\n\
+ --signature=FILE Write torture test signature to FILE\n\
+ +signature=FILE\n\
+ --chroot=PATH Use PATH as location of syscall-servicing binaries\n\
+ +chroot=PATH\n\
+\n\
+HOST OPTIONS (currently unsupported)\n\
+ --disk=DISK Add DISK device. Use a ramdisk since this isn't\n\
+ +disk=DISK supported\n\
+\n\
+TARGET (RISC-V BINARY) OPTIONS\n\
+ These are the options passed to the program executing on the emulated RISC-V\n\
+ microprocessor.\n"
+
+#define HTIF_LONG_OPTIONS_OPTIND 1024
+#define HTIF_LONG_OPTIONS \
+{"help", no_argument, 0, 'h' }, \
+{"rfb", optional_argument, 0, HTIF_LONG_OPTIONS_OPTIND }, \
+{"disk", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 1 }, \
+{"signature", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 2 }, \
+{"chroot", required_argument, 0, HTIF_LONG_OPTIONS_OPTIND + 3 }, \
+{0, 0, 0, 0}
+
+#endif // __HTIF_H
diff --git a/fesvr/htif_hexwriter.cc b/fesvr/htif_hexwriter.cc
new file mode 100644
index 0000000..e4811b3
--- /dev/null
+++ b/fesvr/htif_hexwriter.cc
@@ -0,0 +1,76 @@
+// See LICENSE for license details.
+
+#include <iostream>
+#include <assert.h>
+#include "htif_hexwriter.h"
+
+htif_hexwriter_t::htif_hexwriter_t(size_t b, size_t w, size_t d)
+ : base(b), width(w), depth(d)
+{
+}
+
+void htif_hexwriter_t::read_chunk(addr_t taddr, size_t len, void* vdst)
+{
+ taddr -= base;
+
+ assert(len % chunk_align() == 0);
+ assert(taddr < width*depth);
+ assert(taddr+len <= width*depth);
+
+ uint8_t* dst = (uint8_t*)vdst;
+ while(len)
+ {
+ if(mem[taddr/width].size() == 0)
+ mem[taddr/width].resize(width,0);
+
+ for(size_t j = 0; j < width; j++)
+ dst[j] = mem[taddr/width][j];
+
+ len -= width;
+ taddr += width;
+ dst += width;
+ }
+}
+
+void htif_hexwriter_t::write_chunk(addr_t taddr, size_t len, const void* vsrc)
+{
+ taddr -= base;
+
+ assert(len % chunk_align() == 0);
+ assert(taddr < width*depth);
+ assert(taddr+len <= width*depth);
+
+ const uint8_t* src = (const uint8_t*)vsrc;
+ while(len)
+ {
+ if(mem[taddr/width].size() == 0)
+ mem[taddr/width].resize(width,0);
+
+ for(size_t j = 0; j < width; j++)
+ mem[taddr/width][j] = src[j];
+
+ len -= width;
+ taddr += width;
+ }
+}
+
+std::ostream& operator<< (std::ostream& o, const htif_hexwriter_t& h)
+{
+ std::ios_base::fmtflags flags = o.setf(std::ios::hex,std::ios::basefield);
+
+ for(size_t addr = 0; addr < h.depth; addr++)
+ {
+ std::map<addr_t,std::vector<char> >::const_iterator i = h.mem.find(addr);
+ if(i == h.mem.end())
+ for(size_t j = 0; j < h.width; j++)
+ o << "00";
+ else
+ for(size_t j = 0; j < h.width; j++)
+ o << ((i->second[h.width-j-1] >> 4) & 0xF) << (i->second[h.width-j-1] & 0xF);
+ o << std::endl;
+ }
+
+ o.setf(flags);
+
+ return o;
+}
diff --git a/fesvr/htif_hexwriter.h b/fesvr/htif_hexwriter.h
new file mode 100644
index 0000000..7256166
--- /dev/null
+++ b/fesvr/htif_hexwriter.h
@@ -0,0 +1,32 @@
+// See LICENSE for license details.
+
+#ifndef __HTIF_HEXWRITER_H
+#define __HTIF_HEXWRITER_H
+
+#include <map>
+#include <vector>
+#include <stdlib.h>
+#include "memif.h"
+
+class htif_hexwriter_t : public chunked_memif_t
+{
+public:
+ htif_hexwriter_t(size_t b, size_t w, size_t d);
+
+protected:
+ size_t base;
+ size_t width;
+ size_t depth;
+ std::map<addr_t,std::vector<char> > mem;
+
+ void read_chunk(addr_t taddr, size_t len, void* dst);
+ void write_chunk(addr_t taddr, size_t len, const void* src);
+ void clear_chunk(addr_t taddr, size_t len) {}
+
+ size_t chunk_max_size() { return width; }
+ size_t chunk_align() { return width; }
+
+ friend std::ostream& operator<< (std::ostream&, const htif_hexwriter_t&);
+};
+
+#endif // __HTIF_HEXWRITER_H
diff --git a/fesvr/htif_pthread.cc b/fesvr/htif_pthread.cc
new file mode 100644
index 0000000..b9e3832
--- /dev/null
+++ b/fesvr/htif_pthread.cc
@@ -0,0 +1,66 @@
+// See LICENSE for license details.
+
+#include "htif_pthread.h"
+#include <algorithm>
+#include <stdio.h>
+
+void htif_pthread_t::thread_main(void* arg)
+{
+ htif_pthread_t* htif = static_cast<htif_pthread_t*>(arg);
+ htif->run();
+ while (true)
+ htif->target->switch_to();
+}
+
+htif_pthread_t::htif_pthread_t(int argc, char** argv)
+ : htif_t(argc, argv)
+{
+ target = context_t::current();
+ host.init(thread_main, this);
+}
+
+htif_pthread_t::~htif_pthread_t()
+{
+}
+
+ssize_t htif_pthread_t::read(void* buf, size_t max_size)
+{
+ while (th_data.size() == 0)
+ target->switch_to();
+
+ size_t s = std::min(max_size, th_data.size());
+ std::copy(th_data.begin(), th_data.begin() + s, (char*)buf);
+ th_data.erase(th_data.begin(), th_data.begin() + s);
+
+ return s;
+}
+
+ssize_t htif_pthread_t::write(const void* buf, size_t size)
+{
+ ht_data.insert(ht_data.end(), (const char*)buf, (const char*)buf + size);
+ return size;
+}
+
+void htif_pthread_t::send(const void* buf, size_t size)
+{
+ th_data.insert(th_data.end(), (const char*)buf, (const char*)buf + size);
+}
+
+void htif_pthread_t::recv(void* buf, size_t size)
+{
+ while (!this->recv_nonblocking(buf, size))
+ ;
+}
+
+bool htif_pthread_t::recv_nonblocking(void* buf, size_t size)
+{
+ if (ht_data.size() < size)
+ {
+ host.switch_to();
+ return false;
+ }
+
+ std::copy(ht_data.begin(), ht_data.begin() + size, (char*)buf);
+ ht_data.erase(ht_data.begin(), ht_data.begin() + size);
+ return true;
+}
diff --git a/fesvr/htif_pthread.h b/fesvr/htif_pthread.h
new file mode 100644
index 0000000..c00c382
--- /dev/null
+++ b/fesvr/htif_pthread.h
@@ -0,0 +1,38 @@
+// See LICENSE for license details.
+
+#ifndef _HTIF_PTHREAD_H
+#define _HTIF_PTHREAD_H
+
+#include "htif.h"
+#include "context.h"
+#include <deque>
+
+class htif_pthread_t : public htif_t
+{
+ public:
+ htif_pthread_t(int argc, char** argv);
+ virtual ~htif_pthread_t();
+
+ // target inteface
+ void send(const void* buf, size_t size);
+ void recv(void* buf, size_t size);
+ bool recv_nonblocking(void* buf, size_t size);
+
+ protected:
+ // host interface
+ virtual ssize_t read(void* buf, size_t max_size);
+ virtual ssize_t write(const void* buf, size_t size);
+
+ virtual size_t chunk_align() { return 64; }
+ virtual size_t chunk_max_size() { return 1024; }
+
+ private:
+ context_t host;
+ context_t* target;
+ std::deque<char> th_data;
+ std::deque<char> ht_data;
+
+ static void thread_main(void* htif);
+};
+
+#endif
diff --git a/fesvr/memif.cc b/fesvr/memif.cc
new file mode 100644
index 0000000..fd96291
--- /dev/null
+++ b/fesvr/memif.cc
@@ -0,0 +1,183 @@
+// See LICENSE for license details.
+
+#include <algorithm>
+#include <stdlib.h>
+#include <string.h>
+#include <stdexcept>
+#include "memif.h"
+
+void memif_t::read(addr_t addr, size_t len, void* bytes)
+{
+ size_t align = cmemif->chunk_align();
+ if (len && (addr & (align-1)))
+ {
+ size_t this_len = std::min(len, align - size_t(addr & (align-1)));
+ uint8_t chunk[align];
+
+ cmemif->read_chunk(addr & ~(align-1), align, chunk);
+ memcpy(bytes, chunk + (addr & (align-1)), this_len);
+
+ bytes = (char*)bytes + this_len;
+ addr += this_len;
+ len -= this_len;
+ }
+
+ if (len & (align-1))
+ {
+ size_t this_len = len & (align-1);
+ size_t start = len - this_len;
+ uint8_t chunk[align];
+
+ cmemif->read_chunk(addr + start, align, chunk);
+ memcpy((char*)bytes + start, chunk, this_len);
+
+ len -= this_len;
+ }
+
+ // now we're aligned
+ for (size_t pos = 0; pos < len; pos += cmemif->chunk_max_size())
+ cmemif->read_chunk(addr + pos, std::min(cmemif->chunk_max_size(), len - pos), (char*)bytes + pos);
+}
+
+void memif_t::write(addr_t addr, size_t len, const void* bytes)
+{
+ size_t align = cmemif->chunk_align();
+ if (len && (addr & (align-1)))
+ {
+ size_t this_len = std::min(len, align - size_t(addr & (align-1)));
+ uint8_t chunk[align];
+
+ cmemif->read_chunk(addr & ~(align-1), align, chunk);
+ memcpy(chunk + (addr & (align-1)), bytes, this_len);
+ cmemif->write_chunk(addr & ~(align-1), align, chunk);
+
+ bytes = (char*)bytes + this_len;
+ addr += this_len;
+ len -= this_len;
+ }
+
+ if (len & (align-1))
+ {
+ size_t this_len = len & (align-1);
+ size_t start = len - this_len;
+ uint8_t chunk[align];
+
+ cmemif->read_chunk(addr + start, align, chunk);
+ memcpy(chunk, (char*)bytes + start, this_len);
+ cmemif->write_chunk(addr + start, align, chunk);
+
+ len -= this_len;
+ }
+
+ // now we're aligned
+ bool all_zero = len != 0;
+ for (size_t i = 0; i < len; i++)
+ all_zero &= ((const char*)bytes)[i] == 0;
+
+ if (all_zero) {
+ cmemif->clear_chunk(addr, len);
+ } else {
+ size_t max_chunk = cmemif->chunk_max_size();
+ for (size_t pos = 0; pos < len; pos += max_chunk)
+ cmemif->write_chunk(addr + pos, std::min(max_chunk, len - pos), (char*)bytes + pos);
+ }
+}
+
+#define MEMIF_READ_FUNC \
+ if(addr & (sizeof(val)-1)) \
+ throw std::runtime_error("misaligned address"); \
+ this->read(addr, sizeof(val), &val); \
+ return val
+
+#define MEMIF_WRITE_FUNC \
+ if(addr & (sizeof(val)-1)) \
+ throw std::runtime_error("misaligned address"); \
+ this->write(addr, sizeof(val), &val)
+
+uint8_t memif_t::read_uint8(addr_t addr)
+{
+ uint8_t val;
+ MEMIF_READ_FUNC;
+}
+
+int8_t memif_t::read_int8(addr_t addr)
+{
+ int8_t val;
+ MEMIF_READ_FUNC;
+}
+
+void memif_t::write_uint8(addr_t addr, uint8_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+void memif_t::write_int8(addr_t addr, int8_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+uint16_t memif_t::read_uint16(addr_t addr)
+{
+ uint16_t val;
+ MEMIF_READ_FUNC;
+}
+
+int16_t memif_t::read_int16(addr_t addr)
+{
+ int16_t val;
+ MEMIF_READ_FUNC;
+}
+
+void memif_t::write_uint16(addr_t addr, uint16_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+void memif_t::write_int16(addr_t addr, int16_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+uint32_t memif_t::read_uint32(addr_t addr)
+{
+ uint32_t val;
+ MEMIF_READ_FUNC;
+}
+
+int32_t memif_t::read_int32(addr_t addr)
+{
+ int32_t val;
+ MEMIF_READ_FUNC;
+}
+
+void memif_t::write_uint32(addr_t addr, uint32_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+void memif_t::write_int32(addr_t addr, int32_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+uint64_t memif_t::read_uint64(addr_t addr)
+{
+ uint64_t val;
+ MEMIF_READ_FUNC;
+}
+
+int64_t memif_t::read_int64(addr_t addr)
+{
+ int64_t val;
+ MEMIF_READ_FUNC;
+}
+
+void memif_t::write_uint64(addr_t addr, uint64_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
+
+void memif_t::write_int64(addr_t addr, int64_t val)
+{
+ MEMIF_WRITE_FUNC;
+}
diff --git a/fesvr/memif.h b/fesvr/memif.h
new file mode 100644
index 0000000..3854d66
--- /dev/null
+++ b/fesvr/memif.h
@@ -0,0 +1,62 @@
+// See LICENSE for license details.
+
+#ifndef __MEMIF_H
+#define __MEMIF_H
+
+#include <stdint.h>
+#include <stddef.h>
+
+typedef uint64_t reg_t;
+typedef int64_t sreg_t;
+typedef reg_t addr_t;
+
+class chunked_memif_t
+{
+public:
+ virtual void read_chunk(addr_t taddr, size_t len, void* dst) = 0;
+ virtual void write_chunk(addr_t taddr, size_t len, const void* src) = 0;
+ virtual void clear_chunk(addr_t taddr, size_t len) = 0;
+
+ virtual size_t chunk_align() = 0;
+ virtual size_t chunk_max_size() = 0;
+};
+
+class memif_t
+{
+public:
+ memif_t(chunked_memif_t* _cmemif) : cmemif(_cmemif) {}
+ virtual ~memif_t(){}
+
+ // read and write byte arrays
+ virtual void read(addr_t addr, size_t len, void* bytes);
+ virtual void write(addr_t addr, size_t len, const void* bytes);
+
+ // read and write 8-bit words
+ virtual uint8_t read_uint8(addr_t addr);
+ virtual int8_t read_int8(addr_t addr);
+ virtual void write_uint8(addr_t addr, uint8_t val);
+ virtual void write_int8(addr_t addr, int8_t val);
+
+ // read and write 16-bit words
+ virtual uint16_t read_uint16(addr_t addr);
+ virtual int16_t read_int16(addr_t addr);
+ virtual void write_uint16(addr_t addr, uint16_t val);
+ virtual void write_int16(addr_t addr, int16_t val);
+
+ // read and write 32-bit words
+ virtual uint32_t read_uint32(addr_t addr);
+ virtual int32_t read_int32(addr_t addr);
+ virtual void write_uint32(addr_t addr, uint32_t val);
+ virtual void write_int32(addr_t addr, int32_t val);
+
+ // read and write 64-bit words
+ virtual uint64_t read_uint64(addr_t addr);
+ virtual int64_t read_int64(addr_t addr);
+ virtual void write_uint64(addr_t addr, uint64_t val);
+ virtual void write_int64(addr_t addr, int64_t val);
+
+protected:
+ chunked_memif_t* cmemif;
+};
+
+#endif // __MEMIF_H
diff --git a/fesvr/option_parser.cc b/fesvr/option_parser.cc
new file mode 100644
index 0000000..72daec4
--- /dev/null
+++ b/fesvr/option_parser.cc
@@ -0,0 +1,51 @@
+// See LICENSE for license details.
+
+#include "option_parser.h"
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <cassert>
+
+void option_parser_t::option(char c, const char* s, int arg, std::function<void(const char*)> action)
+{
+ opts.push_back(option_t(c, s, arg, action));
+}
+
+const char* const* option_parser_t::parse(const char* const* argv0)
+{
+ assert(argv0);
+ const char* const* argv = argv0 + 1;
+ for (const char* opt; (opt = *argv) != NULL && opt[0] == '-'; argv++)
+ {
+ bool found = false;
+ for (auto it = opts.begin(); !found && it != opts.end(); it++)
+ {
+ size_t slen = it->str ? strlen(it->str) : 0;
+ bool chr_match = opt[1] != '-' && it->chr && opt[1] == it->chr;
+ bool str_match = opt[1] == '-' && slen && strncmp(opt+2, it->str, slen) == 0;
+ if (chr_match || (str_match && (opt[2+slen] == '=' || opt[2+slen] == '\0')))
+ {
+ const char* optarg =
+ chr_match ? (opt[2] ? &opt[2] : NULL) :
+ opt[2+slen] ? &opt[3+slen] :
+ it->arg ? *(++argv) : NULL;
+ if (optarg && !it->arg)
+ error("no argument allowed for option", *argv0, opt);
+ if (!optarg && it->arg)
+ error("argument required for option", *argv0, opt);
+ it->func(optarg);
+ found = true;
+ }
+ }
+ if (!found)
+ error("unrecognized option", *argv0, opt);
+ }
+ return argv;
+}
+
+void option_parser_t::error(const char* msg, const char* argv0, const char* arg)
+{
+ fprintf(stderr, "%s: %s %s\n", argv0, msg, arg ? arg : "");
+ if (helpmsg) helpmsg();
+ exit(1);
+}
diff --git a/fesvr/option_parser.h b/fesvr/option_parser.h
new file mode 100644
index 0000000..b2cb8ed
--- /dev/null
+++ b/fesvr/option_parser.h
@@ -0,0 +1,31 @@
+// See LICENSE for license details.
+
+#ifndef _OPTION_PARSER_H
+#define _OPTION_PARSER_H
+
+#include <vector>
+#include <functional>
+
+class option_parser_t
+{
+ public:
+ option_parser_t() : helpmsg(0) {}
+ void help(void (*helpm)(void)) { helpmsg = helpm; }
+ void option(char c, const char* s, int arg, std::function<void(const char*)> action);
+ const char* const* parse(const char* const* argv0);
+ private:
+ struct option_t
+ {
+ char chr;
+ const char* str;
+ int arg;
+ std::function<void(const char*)> func;
+ option_t(char chr, const char* str, int arg, std::function<void(const char*)> func)
+ : chr(chr), str(str), arg(arg), func(func) {}
+ };
+ std::vector<option_t> opts;
+ void (*helpmsg)(void);
+ void error(const char* msg, const char* argv0, const char* arg);
+};
+
+#endif
diff --git a/fesvr/rfb.cc b/fesvr/rfb.cc
new file mode 100644
index 0000000..2594a1b
--- /dev/null
+++ b/fesvr/rfb.cc
@@ -0,0 +1,230 @@
+#include "rfb.h"
+#include "memif.h"
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sched.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <cstdlib>
+#include <stdexcept>
+#include <string>
+#include <cstring>
+#include <cinttypes>
+using namespace std::placeholders;
+
+rfb_t::rfb_t(int display)
+ : sockfd(-1), afd(-1),
+ memif(0), addr(0), width(0), height(0), bpp(0), display(display),
+ thread(pthread_self()), fb1(0), fb2(0), read_pos(0),
+ lock(PTHREAD_MUTEX_INITIALIZER)
+{
+ register_command(0, std::bind(&rfb_t::handle_configure, this, _1), "configure");
+ register_command(1, std::bind(&rfb_t::handle_set_address, this, _1), "set_address");
+}
+
+void* rfb_thread_main(void* arg)
+{
+ ((rfb_t*)arg)->thread_main();
+ return 0;
+}
+
+void rfb_t::thread_main()
+{
+ pthread_mutex_lock(&lock);
+
+ int port = 5900 + display;
+ sockfd = socket(PF_INET, SOCK_STREAM, 0);
+ if (sockfd < 0)
+ throw std::runtime_error("could not acquire tcp socket");
+
+ struct sockaddr_in saddr, caddr;
+ saddr.sin_family = AF_INET;
+ saddr.sin_addr.s_addr = INADDR_ANY;
+ saddr.sin_port = htons(port);
+ if (bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr)) < 0)
+ throw std::runtime_error("could not bind to port " + std::to_string(port));
+ if (listen(sockfd, 0) < 0)
+ throw std::runtime_error("could not listen on port " + std::to_string(port));
+
+ socklen_t clen = sizeof(caddr);
+ afd = accept(sockfd, (struct sockaddr*)&caddr, &clen);
+ if (afd < 0)
+ throw std::runtime_error("could not accept connection");
+
+ std::string version = "RFB 003.003\n";
+ write(version);
+ if (read() != version)
+ throw std::runtime_error("bad client version");
+
+ write(str(uint32_t(htonl(1))));
+
+ read(); // clientinit
+
+ std::string serverinit;
+ serverinit += str(uint16_t(htons(width)));
+ serverinit += str(uint16_t(htons(height)));
+ serverinit += pixel_format();
+ std::string name = "RISC-V";
+ serverinit += str(uint32_t(htonl(name.length())));
+ serverinit += name;
+ write(serverinit);
+
+ pthread_mutex_unlock(&lock);
+
+ while (memif == NULL)
+ sched_yield();
+
+ while (memif != NULL)
+ {
+ std::string s = read();
+ if (s.length() < 4)
+ break; //throw std::runtime_error("bad command");
+
+ switch (s[0])
+ {
+ case 0: set_pixel_format(s); break;
+ case 2: set_encodings(s); break;
+ case 3: break;
+ }
+ }
+
+ pthread_mutex_lock(&lock);
+ close(afd);
+ close(sockfd);
+ afd = -1;
+ sockfd = -1;
+ pthread_mutex_unlock(&lock);
+
+ thread_main();
+}
+
+rfb_t::~rfb_t()
+{
+ memif = 0;
+ if (!pthread_equal(pthread_self(), thread))
+ pthread_join(thread, 0);
+ delete [] fb1;
+ delete [] fb2;
+}
+
+void rfb_t::set_encodings(const std::string& s)
+{
+ uint16_t n = htons(*(uint16_t*)&s[2]);
+ for (size_t b = s.length(); b < 4U+4U*n; b += read().length());
+}
+
+void rfb_t::set_pixel_format(const std::string& s)
+{
+ if (s.length() != 20 || s.substr(4, 16) != pixel_format())
+ throw std::runtime_error("bad pixel format");
+}
+
+void rfb_t::fb_update(const std::string& s)
+{
+ std::string u;
+ u += str(uint8_t(0));
+ u += str(uint8_t(0));
+ u += str(uint16_t(htons(1)));
+ u += str(uint16_t(htons(0)));
+ u += str(uint16_t(htons(0)));
+ u += str(uint16_t(htons(width)));
+ u += str(uint16_t(htons(height)));
+ u += str(uint32_t(htonl(0)));
+ u += std::string((char*)fb1, fb_bytes());
+
+ try
+ {
+ write(u);
+ }
+ catch (std::runtime_error& e)
+ {
+ }
+}
+
+void rfb_t::tick()
+{
+ if (fb_bytes() == 0 || memif == NULL)
+ return;
+
+ memif->read(addr + read_pos, FB_ALIGN, const_cast<char*>(fb2 + read_pos));
+ read_pos = (read_pos + FB_ALIGN) % fb_bytes();
+ if (read_pos == 0)
+ {
+ std::swap(fb1, fb2);
+ if (pthread_mutex_trylock(&lock) == 0)
+ {
+ fb_update("");
+ pthread_mutex_unlock(&lock);
+ }
+ }
+}
+
+std::string rfb_t::pixel_format()
+{
+ int red_bits = 8, green_bits = 8, blue_bits = 8;
+ int bpp = red_bits + green_bits + blue_bits;
+ while (bpp & (bpp-1)) bpp++;
+
+ std::string fmt;
+ fmt += str(uint8_t(bpp));
+ fmt += str(uint8_t(red_bits + green_bits + blue_bits));
+ fmt += str(uint8_t(0)); // little-endian
+ fmt += str(uint8_t(1)); // true color
+ fmt += str(uint16_t(htons((1<<red_bits)-1)));
+ fmt += str(uint16_t(htons((1<<green_bits)-1)));
+ fmt += str(uint16_t(htons((1<<blue_bits)-1)));
+ fmt += str(uint8_t(blue_bits+green_bits));
+ fmt += str(uint8_t(blue_bits));
+ fmt += str(uint8_t(0));
+ fmt += str(uint16_t(0)); // pad
+ fmt += str(uint8_t(0)); // pad
+ return fmt;
+}
+
+void rfb_t::write(const std::string& s)
+{
+ if ((size_t)::write(afd, s.c_str(), s.length()) != s.length())
+ throw std::runtime_error("could not write");
+}
+
+std::string rfb_t::read()
+{
+ char buf[2048];
+ ssize_t len = ::read(afd, buf, sizeof(buf));
+ if (len < 0)
+ throw std::runtime_error("could not read");
+ if (len == sizeof(buf))
+ throw std::runtime_error("received oversized packet");
+ return std::string(buf, len);
+}
+
+void rfb_t::handle_configure(command_t cmd)
+{
+ if (fb1)
+ throw std::runtime_error("you must only set the rfb configuration once");
+
+ width = cmd.payload();
+ height = cmd.payload() >> 16;
+
+ bpp = cmd.payload() >> 32;
+ if (bpp != 32)
+ throw std::runtime_error("rfb requires 32 bpp true color");
+
+ if (fb_bytes() % FB_ALIGN != 0)
+ throw std::runtime_error("rfb size must be a multiple of " + std::to_string(FB_ALIGN));
+
+ fb1 = new char[fb_bytes()];
+ fb2 = new char[fb_bytes()];
+ if (pthread_create(&thread, 0, rfb_thread_main, this))
+ throw std::runtime_error("could not create thread");
+ cmd.respond(1);
+}
+
+void rfb_t::handle_set_address(command_t cmd)
+{
+ addr = cmd.payload();
+ if (addr % FB_ALIGN != 0)
+ throw std::runtime_error("rfb address must be " + std::to_string(FB_ALIGN) + "-byte aligned");
+ memif = &cmd.memif();
+ cmd.respond(1);
+}
diff --git a/fesvr/rfb.h b/fesvr/rfb.h
new file mode 100644
index 0000000..263663a
--- /dev/null
+++ b/fesvr/rfb.h
@@ -0,0 +1,53 @@
+#ifndef _RFB_H
+#define _RFB_H
+
+#include "device.h"
+#include "memif.h"
+#include <pthread.h>
+
+// remote frame buffer
+class rfb_t : public device_t
+{
+ public:
+ rfb_t(int display = 0);
+ ~rfb_t();
+ void tick();
+ std::string name() { return "RISC-V"; }
+ const char* identity() { return "rfb"; }
+
+ private:
+ template <typename T>
+ std::string str(T x)
+ {
+ return std::string((char*)&x, sizeof(x));
+ }
+ size_t fb_bytes() { return size_t(width) * height * bpp/8; }
+ void thread_main();
+ friend void* rfb_thread_main(void*);
+ std::string pixel_format();
+ void fb_update(const std::string& s);
+ void set_encodings(const std::string& s);
+ void set_pixel_format(const std::string& s);
+ void write(const std::string& s);
+ std::string read();
+ void handle_configure(command_t cmd);
+ void handle_set_address(command_t cmd);
+
+ int sockfd;
+ int afd;
+ memif_t* memif;
+ reg_t addr;
+ uint16_t width;
+ uint16_t height;
+ uint16_t bpp;
+ int display;
+ pthread_t thread;
+ volatile char* volatile fb1;
+ volatile char* volatile fb2;
+ size_t read_pos;
+ pthread_mutex_t lock;
+
+ static const int FB_ALIGN = 256;
+};
+
+#endif
diff --git a/fesvr/syscall.cc b/fesvr/syscall.cc
new file mode 100644
index 0000000..6e8baf6
--- /dev/null
+++ b/fesvr/syscall.cc
@@ -0,0 +1,394 @@
+// See LICENSE for license details.
+
+#include "syscall.h"
+#include "htif.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <termios.h>
+#include <sstream>
+#include <iostream>
+using namespace std::placeholders;
+
+#define RISCV_AT_FDCWD -100
+
+struct riscv_stat
+{
+ uint64_t dev;
+ uint64_t ino;
+ uint32_t mode;
+ uint32_t nlink;
+ uint32_t uid;
+ uint32_t gid;
+ uint64_t rdev;
+ uint64_t __pad1;
+ uint64_t size;
+ uint32_t blksize;
+ uint32_t __pad2;
+ uint64_t blocks;
+ uint64_t atime;
+ uint64_t __pad3;
+ uint64_t mtime;
+ uint64_t __pad4;
+ uint64_t ctime;
+ uint64_t __pad5;
+ uint32_t __unused4;
+ uint32_t __unused5;
+
+ riscv_stat(const struct stat& s)
+ : dev(s.st_dev), ino(s.st_ino), mode(s.st_mode), nlink(s.st_nlink),
+ uid(s.st_uid), gid(s.st_gid), rdev(s.st_rdev), __pad1(0),
+ size(s.st_size), blksize(s.st_blksize), __pad2(0),
+ blocks(s.st_blocks), atime(s.st_atime), __pad3(0),
+ mtime(s.st_mtime), __pad4(0), ctime(s.st_ctime), __pad5(0),
+ __unused4(0), __unused5(0) {}
+};
+
+syscall_t::syscall_t(htif_t* htif)
+ : htif(htif), memif(&htif->memif()), table(2048)
+{
+ table[17] = &syscall_t::sys_getcwd;
+ table[25] = &syscall_t::sys_fcntl;
+ table[34] = &syscall_t::sys_mkdirat;
+ table[35] = &syscall_t::sys_unlinkat;
+ table[37] = &syscall_t::sys_linkat;
+ table[38] = &syscall_t::sys_renameat;
+ table[46] = &syscall_t::sys_ftruncate;
+ table[48] = &syscall_t::sys_faccessat;
+ table[49] = &syscall_t::sys_chdir;
+ table[56] = &syscall_t::sys_openat;
+ table[57] = &syscall_t::sys_close;
+ table[62] = &syscall_t::sys_lseek;
+ table[63] = &syscall_t::sys_read;
+ table[64] = &syscall_t::sys_write;
+ table[67] = &syscall_t::sys_pread;
+ table[68] = &syscall_t::sys_pwrite;
+ table[79] = &syscall_t::sys_fstatat;
+ table[80] = &syscall_t::sys_fstat;
+ table[93] = &syscall_t::sys_exit;
+ table[1039] = &syscall_t::sys_lstat;
+ table[2011] = &syscall_t::sys_getmainvars;
+
+ register_command(0, std::bind(&syscall_t::handle_syscall, this, _1), "syscall");
+
+ int stdin_fd = dup(0), stdout_fd0 = dup(1), stdout_fd1 = dup(1);
+ if (stdin_fd < 0 || stdout_fd0 < 0 || stdout_fd1 < 0)
+ throw std::runtime_error("could not dup stdin/stdout");
+
+ fds.alloc(stdin_fd); // stdin -> stdin
+ fds.alloc(stdout_fd0); // stdout -> stdout
+ fds.alloc(stdout_fd1); // stderr -> stdout
+}
+
+std::string syscall_t::do_chroot(const char* fn)
+{
+ if (!chroot.empty() && *fn == '/')
+ return chroot + fn;
+ return fn;
+}
+
+std::string syscall_t::undo_chroot(const char* fn)
+{
+ if (chroot.empty())
+ return fn;
+ if (strncmp(fn, chroot.c_str(), chroot.size()) == 0
+ && (chroot.back() == '/' || fn[chroot.size()] == '/'))
+ return fn + chroot.size() - (chroot.back() == '/');
+ return "/";
+}
+
+void syscall_t::handle_syscall(command_t cmd)
+{
+ if (cmd.payload() & 1) // test pass/fail
+ {
+ htif->exitcode = cmd.payload();
+ if (htif->exit_code())
+ std::cerr << "*** FAILED *** (tohost = " << htif->exit_code() << ")" << std::endl;
+ return;
+ }
+ else // proxied system call
+ dispatch(cmd.payload());
+
+ cmd.respond(1);
+}
+
+reg_t syscall_t::sys_exit(reg_t code, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ htif->exitcode = code << 1 | 1;
+ return 0;
+}
+
+static reg_t sysret_errno(sreg_t ret)
+{
+ return ret == -1 ? -errno : ret;
+}
+
+reg_t syscall_t::sys_read(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> buf(len);
+ ssize_t ret = read(fds.lookup(fd), &buf[0], len);
+ reg_t ret_errno = sysret_errno(ret);
+ if (ret > 0)
+ memif->write(pbuf, ret, &buf[0]);
+ return ret_errno;
+}
+
+reg_t syscall_t::sys_pread(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> buf(len);
+ ssize_t ret = pread(fds.lookup(fd), &buf[0], len, off);
+ reg_t ret_errno = sysret_errno(ret);
+ if (ret > 0)
+ memif->write(pbuf, ret, &buf[0]);
+ return ret_errno;
+}
+
+reg_t syscall_t::sys_write(reg_t fd, reg_t pbuf, reg_t len, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> buf(len);
+ memif->read(pbuf, len, &buf[0]);
+ reg_t ret = sysret_errno(write(fds.lookup(fd), &buf[0], len));
+ return ret;
+}
+
+reg_t syscall_t::sys_pwrite(reg_t fd, reg_t pbuf, reg_t len, reg_t off, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> buf(len);
+ memif->read(pbuf, len, &buf[0]);
+ reg_t ret = sysret_errno(pwrite(fds.lookup(fd), &buf[0], len, off));
+ return ret;
+}
+
+reg_t syscall_t::sys_close(reg_t fd, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ if (close(fds.lookup(fd)) < 0)
+ return sysret_errno(-1);
+ fds.dealloc(fd);
+ return 0;
+}
+
+reg_t syscall_t::sys_lseek(reg_t fd, reg_t ptr, reg_t dir, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ return sysret_errno(lseek(fds.lookup(fd), ptr, dir));
+}
+
+reg_t syscall_t::sys_fstat(reg_t fd, reg_t pbuf, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ struct stat buf;
+ reg_t ret = sysret_errno(fstat(fds.lookup(fd), &buf));
+ if (ret != (reg_t)-1)
+ {
+ riscv_stat rbuf(buf);
+ memif->write(pbuf, sizeof(rbuf), &rbuf);
+ }
+ return ret;
+}
+
+reg_t syscall_t::sys_fcntl(reg_t fd, reg_t cmd, reg_t arg, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ return sysret_errno(fcntl(fds.lookup(fd), cmd, arg));
+}
+
+reg_t syscall_t::sys_ftruncate(reg_t fd, reg_t len, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ return sysret_errno(ftruncate(fds.lookup(fd), len));
+}
+
+reg_t syscall_t::sys_lstat(reg_t pname, reg_t len, reg_t pbuf, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+
+ struct stat buf;
+ reg_t ret = sysret_errno(lstat(do_chroot(&name[0]).c_str(), &buf));
+ riscv_stat rbuf(buf);
+ if (ret != (reg_t)-1)
+ {
+ riscv_stat rbuf(buf);
+ memif->write(pbuf, sizeof(rbuf), &rbuf);
+ }
+ return ret;
+}
+
+#define AT_SYSCALL(syscall, fd, name, ...) \
+ (syscall(fds.lookup(fd), int(fd) == RISCV_AT_FDCWD ? do_chroot(name).c_str() : (name), __VA_ARGS__))
+
+reg_t syscall_t::sys_openat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t mode, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+ int fd = sysret_errno(AT_SYSCALL(openat, dirfd, &name[0], flags, mode));
+ if (fd < 0)
+ return sysret_errno(-1);
+ return fds.alloc(fd);
+}
+
+reg_t syscall_t::sys_fstatat(reg_t dirfd, reg_t pname, reg_t len, reg_t pbuf, reg_t flags, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+
+ struct stat buf;
+ reg_t ret = sysret_errno(AT_SYSCALL(fstatat, dirfd, &name[0], &buf, flags));
+ if (ret != (reg_t)-1)
+ {
+ riscv_stat rbuf(buf);
+ memif->write(pbuf, sizeof(rbuf), &rbuf);
+ }
+ return ret;
+}
+
+reg_t syscall_t::sys_faccessat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+ return sysret_errno(AT_SYSCALL(faccessat, dirfd, &name[0], mode, 0));
+}
+
+reg_t syscall_t::sys_renameat(reg_t odirfd, reg_t popath, reg_t olen, reg_t ndirfd, reg_t pnpath, reg_t nlen, reg_t a6)
+{
+ std::vector<char> opath(olen), npath(nlen);
+ memif->read(popath, olen, &opath[0]);
+ memif->read(pnpath, nlen, &npath[0]);
+ return sysret_errno(renameat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(&opath[0]).c_str() : &opath[0],
+ fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(&npath[0]).c_str() : &npath[0]));
+}
+
+reg_t syscall_t::sys_linkat(reg_t odirfd, reg_t poname, reg_t olen, reg_t ndirfd, reg_t pnname, reg_t nlen, reg_t flags)
+{
+ std::vector<char> oname(olen), nname(nlen);
+ memif->read(poname, olen, &oname[0]);
+ memif->read(pnname, nlen, &nname[0]);
+ return sysret_errno(linkat(fds.lookup(odirfd), int(odirfd) == RISCV_AT_FDCWD ? do_chroot(&oname[0]).c_str() : &oname[0],
+ fds.lookup(ndirfd), int(ndirfd) == RISCV_AT_FDCWD ? do_chroot(&nname[0]).c_str() : &nname[0],
+ flags));
+}
+
+reg_t syscall_t::sys_unlinkat(reg_t dirfd, reg_t pname, reg_t len, reg_t flags, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+ return sysret_errno(AT_SYSCALL(unlinkat, dirfd, &name[0], flags));
+}
+
+reg_t syscall_t::sys_mkdirat(reg_t dirfd, reg_t pname, reg_t len, reg_t mode, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> name(len);
+ memif->read(pname, len, &name[0]);
+ return sysret_errno(AT_SYSCALL(mkdirat, dirfd, &name[0], mode));
+}
+
+reg_t syscall_t::sys_getcwd(reg_t pbuf, reg_t size, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<char> buf(size);
+ char* ret = getcwd(&buf[0], size);
+ if (ret == NULL)
+ return sysret_errno(-1);
+ std::string tmp = undo_chroot(&buf[0]);
+ if (size <= tmp.size())
+ return -ENOMEM;
+ memif->write(pbuf, tmp.size() + 1, &tmp[0]);
+ return tmp.size() + 1;
+}
+
+reg_t syscall_t::sys_getmainvars(reg_t pbuf, reg_t limit, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ std::vector<std::string> args = htif->target_args();
+ std::vector<uint64_t> words(args.size() + 3);
+ words[0] = args.size();
+ words[args.size()+1] = 0; // argv[argc] = NULL
+ words[args.size()+2] = 0; // envp[0] = NULL
+
+ size_t sz = (args.size() + 3) * sizeof(words[0]);
+ for (size_t i = 0; i < args.size(); i++)
+ {
+ words[i+1] = sz + pbuf;
+ sz += args[i].length() + 1;
+ }
+
+ std::vector<char> bytes(sz);
+ memcpy(&bytes[0], &words[0], sizeof(words[0]) * words.size());
+ for (size_t i = 0; i < args.size(); i++)
+ strcpy(&bytes[words[i+1] - pbuf], args[i].c_str());
+
+ if (bytes.size() > limit)
+ return -ENOMEM;
+
+ memif->write(pbuf, bytes.size(), &bytes[0]);
+ return 0;
+}
+
+reg_t syscall_t::sys_chdir(reg_t path, reg_t a1, reg_t a2, reg_t a3, reg_t a4, reg_t a5, reg_t a6)
+{
+ size_t size = 0;
+ while (memif->read_uint8(path + size++))
+ ;
+ std::vector<char> buf(size);
+ for (size_t offset = 0;; offset++)
+ {
+ buf[offset] = memif->read_uint8(path + offset);
+ if (!buf[offset])
+ break;
+ }
+ return sysret_errno(chdir(buf.data()));
+}
+
+void syscall_t::dispatch(reg_t mm)
+{
+ reg_t magicmem[8];
+ memif->read(mm, sizeof(magicmem), magicmem);
+
+ reg_t n = magicmem[0];
+ if (n >= table.size() || !table[n])
+ throw std::runtime_error("bad syscall #" + std::to_string(n));
+
+ magicmem[0] = (this->*table[n])(magicmem[1], magicmem[2], magicmem[3], magicmem[4], magicmem[5], magicmem[6], magicmem[7]);
+
+ memif->write(mm, sizeof(magicmem), magicmem);
+}
+
+reg_t fds_t::alloc(int fd)
+{
+ reg_t i;
+ for (i = 0; i < fds.size(); i++)
+ if (fds[i] == -1)
+ break;
+
+ if (i == fds.size())
+ fds.resize(i+1);
+
+ fds[i] = fd;
+ return i;
+}
+
+void fds_t::dealloc(reg_t fd)
+{
+ fds[fd] = -1;
+}
+
+int fds_t::lookup(reg_t fd)
+{
+ if (int(fd) == RISCV_AT_FDCWD)
+ return AT_FDCWD;
+ return fd >= fds.size() ? -1 : fds[fd];
+}
+
+void syscall_t::set_chroot(const char* where)
+{
+ char buf1[PATH_MAX], buf2[PATH_MAX];
+
+ if (getcwd(buf1, sizeof(buf1)) == NULL
+ || chdir(where) != 0
+ || getcwd(buf2, sizeof(buf2)) == NULL
+ || chdir(buf1) != 0)
+ {
+ fprintf(stderr, "could not chroot to %s\n", where);
+ exit(-1);
+ }
+
+ chroot = buf2;
+}
diff --git a/fesvr/syscall.h b/fesvr/syscall.h
new file mode 100644
index 0000000..8294696
--- /dev/null
+++ b/fesvr/syscall.h
@@ -0,0 +1,72 @@
+// See LICENSE for license details.
+
+#ifndef __SYSCALL_H
+#define __SYSCALL_H
+
+#include "device.h"
+#include "memif.h"
+#include <vector>
+#include <string>
+
+class syscall_t;
+typedef reg_t (syscall_t::*syscall_func_t)(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+
+class htif_t;
+class memif_t;
+
+class fds_t
+{
+ public:
+ reg_t alloc(int fd);
+ void dealloc(reg_t fd);
+ int lookup(reg_t fd);
+ private:
+ std::vector<int> fds;
+};
+
+class syscall_t : public device_t
+{
+ public:
+ syscall_t(htif_t*);
+
+ void set_chroot(const char* where);
+
+ private:
+ const char* identity() { return "syscall_proxy"; }
+
+ htif_t* htif;
+ memif_t* memif;
+ std::vector<syscall_func_t> table;
+ fds_t fds;
+
+ void handle_syscall(command_t cmd);
+ void dispatch(addr_t mm);
+
+ std::string chroot;
+ std::string do_chroot(const char* fn);
+ std::string undo_chroot(const char* fn);
+
+ reg_t sys_exit(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_openat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_read(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_pread(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_write(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_pwrite(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_close(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_lseek(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_fstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_lstat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_fstatat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_faccessat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_fcntl(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_ftruncate(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_renameat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_linkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_unlinkat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_mkdirat(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_getcwd(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_getmainvars(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+ reg_t sys_chdir(reg_t, reg_t, reg_t, reg_t, reg_t, reg_t, reg_t);
+};
+
+#endif
diff --git a/fesvr/term.cc b/fesvr/term.cc
new file mode 100644
index 0000000..c4cba0c
--- /dev/null
+++ b/fesvr/term.cc
@@ -0,0 +1,53 @@
+#include "term.h"
+#include <termios.h>
+#include <unistd.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+
+class canonical_termios_t
+{
+ public:
+ canonical_termios_t()
+ : restore_tios(false)
+ {
+ if (tcgetattr(0, &old_tios) == 0)
+ {
+ struct termios new_tios = old_tios;
+ new_tios.c_lflag &= ~(ICANON | ECHO);
+ if (tcsetattr(0, TCSANOW, &new_tios) == 0)
+ restore_tios = true;
+ }
+ }
+
+ ~canonical_termios_t()
+ {
+ if (restore_tios)
+ tcsetattr(0, TCSANOW, &old_tios);
+ }
+ private:
+ struct termios old_tios;
+ bool restore_tios;
+};
+
+static canonical_termios_t tios; // exit() will clean up for us
+
+int canonical_terminal_t::read()
+{
+ struct pollfd pfd;
+ pfd.fd = 0;
+ pfd.events = POLLIN;
+ int ret = poll(&pfd, 1, 0);
+ if (ret <= 0 || !(pfd.revents & POLLIN))
+ return -1;
+
+ unsigned char ch;
+ ret = ::read(0, &ch, 1);
+ return ret <= 0 ? -1 : ch;
+}
+
+void canonical_terminal_t::write(char ch)
+{
+ if (::write(1, &ch, 1) != 1)
+ abort();
+}
diff --git a/fesvr/term.h b/fesvr/term.h
new file mode 100644
index 0000000..7a2c22f
--- /dev/null
+++ b/fesvr/term.h
@@ -0,0 +1,11 @@
+#ifndef _TERM_H
+#define _TERM_H
+
+class canonical_terminal_t
+{
+ public:
+ static int read();
+ static void write(char);
+};
+
+#endif
diff --git a/fesvr/tsi.cc b/fesvr/tsi.cc
new file mode 100644
index 0000000..5ccafc4
--- /dev/null
+++ b/fesvr/tsi.cc
@@ -0,0 +1,115 @@
+#include "tsi.h"
+#include <cstdio>
+#include <cstdlib>
+
+#define NHARTS_MAX 16
+
+void tsi_t::host_thread(void *arg)
+{
+ tsi_t *tsi = static_cast<tsi_t*>(arg);
+ tsi->run();
+
+ while (true)
+ tsi->target->switch_to();
+}
+
+tsi_t::tsi_t(int argc, char** argv) : htif_t(argc, argv)
+{
+ target = context_t::current();
+ host.init(host_thread, this);
+}
+
+tsi_t::~tsi_t(void)
+{
+}
+
+#define MSIP_BASE 0x2000000
+
+// Interrupt core 0 to make it start executing the program in DRAM
+void tsi_t::reset()
+{
+ uint32_t one = 1;
+
+ write_chunk(MSIP_BASE, sizeof(uint32_t), &one);
+}
+
+void tsi_t::push_addr(addr_t addr)
+{
+ for (int i = 0; i < SAI_ADDR_CHUNKS; i++) {
+ in_data.push_back(addr & 0xffffffff);
+ addr = addr >> 32;
+ }
+}
+
+void tsi_t::push_len(addr_t len)
+{
+ for (int i = 0; i < SAI_LEN_CHUNKS; i++) {
+ in_data.push_back(len & 0xffffffff);
+ len = len >> 32;
+ }
+}
+
+void tsi_t::read_chunk(addr_t taddr, size_t nbytes, void* dst)
+{
+ uint32_t *result = static_cast<uint32_t*>(dst);
+ size_t len = nbytes / sizeof(uint32_t);
+
+ in_data.push_back(SAI_CMD_READ);
+ push_addr(taddr);
+ push_len(len - 1);
+
+ for (size_t i = 0; i < len; i++) {
+ while (out_data.empty())
+ switch_to_target();
+ result[i] = out_data.front();
+ out_data.pop_front();
+ }
+}
+
+void tsi_t::write_chunk(addr_t taddr, size_t nbytes, const void* src)
+{
+ const uint32_t *src_data = static_cast<const uint32_t*>(src);
+ size_t len = nbytes / sizeof(uint32_t);
+
+ in_data.push_back(SAI_CMD_WRITE);
+ push_addr(taddr);
+ push_len(len - 1);
+
+ in_data.insert(in_data.end(), src_data, src_data + len);
+}
+
+void tsi_t::send_word(uint32_t word)
+{
+ out_data.push_back(word);
+}
+
+uint32_t tsi_t::recv_word(void)
+{
+ uint32_t word = in_data.front();
+ in_data.pop_front();
+ return word;
+}
+
+bool tsi_t::data_available(void)
+{
+ return !in_data.empty();
+}
+
+void tsi_t::switch_to_host(void)
+{
+ host.switch_to();
+}
+
+void tsi_t::switch_to_target(void)
+{
+ target->switch_to();
+}
+
+void tsi_t::tick(bool out_valid, uint32_t out_bits, bool in_ready)
+{
+ if (out_valid && out_ready())
+ out_data.push_back(out_bits);
+
+ if (in_valid() && in_ready)
+ in_data.pop_front();
+}
diff --git a/fesvr/tsi.h b/fesvr/tsi.h
new file mode 100644
index 0000000..cd47811
--- /dev/null
+++ b/fesvr/tsi.h
@@ -0,0 +1,57 @@
+#ifndef __SAI_H
+#define __SAI_H
+
+#include "htif.h"
+#include "context.h"
+
+#include <string>
+#include <vector>
+#include <deque>
+#include <stdint.h>
+
+#define SAI_CMD_READ 0
+#define SAI_CMD_WRITE 1
+
+#define SAI_ADDR_CHUNKS 2
+#define SAI_LEN_CHUNKS 2
+
+class tsi_t : public htif_t
+{
+ public:
+ tsi_t(int argc, char** argv);
+ virtual ~tsi_t();
+
+ bool data_available();
+ void send_word(uint32_t word);
+ uint32_t recv_word();
+ void switch_to_host();
+
+ uint32_t in_bits() { return in_data.front(); }
+ bool in_valid() { return !in_data.empty(); }
+ bool out_ready() { return true; }
+ void tick(bool out_valid, uint32_t out_bits, bool in_ready);
+
+ protected:
+ void reset() override;
+ void read_chunk(addr_t taddr, size_t nbytes, void* dst) override;
+ void write_chunk(addr_t taddr, size_t nbytes, const void* src) override;
+ void switch_to_target();
+
+ size_t chunk_align() { return 4; }
+ size_t chunk_max_size() { return 1024; }
+
+ int get_ipi_addrs(addr_t *addrs);
+
+ private:
+ context_t host;
+ context_t* target;
+ std::deque<uint32_t> in_data;
+ std::deque<uint32_t> out_data;
+
+ void push_addr(addr_t addr);
+ void push_len(addr_t len);
+
+ static void host_thread(void *tsi);
+};
+
+#endif