aboutsummaryrefslogtreecommitdiff
path: root/riscv/mmu.h
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 /riscv/mmu.h
parentcec752d09191e96a51f5c21ed8d51e1218f804ff (diff)
downloadriscv-isa-sim-d643e43dca834fcb2e40504f65d5043d9f2b018b.zip
riscv-isa-sim-d643e43dca834fcb2e40504f65d5043d9f2b018b.tar.gz
riscv-isa-sim-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.
Diffstat (limited to 'riscv/mmu.h')
-rw-r--r--riscv/mmu.h45
1 files changed, 32 insertions, 13 deletions
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];
}