diff options
author | Andrew Waterman <andrew@sifive.com> | 2019-03-31 00:49:57 -0700 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2019-03-31 00:50:15 -0700 |
commit | f49618ca9d674ec7e596118f85027c4b503862ac (patch) | |
tree | 3b6ad73cbe8760309f930b743950a2853ad17668 /fesvr | |
parent | 61cb96df00067ba61cf3816c74c18aef5677197a (diff) | |
download | spike-f49618ca9d674ec7e596118f85027c4b503862ac.zip spike-f49618ca9d674ec7e596118f85027c4b503862ac.tar.gz spike-f49618ca9d674ec7e596118f85027c4b503862ac.tar.bz2 |
Add fesvr; only globally install fesvr headers/libsstatic-link
Diffstat (limited to 'fesvr')
-rw-r--r-- | fesvr/context.cc | 115 | ||||
-rw-r--r-- | fesvr/context.h | 54 | ||||
-rw-r--r-- | fesvr/debug_defines.h | 1418 | ||||
-rw-r--r-- | fesvr/device.cc | 155 | ||||
-rw-r--r-- | fesvr/device.h | 118 | ||||
-rw-r--r-- | fesvr/dtm.cc | 642 | ||||
-rw-r--r-- | fesvr/dtm.h | 115 | ||||
-rw-r--r-- | fesvr/dummy.cc | 4 | ||||
-rw-r--r-- | fesvr/elf.h | 121 | ||||
-rw-r--r-- | fesvr/elf2hex.cc | 47 | ||||
-rw-r--r-- | fesvr/elfloader.cc | 89 | ||||
-rw-r--r-- | fesvr/elfloader.h | 13 | ||||
-rw-r--r-- | fesvr/encoding.h | 1471 | ||||
-rw-r--r-- | fesvr/fesvr.ac | 1 | ||||
-rw-r--r-- | fesvr/fesvr.mk.in | 38 | ||||
-rw-r--r-- | fesvr/fesvr.pc.in | 26 | ||||
-rw-r--r-- | fesvr/htif.cc | 329 | ||||
-rw-r--r-- | fesvr/htif.h | 114 | ||||
-rw-r--r-- | fesvr/htif_hexwriter.cc | 76 | ||||
-rw-r--r-- | fesvr/htif_hexwriter.h | 32 | ||||
-rw-r--r-- | fesvr/htif_pthread.cc | 66 | ||||
-rw-r--r-- | fesvr/htif_pthread.h | 38 | ||||
-rw-r--r-- | fesvr/memif.cc | 183 | ||||
-rw-r--r-- | fesvr/memif.h | 62 | ||||
-rw-r--r-- | fesvr/option_parser.cc | 51 | ||||
-rw-r--r-- | fesvr/option_parser.h | 31 | ||||
-rw-r--r-- | fesvr/rfb.cc | 230 | ||||
-rw-r--r-- | fesvr/rfb.h | 53 | ||||
-rw-r--r-- | fesvr/syscall.cc | 394 | ||||
-rw-r--r-- | fesvr/syscall.h | 72 | ||||
-rw-r--r-- | fesvr/term.cc | 53 | ||||
-rw-r--r-- | fesvr/term.h | 11 | ||||
-rw-r--r-- | fesvr/tsi.cc | 115 | ||||
-rw-r--r-- | fesvr/tsi.h | 57 |
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 |