From: Andrew Waterman Date: Wed, 13 Feb 2013 22:13:51 +0000 (-0800) Subject: clean up fetch-execute loop a bit X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=ea3ad100c5603d0a32dba2e5561f4df2dd9493dd;p=riscv-isa-sim.git clean up fetch-execute loop a bit --- diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 6782ae2..0cc1035 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -13,6 +13,11 @@ mmu_t::~mmu_t() { } +void mmu_t::flush_icache() +{ + memset(icache_tag, -1, sizeof(icache_tag)); +} + void mmu_t::flush_tlb() { memset(tlb_insn_tag, -1, sizeof(tlb_insn_tag)); @@ -22,12 +27,7 @@ void mmu_t::flush_tlb() flush_icache(); } -void mmu_t::flush_icache() -{ - memset(icache_tag, -1, sizeof(icache_tag)); -} - -void* mmu_t::refill(reg_t addr, reg_t bytes, bool store, bool fetch) +void* mmu_t::refill_tlb(reg_t addr, reg_t bytes, bool store, bool fetch) { reg_t idx = (addr >> PGSHIFT) % TLB_ENTRIES; reg_t expected_tag = addr & ~(PGSIZE-1); diff --git a/riscv/mmu.h b/riscv/mmu.h index 2420878..7400df8 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -85,56 +85,60 @@ public: store_func(uint32) store_func(uint64) + struct insn_fetch_t + { + insn_t insn; + insn_func_t func; + }; + // load instruction from memory at aligned address. // (needed because instruction alignment requirement is variable // if RVC is supported) // returns the instruction at the specified address, given the current // RVC mode. func is set to a pointer to a function that knows how to // execute the returned instruction. - insn_t __attribute__((always_inline)) load_insn(reg_t addr, bool rvc, - insn_func_t* func) + inline insn_fetch_t load_insn(reg_t addr, bool rvc) { - insn_t insn; - #ifdef RISCV_ENABLE_RVC if(addr % 4 == 2 && rvc) // fetch across word boundary { void* addr_lo = translate(addr, 2, false, true); - insn.bits = *(uint16_t*)addr_lo; + insn_fetch_t fetch; + fetch.insn.bits = *(uint16_t*)addr_lo; + size_t dispatch_idx = fetch.insn.bits % processor_t::DISPATCH_TABLE_SIZE; + fetch.func = processor_t::dispatch_table[dispatch_idx]; - *func = processor_t::dispatch_table - [insn.bits % processor_t::DISPATCH_TABLE_SIZE]; - - if(!INSN_IS_RVC(insn.bits)) + if(!INSN_IS_RVC(fetch.insn.bits)) { void* addr_hi = translate(addr+2, 2, false, true); - insn.bits |= (uint32_t)*(uint16_t*)addr_hi << 16; + fetch.insn.bits |= (uint32_t)*(uint16_t*)addr_hi << 16; } + return fetch; } else #endif { reg_t idx = (addr/sizeof(insn_t)) % ICACHE_ENTRIES; - insn_t data = icache_data[idx]; - *func = icache_func[idx]; - if(likely(icache_tag[idx] == addr)) - return data; - - // the processor guarantees alignment based upon rvc mode - void* paddr = translate(addr, sizeof(insn_t), false, true); - insn = *(insn_t*)paddr; - *func = processor_t::dispatch_table - [insn.bits % processor_t::DISPATCH_TABLE_SIZE]; - - if (!tracer.interested_in_range(addr, addr + sizeof(insn_t), false, true)) + insn_fetch_t fetch; + if (unlikely(icache_tag[idx] != addr)) { + void* paddr = translate(addr, sizeof(insn_t), false, true); + fetch.insn = *(insn_t*)paddr; + size_t dispatch_idx = fetch.insn.bits % processor_t::DISPATCH_TABLE_SIZE; + fetch.func = processor_t::dispatch_table[dispatch_idx]; + + reg_t idx = ((uintptr_t)paddr/sizeof(insn_t)) % ICACHE_ENTRIES; icache_tag[idx] = addr; - icache_data[idx] = insn; - icache_func[idx] = *func; + icache_data[idx] = fetch.insn; + icache_func[idx] = fetch.func; + + if (tracer.interested_in_range(addr, addr + sizeof(insn_t), false, true)) + icache_tag[idx] = -1; } + fetch.insn = icache_data[idx];; + fetch.func = icache_func[idx]; + return fetch; } - - return insn; } // get the virtual address that caused a fault @@ -177,7 +181,7 @@ private: reg_t icache_tag[ICACHE_ENTRIES]; // finish translation on a TLB miss and upate the TLB - void* refill(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); @@ -192,7 +196,7 @@ private: if(likely(tlb_tag[idx] == expected_tag)) return ((uintptr_t)addr & (PGSIZE-1)) + tlb_data[idx]; - return refill(addr, bytes, store, fetch); + return refill_tlb(addr, bytes, store, fetch); } friend class processor_t; diff --git a/riscv/processor.cc b/riscv/processor.cc index cdcf536..38f2965 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -112,21 +112,19 @@ void processor_t::step(size_t n, bool noisy) return; size_t i = 0; - while(1) try + try { take_interrupt(); mmu_t& _mmu = mmu; - insn_t insn; - insn_func_t func; reg_t npc = pc; // execute_insn fetches and executes one instruction #define execute_insn(noisy) \ do { \ - insn = _mmu.load_insn(npc, sr & SR_EC, &func); \ - if(noisy) disasm(insn,pc); \ - npc = func(this, insn, npc); \ + mmu_t::insn_fetch_t fetch = _mmu.load_insn(npc, sr & SR_EC); \ + if(noisy) disasm(fetch.insn, npc); \ + npc = fetch.func(this, fetch.insn, npc); \ pc = npc; \ } while(0) @@ -145,26 +143,20 @@ void processor_t::step(size_t n, bool noisy) for( ; i < n; i++) execute_insn(false); } - - break; } catch(trap_t t) { // an exception occurred in the target processor - i++; take_trap(t,noisy); } catch(interrupt_t t) { - i++; take_trap((1ULL << (8*sizeof(reg_t)-1)) + t.i, noisy); } catch(vt_command_t cmd) { // this microthread has finished - i++; assert(cmd == vt_command_stop); - break; } cycle += i;