aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--riscv/decode.h2
-rw-r--r--riscv/encoding.h27
-rw-r--r--riscv/execute.cc117
-rw-r--r--riscv/insns/c_add.h13
-rw-r--r--riscv/insns/c_addi16sp.h3
-rw-r--r--riscv/insns/c_addiw.h1
-rw-r--r--riscv/insns/c_ebreak.h2
-rw-r--r--riscv/insns/c_jalr.h5
-rw-r--r--riscv/insns/c_jr.h3
-rw-r--r--riscv/insns/c_lui.h7
-rw-r--r--riscv/insns/c_mv.h8
-rw-r--r--riscv/mmu.h30
-rw-r--r--riscv/processor.cc198
-rw-r--r--riscv/processor.h10
-rw-r--r--riscv/riscv.mk.in201
15 files changed, 438 insertions, 189 deletions
diff --git a/riscv/decode.h b/riscv/decode.h
index 16e57d7..8462da2 100644
--- a/riscv/decode.h
+++ b/riscv/decode.h
@@ -53,6 +53,8 @@ const int NFPR = 32;
((x) & 0x1f) < 0x1f ? 4 : \
((x) & 0x3f) < 0x3f ? 6 : \
8)
+#define MAX_INSN_LENGTH 8
+#define PC_ALIGN 2
typedef uint64_t insn_bits_t;
class insn_t
diff --git a/riscv/encoding.h b/riscv/encoding.h
index 039ffdf..16a7792 100644
--- a/riscv/encoding.h
+++ b/riscv/encoding.h
@@ -225,6 +225,8 @@
#define MASK_C_ADD 0xf003
#define MATCH_C_ADDI 0xc002
#define MASK_C_ADDI 0xe003
+#define MATCH_C_ADDI16SP 0xa002
+#define MASK_C_ADDI16SP 0xef83
#define MATCH_C_ADDI4SPN 0x8000
#define MASK_C_ADDI4SPN 0xe003
#define MATCH_C_ADDIW 0xe002
@@ -235,6 +237,8 @@
#define MASK_C_BEQZ 0xe003
#define MATCH_C_BNEZ 0x6002
#define MASK_C_BNEZ 0xe003
+#define MATCH_C_EBREAK 0x1000
+#define MASK_C_EBREAK 0xffff
#define MATCH_C_FLD 0xa000
#define MASK_C_FLD 0xe003
#define MATCH_C_FLDSP 0xa001
@@ -255,6 +259,14 @@
#define MASK_C_J 0xe003
#define MATCH_C_JAL 0x2002
#define MASK_C_JAL 0xe003
+#define MATCH_C_JALR 0x1000
+#define MASK_C_JALR 0xf07f
+#define MATCH_C_JR 0x0
+#define MASK_C_JR 0xf07f
+#define MATCH_C_LD 0xe000
+#define MASK_C_LD 0xe003
+#define MATCH_C_LDSP 0xe001
+#define MASK_C_LDSP 0xe003
#define MATCH_C_LI 0x8002
#define MASK_C_LI 0xe003
#define MATCH_C_LUI 0xa002
@@ -265,6 +277,12 @@
#define MASK_C_LWSP 0xe003
#define MATCH_C_MV 0x0
#define MASK_C_MV 0xf003
+#define MATCH_C_NOP 0xc002
+#define MASK_C_NOP 0xffff
+#define MATCH_C_SD 0x6000
+#define MASK_C_SD 0xe003
+#define MATCH_C_SDSP 0x6001
+#define MASK_C_SDSP 0xe003
#define MATCH_C_SLLI 0x1
#define MASK_C_SLLI 0xe003
#define MATCH_C_SW 0x4000
@@ -646,11 +664,13 @@ DECLARE_INSN(bltu, MATCH_BLTU, MASK_BLTU)
DECLARE_INSN(bne, MATCH_BNE, MASK_BNE)
DECLARE_INSN(c_add, MATCH_C_ADD, MASK_C_ADD)
DECLARE_INSN(c_addi, MATCH_C_ADDI, MASK_C_ADDI)
+DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP)
DECLARE_INSN(c_addi4spn, MATCH_C_ADDI4SPN, MASK_C_ADDI4SPN)
DECLARE_INSN(c_addiw, MATCH_C_ADDIW, MASK_C_ADDIW)
DECLARE_INSN(c_addw, MATCH_C_ADDW, MASK_C_ADDW)
DECLARE_INSN(c_beqz, MATCH_C_BEQZ, MASK_C_BEQZ)
DECLARE_INSN(c_bnez, MATCH_C_BNEZ, MASK_C_BNEZ)
+DECLARE_INSN(c_ebreak, MATCH_C_EBREAK, MASK_C_EBREAK)
DECLARE_INSN(c_fld, MATCH_C_FLD, MASK_C_FLD)
DECLARE_INSN(c_fldsp, MATCH_C_FLDSP, MASK_C_FLDSP)
DECLARE_INSN(c_flw, MATCH_C_FLW, MASK_C_FLW)
@@ -661,11 +681,18 @@ DECLARE_INSN(c_fsw, MATCH_C_FSW, MASK_C_FSW)
DECLARE_INSN(c_fswsp, MATCH_C_FSWSP, MASK_C_FSWSP)
DECLARE_INSN(c_j, MATCH_C_J, MASK_C_J)
DECLARE_INSN(c_jal, MATCH_C_JAL, MASK_C_JAL)
+DECLARE_INSN(c_jalr, MATCH_C_JALR, MASK_C_JALR)
+DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR)
+DECLARE_INSN(c_ld, MATCH_C_LD, MASK_C_LD)
+DECLARE_INSN(c_ldsp, MATCH_C_LDSP, MASK_C_LDSP)
DECLARE_INSN(c_li, MATCH_C_LI, MASK_C_LI)
DECLARE_INSN(c_lui, MATCH_C_LUI, MASK_C_LUI)
DECLARE_INSN(c_lw, MATCH_C_LW, MASK_C_LW)
DECLARE_INSN(c_lwsp, MATCH_C_LWSP, MASK_C_LWSP)
DECLARE_INSN(c_mv, MATCH_C_MV, MASK_C_MV)
+DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP)
+DECLARE_INSN(c_sd, MATCH_C_SD, MASK_C_SD)
+DECLARE_INSN(c_sdsp, MATCH_C_SDSP, MASK_C_SDSP)
DECLARE_INSN(c_slli, MATCH_C_SLLI, MASK_C_SLLI)
DECLARE_INSN(c_sw, MATCH_C_SW, MASK_C_SW)
DECLARE_INSN(c_swsp, MATCH_C_SWSP, MASK_C_SWSP)
diff --git a/riscv/execute.cc b/riscv/execute.cc
new file mode 100644
index 0000000..bb7ed34
--- /dev/null
+++ b/riscv/execute.cc
@@ -0,0 +1,117 @@
+// See LICENSE for license details.
+
+#include "processor.h"
+#include "mmu.h"
+#include <cassert>
+
+static void commit_log(state_t* state, reg_t pc, insn_t insn)
+{
+#ifdef RISCV_ENABLE_COMMITLOG
+ if (get_field(state->mstatus, MSTATUS_IE)) {
+ uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
+ if (state->log_reg_write.addr) {
+ fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
+ pc,
+ insn.bits() & mask,
+ state->log_reg_write.addr & 1 ? 'f' : 'x',
+ state->log_reg_write.addr >> 1,
+ state->log_reg_write.data);
+ } else {
+ fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n", pc, insn.bits() & mask);
+ }
+ }
+ state->log_reg_write.addr = 0;
+#endif
+}
+
+inline void processor_t::update_histogram(size_t pc)
+{
+#ifdef RISCV_ENABLE_HISTOGRAM
+ size_t idx = pc >> 2;
+ pc_histogram[idx]++;
+#endif
+}
+
+static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
+{
+ reg_t npc = fetch.func(p, fetch.insn, pc);
+ if (npc != PC_SERIALIZE) {
+ commit_log(p->get_state(), pc, fetch.insn);
+ p->update_histogram(pc);
+ }
+ return npc;
+}
+
+// fetch/decode/execute loop
+void processor_t::step(size_t n)
+{
+ while (run && n > 0) {
+ size_t instret = 0;
+ reg_t pc = state.pc;
+ mmu_t* _mmu = mmu;
+
+ #define advance_pc() \
+ if (unlikely(pc == PC_SERIALIZE)) { \
+ pc = state.pc; \
+ state.serialized = true; \
+ break; \
+ } else { \
+ state.pc = pc; \
+ instret++; \
+ }
+
+ try
+ {
+ check_timer();
+ take_interrupt();
+
+ if (unlikely(debug))
+ {
+ while (instret < n)
+ {
+ insn_fetch_t fetch = mmu->load_insn(pc);
+ if (!state.serialized)
+ disasm(fetch.insn);
+ pc = execute_insn(this, pc, fetch);
+ advance_pc();
+ }
+ }
+ else while (instret < n)
+ {
+ size_t idx = _mmu->icache_index(pc);
+ auto ic_entry = _mmu->access_icache(pc);
+
+ #define ICACHE_ACCESS(i) { \
+ insn_fetch_t fetch = ic_entry->data; \
+ ic_entry++; \
+ pc = execute_insn(this, pc, fetch); \
+ if (i == mmu_t::ICACHE_ENTRIES-1) break; \
+ if (unlikely(ic_entry->tag != pc)) goto miss; \
+ if (unlikely(instret+1 == n)) break; \
+ instret++; \
+ state.pc = pc; \
+ }
+
+ switch (idx) {
+ #include "icache.h"
+ }
+
+ advance_pc();
+ continue;
+
+miss:
+ advance_pc();
+ // refill I$ if it looks like there wasn't a taken branch
+ if (pc > (ic_entry-1)->tag && pc <= (ic_entry-1)->tag + MAX_INSN_LENGTH)
+ _mmu->refill_icache(pc, ic_entry);
+ }
+ }
+ catch(trap_t& t)
+ {
+ take_trap(t, pc);
+ }
+
+ state.minstret += instret;
+ n -= instret;
+ }
+}
diff --git a/riscv/insns/c_add.h b/riscv/insns/c_add.h
index c13385e..ab7d4d4 100644
--- a/riscv/insns/c_add.h
+++ b/riscv/insns/c_add.h
@@ -1,12 +1,3 @@
require_extension('C');
-if (insn.rvc_rs2() == 0) {
- if (insn.rvc_rs1() == 0) { // c.ebreak
- throw trap_breakpoint();
- } else { // c.jalr
- reg_t tmp = npc;
- set_pc(RVC_RS1 & ~reg_t(1));
- WRITE_REG(X_RA, tmp);
- }
-} else {
- WRITE_RD(sext_xlen(RVC_RS1 + RVC_RS2));
-}
+require(insn.rvc_rs2() != 0);
+WRITE_RD(sext_xlen(RVC_RS1 + RVC_RS2));
diff --git a/riscv/insns/c_addi16sp.h b/riscv/insns/c_addi16sp.h
new file mode 100644
index 0000000..3bc88a4
--- /dev/null
+++ b/riscv/insns/c_addi16sp.h
@@ -0,0 +1,3 @@
+require_extension('C');
+require(insn.rvc_addi16sp_imm() != 0);
+WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
diff --git a/riscv/insns/c_addiw.h b/riscv/insns/c_addiw.h
index fe87872..05d3497 100644
--- a/riscv/insns/c_addiw.h
+++ b/riscv/insns/c_addiw.h
@@ -1,2 +1,3 @@
require_extension('C');
+require_rv64;
WRITE_RD(sext32(RVC_RS1 + insn.rvc_imm()));
diff --git a/riscv/insns/c_ebreak.h b/riscv/insns/c_ebreak.h
new file mode 100644
index 0000000..a17200f
--- /dev/null
+++ b/riscv/insns/c_ebreak.h
@@ -0,0 +1,2 @@
+require_extension('C');
+throw trap_breakpoint();
diff --git a/riscv/insns/c_jalr.h b/riscv/insns/c_jalr.h
new file mode 100644
index 0000000..cb1e422
--- /dev/null
+++ b/riscv/insns/c_jalr.h
@@ -0,0 +1,5 @@
+require_extension('C');
+require(insn.rvc_rs1() != 0);
+reg_t tmp = npc;
+set_pc(RVC_RS1 & ~reg_t(1));
+WRITE_REG(X_RA, tmp);
diff --git a/riscv/insns/c_jr.h b/riscv/insns/c_jr.h
new file mode 100644
index 0000000..9c4a8ea
--- /dev/null
+++ b/riscv/insns/c_jr.h
@@ -0,0 +1,3 @@
+require_extension('C');
+require(insn.rvc_rs1() != 0);
+set_pc(RVC_RS1 & ~reg_t(1));
diff --git a/riscv/insns/c_lui.h b/riscv/insns/c_lui.h
index cb76c61..e5060a3 100644
--- a/riscv/insns/c_lui.h
+++ b/riscv/insns/c_lui.h
@@ -1,6 +1,3 @@
require_extension('C');
-if (insn.rvc_rd() == 0) { // c.addi16sp
- WRITE_REG(X_SP, sext_xlen(RVC_SP + insn.rvc_addi16sp_imm()));
-} else {
- WRITE_RD(insn.rvc_imm() << 12);
-}
+require(insn.rvc_rd() != 0);
+WRITE_RD(insn.rvc_imm() << 12);
diff --git a/riscv/insns/c_mv.h b/riscv/insns/c_mv.h
index 4a23063..a03d0d0 100644
--- a/riscv/insns/c_mv.h
+++ b/riscv/insns/c_mv.h
@@ -1,7 +1,3 @@
require_extension('C');
-if (insn.rvc_rs2() == 0) {
- require(insn.rvc_rd() != 0);
- set_pc(RVC_RS1 & ~reg_t(1));
-} else {
- WRITE_RD(RVC_RS2);
-}
+require(insn.rvc_rs2() != 0);
+WRITE_RD(RVC_RS2);
diff --git a/riscv/mmu.h b/riscv/mmu.h
index ddb1d51..ce8685d 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -72,18 +72,11 @@ public:
inline size_t icache_index(reg_t addr)
{
- // for instruction sizes != 4, this hash still works but is suboptimal
- return (addr / 4) % ICACHE_ENTRIES;
+ return (addr / PC_ALIGN) % ICACHE_ENTRIES;
}
- // load instruction from memory at aligned address.
- icache_entry_t* access_icache(reg_t addr) __attribute__((always_inline))
+ inline icache_entry_t* refill_icache(reg_t addr, icache_entry_t* entry)
{
- reg_t idx = icache_index(addr);
- icache_entry_t* entry = &icache[idx];
- if (likely(entry->tag == addr))
- return entry;
-
char* iaddr = (char*)translate(addr, 1, false, true);
insn_bits_t insn = *(uint16_t*)iaddr;
int length = insn_length(insn);
@@ -106,16 +99,23 @@ public:
}
insn_fetch_t fetch = {proc->decode_insn(insn), insn};
- icache[idx].tag = addr;
- icache[idx].data = fetch;
+ entry->tag = addr;
+ entry->data = fetch;
reg_t paddr = iaddr - mem;
- if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + 1, false, true))
- {
- icache[idx].tag = -1;
+ if (tracer.interested_in_range(paddr, paddr + 1, false, true)) {
+ entry->tag = -1;
tracer.trace(paddr, length, false, true);
}
- return &icache[idx];
+ return entry;
+ }
+
+ inline icache_entry_t* access_icache(reg_t addr)
+ {
+ icache_entry_t* entry = &icache[icache_index(addr)];
+ if (likely(entry->tag == addr))
+ return entry;
+ return refill_icache(addr, entry);
}
inline insn_fetch_t load_insn(reg_t addr)
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 5b53391..d1e7ce3 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -30,10 +30,7 @@ processor_t::processor_t(const char* isa, sim_t* sim, uint32_t id)
reset(true);
- #define DECLARE_INSN(name, match, mask) REGISTER_INSN(this, name, match, mask)
- #include "encoding.h"
- #undef DECLARE_INSN
- build_opcode_map();
+ register_base_instructions();
}
processor_t::~processor_t()
@@ -173,121 +170,12 @@ void processor_t::take_interrupt()
}
}
-static void commit_log(state_t* state, reg_t pc, insn_t insn)
-{
-#ifdef RISCV_ENABLE_COMMITLOG
- if (get_field(state->mstatus, MSTATUS_IE)) {
- uint64_t mask = (insn.length() == 8 ? uint64_t(0) : (uint64_t(1) << (insn.length() * 8))) - 1;
- if (state->log_reg_write.addr) {
- fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2" PRIu64 " 0x%016" PRIx64 "\n",
- pc,
- insn.bits() & mask,
- state->log_reg_write.addr & 1 ? 'f' : 'x',
- state->log_reg_write.addr >> 1,
- state->log_reg_write.data);
- } else {
- fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n", pc, insn.bits() & mask);
- }
- }
- state->log_reg_write.addr = 0;
-#endif
-}
-
-inline void processor_t::update_histogram(size_t pc)
-{
-#ifdef RISCV_ENABLE_HISTOGRAM
- size_t idx = pc >> 2;
- pc_histogram[idx]++;
-#endif
-}
-
-static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
-{
- reg_t npc = fetch.func(p, fetch.insn, pc);
- if (npc != PC_SERIALIZE) {
- commit_log(p->get_state(), pc, fetch.insn);
- p->update_histogram(pc);
- }
- return npc;
-}
-
void processor_t::check_timer()
{
if (sim->rtc >= state.mtimecmp)
state.mip |= MIP_MTIP;
}
-void processor_t::step(size_t n)
-{
- size_t instret = 0;
- reg_t pc = state.pc;
- mmu_t* _mmu = mmu;
-
- if (unlikely(!run || !n))
- return;
-
- #define maybe_serialize() \
- if (unlikely(pc == PC_SERIALIZE)) { \
- pc = state.pc; \
- state.serialized = true; \
- break; \
- }
-
- try
- {
- check_timer();
- take_interrupt();
-
- if (unlikely(debug))
- {
- while (instret < n)
- {
- insn_fetch_t fetch = mmu->load_insn(pc);
- if (!state.serialized)
- disasm(fetch.insn);
- pc = execute_insn(this, pc, fetch);
- maybe_serialize();
- instret++;
- state.pc = pc;
- }
- }
- else while (instret < n)
- {
- size_t idx = _mmu->icache_index(pc);
- auto ic_entry = _mmu->access_icache(pc);
-
- #define ICACHE_ACCESS(idx) { \
- insn_fetch_t fetch = ic_entry->data; \
- ic_entry++; \
- pc = execute_insn(this, pc, fetch); \
- if (idx == mmu_t::ICACHE_ENTRIES-1) break; \
- if (unlikely(ic_entry->tag != pc)) break; \
- if (unlikely(instret+1 == n)) break; \
- instret++; \
- state.pc = pc; \
- }
-
- switch (idx) {
- #include "icache.h"
- }
-
- maybe_serialize();
- instret++;
- state.pc = pc;
- }
- }
- catch(trap_t& t)
- {
- take_trap(t, pc);
- }
-
- state.minstret += instret;
-
- // tail-recurse if we didn't execute as many instructions as we'd hoped
- if (instret < n)
- step(n - instret);
-}
-
void processor_t::push_privilege_stack()
{
reg_t s = state.mstatus;
@@ -463,7 +351,7 @@ void processor_t::set_csr(int which, reg_t val)
break;
}
case CSR_SEPC: state.sepc = val; break;
- case CSR_STVEC: state.stvec = val & ~3; break;
+ case CSR_STVEC: state.stvec = val >> 2 << 2; break;
case CSR_SPTBR: state.sptbr = zext_xlen(val & -PGSIZE); break;
case CSR_SSCRATCH: state.sscratch = val; break;
case CSR_MEPC: state.mepc = val; break;
@@ -602,55 +490,51 @@ reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc)
insn_func_t processor_t::decode_insn(insn_t insn)
{
- size_t mask = opcode_map.size()-1;
- insn_desc_t* desc = opcode_map[insn.bits() & mask];
+ // look up opcode in hash table
+ size_t idx = insn.bits() % OPCODE_CACHE_SIZE;
+ insn_desc_t desc = opcode_cache[idx];
+
+ if (unlikely(insn.bits() != desc.match)) {
+ // fall back to linear search
+ insn_desc_t* p = &instructions[0];
+ while ((insn.bits() & p->mask) != p->match)
+ p++;
+ desc = *p;
+
+ if (p->mask != 0 && p > &instructions[0]) {
+ if (p->match != (p-1)->match && p->match != (p+1)->match) {
+ // move to front of opcode list to reduce miss penalty
+ while (--p >= &instructions[0])
+ *(p+1) = *p;
+ instructions[0] = desc;
+ }
+ }
- while ((insn.bits() & desc->mask) != desc->match)
- desc++;
+ opcode_cache[idx] = desc;
+ opcode_cache[idx].match = insn.bits();
+ }
- return xlen == 64 ? desc->rv64 : desc->rv32;
+ return xlen == 64 ? desc.rv64 : desc.rv32;
}
void processor_t::register_insn(insn_desc_t desc)
{
- assert(desc.mask & 1);
instructions.push_back(desc);
}
void processor_t::build_opcode_map()
{
- size_t buckets = -1;
- for (auto& inst : instructions)
- while ((inst.mask & buckets) != buckets)
- buckets /= 2;
- buckets++;
-
struct cmp {
- decltype(insn_desc_t::match) mask;
- cmp(decltype(mask) mask) : mask(mask) {}
bool operator()(const insn_desc_t& lhs, const insn_desc_t& rhs) {
- if ((lhs.match & mask) != (rhs.match & mask))
- return (lhs.match & mask) < (rhs.match & mask);
- return lhs.match < rhs.match;
+ if (lhs.match == rhs.match)
+ return lhs.mask > rhs.mask;
+ return lhs.match > rhs.match;
}
};
- std::sort(instructions.begin(), instructions.end(), cmp(buckets-1));
-
- opcode_map.resize(buckets);
- opcode_store.resize(instructions.size() + 1);
+ std::sort(instructions.begin(), instructions.end(), cmp());
- size_t j = 0;
- for (size_t b = 0, i = 0; b < buckets; b++)
- {
- opcode_map[b] = &opcode_store[j];
- while (i < instructions.size() && b == (instructions[i].match & (buckets-1)))
- opcode_store[j++] = instructions[i++];
- }
-
- assert(j == opcode_store.size()-1);
- opcode_store[j].match = opcode_store[j].mask = 0;
- opcode_store[j].rv32 = &illegal_instruction;
- opcode_store[j].rv64 = &illegal_instruction;
+ for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++)
+ opcode_cache[i] = {1, 0, &illegal_instruction, &illegal_instruction};
}
void processor_t::register_extension(extension_t* x)
@@ -665,3 +549,23 @@ void processor_t::register_extension(extension_t* x)
ext = x;
x->set_processor(this);
}
+
+void processor_t::register_base_instructions()
+{
+ std::map<std::string, std::pair<insn_bits_t, insn_bits_t>> opcodes;
+
+ #define DECLARE_INSN(name, match, mask) \
+ opcodes[#name] = std::make_pair(match, mask);
+ #include "encoding.h"
+ #undef DECLARE_INSN
+
+ #define DEFINE_INSN(name) \
+ if (!opcodes.count(#name)) \
+ throw std::logic_error("opcode for " #name " not found"); \
+ REGISTER_INSN(this, name, opcodes[#name].first, opcodes[#name].second)
+ #include "insn_list.h"
+ #undef DEFINE_INSN
+
+ register_insn({0, 0, &illegal_instruction, &illegal_instruction});
+ build_opcode_map();
+}
diff --git a/riscv/processor.h b/riscv/processor.h
index 6af7887..d117ff1 100644
--- a/riscv/processor.h
+++ b/riscv/processor.h
@@ -18,8 +18,8 @@ class disassembler_t;
struct insn_desc_t
{
- uint32_t match;
- uint32_t mask;
+ insn_bits_t match;
+ insn_bits_t mask;
insn_func_t rv32;
insn_func_t rv64;
};
@@ -115,10 +115,11 @@ private:
bool histogram_enabled;
std::vector<insn_desc_t> instructions;
- std::vector<insn_desc_t*> opcode_map;
- std::vector<insn_desc_t> opcode_store;
std::map<size_t,size_t> pc_histogram;
+ static const size_t OPCODE_CACHE_SIZE = 8191;
+ insn_desc_t opcode_cache[OPCODE_CACHE_SIZE];
+
void check_timer();
void take_interrupt(); // take a trap if any interrupts are pending
void take_trap(trap_t& t, reg_t epc); // take an exception
@@ -130,6 +131,7 @@ private:
void parse_isa_string(const char* isa);
void build_opcode_map();
+ void register_base_instructions();
insn_func_t decode_insn(insn_t insn);
};
diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in
index 7ce2cb9..f35f200 100644
--- a/riscv/riscv.mk.in
+++ b/riscv/riscv.mk.in
@@ -29,6 +29,7 @@ riscv_precompiled_hdrs = \
riscv_srcs = \
htif.cc \
processor.cc \
+ execute.cc \
sim.cc \
interactive.cc \
trap.cc \
@@ -45,9 +46,203 @@ riscv_test_srcs =
riscv_gen_hdrs = \
icache.h \
+ insn_list.h \
+
+riscv_insn_list = \
+ add \
+ addi \
+ addiw \
+ addw \
+ amoadd_d \
+ amoadd_w \
+ amoand_d \
+ amoand_w \
+ amomax_d \
+ amomaxu_d \
+ amomaxu_w \
+ amomax_w \
+ amomin_d \
+ amominu_d \
+ amominu_w \
+ amomin_w \
+ amoor_d \
+ amoor_w \
+ amoswap_d \
+ amoswap_w \
+ amoxor_d \
+ amoxor_w \
+ and \
+ andi \
+ auipc \
+ beq \
+ bge \
+ bgeu \
+ blt \
+ bltu \
+ bne \
+ c_add \
+ c_addi16sp \
+ c_addi4spn \
+ c_addi \
+ c_addiw \
+ c_addw \
+ c_beqz \
+ c_bnez \
+ c_ebreak \
+ c_fld \
+ c_fldsp \
+ c_flw \
+ c_flwsp \
+ c_fsd \
+ c_fsdsp \
+ c_fsw \
+ c_fswsp \
+ c_jal \
+ c_jalr \
+ c_j \
+ c_jr \
+ c_li \
+ c_lui \
+ c_lw \
+ c_lwsp \
+ c_mv \
+ c_slli \
+ csrrc \
+ csrrci \
+ csrrs \
+ csrrsi \
+ csrrw \
+ csrrwi \
+ c_sw \
+ c_swsp \
+ div \
+ divu \
+ divuw \
+ divw \
+ fadd_d \
+ fadd_s \
+ fclass_d \
+ fclass_s \
+ fcvt_d_l \
+ fcvt_d_lu \
+ fcvt_d_s \
+ fcvt_d_w \
+ fcvt_d_wu \
+ fcvt_l_d \
+ fcvt_l_s \
+ fcvt_lu_d \
+ fcvt_lu_s \
+ fcvt_s_d \
+ fcvt_s_l \
+ fcvt_s_lu \
+ fcvt_s_w \
+ fcvt_s_wu \
+ fcvt_w_d \
+ fcvt_w_s \
+ fcvt_wu_d \
+ fcvt_wu_s \
+ fdiv_d \
+ fdiv_s \
+ fence \
+ fence_i \
+ feq_d \
+ feq_s \
+ fld \
+ fle_d \
+ fle_s \
+ flt_d \
+ flt_s \
+ flw \
+ fmadd_d \
+ fmadd_s \
+ fmax_d \
+ fmax_s \
+ fmin_d \
+ fmin_s \
+ fmsub_d \
+ fmsub_s \
+ fmul_d \
+ fmul_s \
+ fmv_d_x \
+ fmv_s_x \
+ fmv_x_d \
+ fmv_x_s \
+ fnmadd_d \
+ fnmadd_s \
+ fnmsub_d \
+ fnmsub_s \
+ fsd \
+ fsgnj_d \
+ fsgnjn_d \
+ fsgnjn_s \
+ fsgnj_s \
+ fsgnjx_d \
+ fsgnjx_s \
+ fsqrt_d \
+ fsqrt_s \
+ fsub_d \
+ fsub_s \
+ fsw \
+ hrts \
+ jal \
+ jalr \
+ lb \
+ lbu \
+ ld \
+ lh \
+ lhu \
+ lr_d \
+ lr_w \
+ lui \
+ lw \
+ lwu \
+ mrth \
+ mrts \
+ mul \
+ mulh \
+ mulhsu \
+ mulhu \
+ mulw \
+ or \
+ ori \
+ rem \
+ remu \
+ remuw \
+ remw \
+ sb \
+ sbreak \
+ scall \
+ sc_d \
+ sc_w \
+ sd \
+ sfence_vm \
+ sh \
+ sll \
+ slli \
+ slliw \
+ sllw \
+ slt \
+ slti \
+ sltiu \
+ sltu \
+ sra \
+ srai \
+ sraiw \
+ sraw \
+ sret \
+ srl \
+ srli \
+ srliw \
+ srlw \
+ sub \
+ subw \
+ sw \
+ wfi \
+ xor \
+ xori \
riscv_gen_srcs = \
- $(addsuffix .cc, $(call get_insn_list,$(src_dir)/riscv/encoding.h))
+ $(addsuffix .cc,$(riscv_insn_list))
icache_entries := `grep "ICACHE_ENTRIES =" $(src_dir)/riscv/mmu.h | sed 's/.* = \(.*\);/\1/'`
@@ -55,6 +250,10 @@ icache.h: mmu.h
$(src_dir)/riscv/gen_icache $(icache_entries) > $@.tmp
mv $@.tmp $@
+insn_list.h: $(src_dir)/riscv/riscv.mk.in
+ echo $(riscv_insn_list) | sed 's/\s\+\|$$/\n/g' | sed '/^$$/d' | sed 's/\./_/g' | sed 's/\(.*\)/DEFINE_INSN(\1)/' > $@.tmp
+ mv $@.tmp $@
+
$(riscv_gen_srcs): %.cc: insns/%.h insn_template.cc
sed 's/NAME/$(subst .cc,,$@)/' $(src_dir)/riscv/insn_template.cc | sed 's/OPCODE/$(call get_opcode,$(src_dir)/riscv/encoding.h,$(subst .cc,,$@))/' > $@