aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <waterman@cs.berkeley.edu>2014-12-04 23:10:33 -0800
committerAndrew Waterman <waterman@cs.berkeley.edu>2014-12-04 23:32:54 -0800
commitd643e43dca834fcb2e40504f65d5043d9f2b018b (patch)
tree289f2043af8249f74f408ad804b843c27289d25d
parentcec752d09191e96a51f5c21ed8d51e1218f804ff (diff)
downloadspike-d643e43dca834fcb2e40504f65d5043d9f2b018b.zip
spike-d643e43dca834fcb2e40504f65d5043d9f2b018b.tar.gz
spike-d643e43dca834fcb2e40504f65d5043d9f2b018b.tar.bz2
Support 2/4/6/8-byte instructions
Most of the complexity is in instruction address translation, since instructions may span page boundaries.
-rw-r--r--hwacha/insns/vf.h4
-rw-r--r--riscv/decode.h40
-rw-r--r--riscv/mmu.h45
-rw-r--r--riscv/processor.cc18
-rw-r--r--spike/riscv-dis.cc6
5 files changed, 66 insertions, 47 deletions
diff --git a/hwacha/insns/vf.h b/hwacha/insns/vf.h
index fafb8b9..395ef1e 100644
--- a/hwacha/insns/vf.h
+++ b/hwacha/insns/vf.h
@@ -10,7 +10,7 @@ vf_loop:
if (VF_PC & 3)
h->take_exception(HWACHA_CAUSE_VF_MISALIGNED_FETCH, VF_PC);
- insn_t ut_insn = p->get_mmu()->load_insn(VF_PC).insn.insn;
+ insn_t ut_insn = p->get_mmu()->load_insn(VF_PC).insn;
bool matched = false;
@@ -30,7 +30,7 @@ vf_loop:
if (h->vf_active())
goto vf_loop;
} else {
- fprintf(stderr, "vf block: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n",
+ fprintf(stderr, "vf block: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
VF_PC, ut_insn.bits(), h->get_ut_disassembler()->disassemble(ut_insn).c_str());
if (h->vf_active())
npc = pc;
diff --git a/riscv/decode.h b/riscv/decode.h
index 543080d..b325c59 100644
--- a/riscv/decode.h
+++ b/riscv/decode.h
@@ -44,26 +44,29 @@ const int NFPR = 32;
#define FSR_NXA (FPEXC_NX << FSR_AEXC_SHIFT)
#define FSR_AEXC (FSR_NVA | FSR_OFA | FSR_UFA | FSR_DZA | FSR_NXA)
+typedef uint64_t insn_bits_t;
class insn_t
{
public:
- uint32_t bits() { return b; }
- int32_t i_imm() { return int32_t(b) >> 20; }
- int32_t s_imm() { return x(7, 5) + (xs(25, 7) << 5); }
- int32_t sb_imm() { return (x(8, 4) << 1) + (x(25,6) << 5) + (x(7,1) << 11) + (imm_sign() << 12); }
- int32_t u_imm() { return int32_t(b) >> 12 << 12; }
- int32_t uj_imm() { return (x(21, 10) << 1) + (x(20, 1) << 11) + (x(12, 8) << 12) + (imm_sign() << 20); }
- uint32_t rd() { return x(7, 5); }
- uint32_t rs1() { return x(15, 5); }
- uint32_t rs2() { return x(20, 5); }
- uint32_t rs3() { return x(27, 5); }
- uint32_t rm() { return x(12, 3); }
- uint32_t csr() { return x(20, 12); }
+ insn_t() = default;
+ insn_t(insn_bits_t bits) : b(bits) {}
+ insn_bits_t bits() { return b; }
+ int64_t i_imm() { return int64_t(b) >> 20; }
+ int64_t s_imm() { return x(7, 5) + (xs(25, 7) << 5); }
+ int64_t sb_imm() { return (x(8, 4) << 1) + (x(25,6) << 5) + (x(7,1) << 11) + (imm_sign() << 12); }
+ int64_t u_imm() { return int64_t(b) >> 12 << 12; }
+ int64_t uj_imm() { return (x(21, 10) << 1) + (x(20, 1) << 11) + (x(12, 8) << 12) + (imm_sign() << 20); }
+ uint64_t rd() { return x(7, 5); }
+ uint64_t rs1() { return x(15, 5); }
+ uint64_t rs2() { return x(20, 5); }
+ uint64_t rs3() { return x(27, 5); }
+ uint64_t rm() { return x(12, 3); }
+ uint64_t csr() { return x(20, 12); }
private:
- uint32_t b;
- uint32_t x(int lo, int len) { return b << (32-lo-len) >> (32-len); }
- uint32_t xs(int lo, int len) { return int32_t(b) << (32-lo-len) >> (32-len); }
- uint32_t imm_sign() { return xs(31, 1); }
+ insn_bits_t b;
+ uint64_t x(int lo, int len) { return (b >> lo) & ((insn_bits_t(1) << len)-1); }
+ uint64_t xs(int lo, int len) { return int64_t(b) << (64-lo-len) >> (64-len); }
+ uint64_t imm_sign() { return xs(63, 1); }
};
template <class T, size_t N, bool zero_reg>
@@ -76,9 +79,8 @@ public:
}
void write(size_t i, T value)
{
- data[i] = value;
- if (zero_reg)
- data[0] = 0;
+ if (!zero_reg || i != 0)
+ data[i] = value;
}
const T& operator [] (size_t i) const
{
diff --git a/riscv/mmu.h b/riscv/mmu.h
index c3d8f41..778e5fa 100644
--- a/riscv/mmu.h
+++ b/riscv/mmu.h
@@ -25,10 +25,7 @@ const reg_t VA_BITS = VPN_BITS + PGSHIFT;
struct insn_fetch_t
{
insn_func_t func;
- union {
- insn_t insn;
- uint_fast32_t pad;
- } insn;
+ insn_t insn;
};
struct icache_entry_t {
@@ -77,27 +74,49 @@ public:
store_func(uint32)
store_func(uint64)
+ inline size_t icache_index(reg_t addr)
+ {
+ // for instruction sizes != 4, this hash still works but is suboptimal
+ return (addr / 4) % ICACHE_SIZE;
+ }
+
// load instruction from memory at aligned address.
- inline icache_entry_t* access_icache(reg_t addr)
+ icache_entry_t* access_icache(reg_t addr) __attribute__((always_inline))
{
- reg_t idx = (addr / sizeof(insn_t)) % ICACHE_SIZE;
+ reg_t idx = icache_index(addr);
icache_entry_t* entry = &icache[idx];
if (likely(entry->tag == addr))
return entry;
- void* iaddr = translate(addr, sizeof(insn_t), false, true);
- insn_fetch_t fetch;
- fetch.insn.pad = *(decltype(fetch.insn.insn.bits())*)iaddr;
- fetch.func = proc->decode_insn(fetch.insn.insn);
+ char* iaddr = (char*)translate(addr, 2, false, true);
+ insn_bits_t insn = *(uint16_t*)iaddr;
+
+ if (unlikely(insn_length(insn) == 2)) {
+ insn = (int16_t)insn;
+ } else if (likely(insn_length(insn) == 4)) {
+ if (likely((addr & (PGSIZE-1)) < PGSIZE-2))
+ insn |= (insn_bits_t)*(int16_t*)(iaddr + 2) << 16;
+ else
+ insn |= (insn_bits_t)*(int16_t*)translate(addr + 2, 2, false, true) << 16;
+ } else if (insn_length(insn) == 6) {
+ insn |= (insn_bits_t)*(int16_t*)translate(addr + 4, 2, false, true) << 32;
+ insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16;
+ } else {
+ static_assert(sizeof(insn_bits_t) == 8, "insn_bits_t must be uint64_t");
+ insn |= (insn_bits_t)*(int16_t*)translate(addr + 6, 2, false, true) << 48;
+ insn |= (insn_bits_t)*(uint16_t*)translate(addr + 4, 2, false, true) << 32;
+ insn |= (insn_bits_t)*(uint16_t*)translate(addr + 2, 2, false, true) << 16;
+ }
+ insn_fetch_t fetch = {proc->decode_insn(insn), insn};
icache[idx].tag = addr;
icache[idx].data = fetch;
- reg_t paddr = (char*)iaddr - mem;
- if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + sizeof(insn_t), false, true))
+ reg_t paddr = iaddr - mem;
+ if (!tracer.empty() && tracer.interested_in_range(paddr, paddr + 1, false, true))
{
icache[idx].tag = -1;
- tracer.trace(paddr, sizeof(insn_t), false, true);
+ tracer.trace(paddr, 1, false, true);
}
return &icache[idx];
}
diff --git a/riscv/processor.cc b/riscv/processor.cc
index 956b2d3..08ec2b7 100644
--- a/riscv/processor.cc
+++ b/riscv/processor.cc
@@ -129,13 +129,13 @@ static void commit_log(state_t* state, insn_t insn)
#ifdef RISCV_ENABLE_COMMITLOG
if (state->sr & SR_EI) {
if (state->log_reg_write.addr) {
- fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx32 ") %c%2u 0x%016" PRIx64 "\n",
+ fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ") %c%2u 0x%016" PRIx64 "\n",
state->pc, insn.bits(),
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" PRIx32 ")\n",
+ fprintf(stderr, "0x%016" PRIx64 " (0x%08" PRIx64 ")\n",
state->pc, insn.bits());
}
}
@@ -153,8 +153,8 @@ inline void processor_t::update_histogram(size_t pc)
static reg_t execute_insn(processor_t* p, reg_t pc, insn_fetch_t fetch)
{
- reg_t npc = fetch.func(p, fetch.insn.insn, pc);
- commit_log(p->get_state(), fetch.insn.insn);
+ reg_t npc = fetch.func(p, fetch.insn, pc);
+ commit_log(p->get_state(), fetch.insn);
p->update_histogram(pc);
return npc;
}
@@ -192,13 +192,13 @@ void processor_t::step(size_t n)
while (instret++ < n)
{
insn_fetch_t fetch = mmu->load_insn(pc);
- disasm(fetch.insn.insn);
+ disasm(fetch.insn);
pc = execute_insn(this, pc, fetch);
}
}
else while (instret < n)
{
- size_t idx = (pc / sizeof(insn_t)) % ICACHE_SIZE;
+ size_t idx = _mmu->icache_index(pc);
auto ic_entry = _mmu->access_icache(pc);
#define ICACHE_ACCESS(idx) { \
@@ -251,9 +251,9 @@ void processor_t::deliver_ipi()
void processor_t::disasm(insn_t insn)
{
- // the disassembler is stateless, so we share it
- fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx32 ") %s\n",
- id, state.pc, insn.bits(), disassembler->disassemble(insn).c_str());
+ uint64_t bits = insn.bits() & ((1ULL << (8 * insn_length(insn.bits()))) - 1);
+ fprintf(stderr, "core %3d: 0x%016" PRIx64 " (0x%08" PRIx64 ") %s\n",
+ id, state.pc, bits, disassembler->disassemble(insn).c_str());
}
void processor_t::set_pcr(int which, reg_t val)
diff --git a/spike/riscv-dis.cc b/spike/riscv-dis.cc
index 89c4b74..d0af451 100644
--- a/spike/riscv-dis.cc
+++ b/spike/riscv-dis.cc
@@ -32,10 +32,8 @@ int main(int argc, char** argv)
break;
size_t numstart = start + strlen("DASM(");
- uint32_t n = strtoul(&s[numstart], NULL, 16);
-
- string dis = d.disassemble(*(insn_t*)&n);
-
+ insn_bits_t bits = strtoull(&s[numstart], NULL, 16);
+ string dis = d.disassemble(bits);
s = s.substr(0, start) + dis + s.substr(end+1);
start += dis.length();
}