diff options
author | Andrew Waterman <waterman@eecs.berkeley.edu> | 2013-12-17 10:18:47 -0800 |
---|---|---|
committer | Andrew Waterman <waterman@eecs.berkeley.edu> | 2013-12-17 10:18:47 -0800 |
commit | 7f457c47b339cc7c79f56bb277ed8ed989e88ae1 (patch) | |
tree | 4a3cc949c4a5631699c69443b1a24049ca01fbb4 /riscv/mmu.h | |
parent | e85cb99c5e042ebce78f64213677a48ee7ba0491 (diff) | |
download | spike-7f457c47b339cc7c79f56bb277ed8ed989e88ae1.zip spike-7f457c47b339cc7c79f56bb277ed8ed989e88ae1.tar.gz spike-7f457c47b339cc7c79f56bb277ed8ed989e88ae1.tar.bz2 |
Speed things up quite a bit
Diffstat (limited to 'riscv/mmu.h')
-rw-r--r-- | riscv/mmu.h | 71 |
1 files changed, 40 insertions, 31 deletions
diff --git a/riscv/mmu.h b/riscv/mmu.h index 227d5c7..551fa46 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -31,11 +31,11 @@ public: // template for functions that load an aligned value from memory #define load_func(type) \ - type##_t load_##type(reg_t addr) { \ + type##_t load_##type(reg_t addr) __attribute__((always_inline)) { \ if(unlikely(addr % sizeof(type##_t))) \ throw trap_load_address_misaligned(addr); \ - reg_t paddr = translate(addr, sizeof(type##_t), false, false); \ - return *(type##_t*)(mem + paddr); \ + void* paddr = translate(addr, sizeof(type##_t), false, false); \ + return *(type##_t*)paddr; \ } // load value from memory at aligned address; zero extend to register width @@ -55,8 +55,8 @@ public: void store_##type(reg_t addr, type##_t val) { \ if(unlikely(addr % sizeof(type##_t))) \ throw trap_store_address_misaligned(addr); \ - reg_t paddr = translate(addr, sizeof(type##_t), true, false); \ - *(type##_t*)(mem + paddr) = val; \ + void* paddr = translate(addr, sizeof(type##_t), true, false); \ + *(type##_t*)paddr = val; \ } // store value to memory at aligned address @@ -77,25 +77,28 @@ public: // load instruction from memory at aligned address. inline insn_fetch_t load_insn(reg_t addr) { - reg_t idx = (addr/sizeof(insn_t)) % ICACHE_ENTRIES; - if (unlikely(icache_tag[idx] != addr)) + reg_t offset = addr & (sizeof(insn_t) * (ICACHE_ENTRIES-1)); + offset *= sizeof(icache_entry_t) / sizeof(insn_t); + icache_entry_t* entry = (icache_entry_t*)((char*)icache + offset); + insn_fetch_t data = entry->data; + if (likely(entry->tag == addr)) + return data; + + 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); + + entry->tag = addr; + entry->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 = translate(addr, sizeof(insn_t), false, true); - insn_fetch_t fetch; - fetch.insn.insn = *(insn_t*)(mem + paddr); - fetch.func = proc->decode_insn(fetch.insn.insn); - - reg_t idx = (paddr/sizeof(insn_t)) % ICACHE_ENTRIES; - icache_tag[idx] = addr; - icache_data[idx] = fetch; - - if (tracer.interested_in_range(paddr, paddr + sizeof(insn_t), false, true)) - { - icache_tag[idx] = -1; - tracer.trace(paddr, sizeof(insn_t), false, true); - } + entry->tag = -1; + tracer.trace(paddr, sizeof(insn_t), false, true); } - return icache_data[idx]; + return entry->data; } void set_processor(processor_t* p) { proc = p; flush_tlb(); } @@ -112,32 +115,38 @@ private: memtracer_list_t tracer; // implement an instruction cache for simulator performance - static const reg_t ICACHE_ENTRIES = 256; - insn_fetch_t icache_data[ICACHE_ENTRIES]; + static const reg_t ICACHE_ENTRIES = 2048; + struct icache_entry_t { + reg_t tag; + reg_t pad; + insn_fetch_t data; + }; + icache_entry_t icache[ICACHE_ENTRIES]; // implement a TLB for simulator performance static const reg_t TLB_ENTRIES = 256; - reg_t tlb_data[TLB_ENTRIES]; + char* tlb_data[TLB_ENTRIES]; reg_t tlb_insn_tag[TLB_ENTRIES]; reg_t tlb_load_tag[TLB_ENTRIES]; reg_t tlb_store_tag[TLB_ENTRIES]; - reg_t icache_tag[ICACHE_ENTRIES]; // finish translation on a TLB miss and upate the TLB - reg_t refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch); + void* refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch); // perform a page table walk for a given virtual address pte_t walk(reg_t addr); // translate a virtual address to a physical address - reg_t translate(reg_t addr, reg_t bytes, bool store, bool fetch) + void* translate(reg_t addr, reg_t bytes, bool store, bool fetch) + __attribute__((always_inline)) { reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES; + reg_t expected_tag = addr & ~(PGSIZE-1); reg_t* tlb_tag = fetch ? tlb_insn_tag : store ? tlb_store_tag :tlb_load_tag; - reg_t expected_tag = addr & ~(PGSIZE-1); - if(likely(tlb_tag[idx] == expected_tag)) - return ((uintptr_t)addr & (PGSIZE-1)) + tlb_data[idx]; + void* data = tlb_data[idx] + addr; + if (likely(tlb_tag[idx] == expected_tag)) + return data; return refill_tlb(addr, bytes, store, fetch); } |