diff options
author | Andrew Waterman <andrew@sifive.com> | 2022-02-16 05:02:41 -0800 |
---|---|---|
committer | Andrew Waterman <andrew@sifive.com> | 2022-02-16 05:02:41 -0800 |
commit | 8cc6ebead30e00912fa1d254840b6288a16a2a23 (patch) | |
tree | dc853266bc4ae5655b349171504734cb82946491 /riscv | |
parent | e03fa93c988ec92b6f1427b5cc10c40b41351e70 (diff) | |
parent | b68b758b251645c89408c7cd1ce4bd2a2d55889c (diff) | |
download | riscv-isa-sim-8cc6ebead30e00912fa1d254840b6288a16a2a23.zip riscv-isa-sim-8cc6ebead30e00912fa1d254840b6288a16a2a23.tar.gz riscv-isa-sim-8cc6ebead30e00912fa1d254840b6288a16a2a23.tar.bz2 |
Merge branch 'plctlab-plct-cmo-upstream'
Diffstat (limited to 'riscv')
-rw-r--r-- | riscv/cachesim.cc | 25 | ||||
-rw-r--r-- | riscv/cachesim.h | 5 | ||||
-rw-r--r-- | riscv/decode.h | 14 | ||||
-rw-r--r-- | riscv/insns/cbo_clean.h | 4 | ||||
-rw-r--r-- | riscv/insns/cbo_flush.h | 4 | ||||
-rw-r--r-- | riscv/insns/cbo_inval.h | 9 | ||||
-rw-r--r-- | riscv/insns/cbo_zero.h | 4 | ||||
-rw-r--r-- | riscv/insns/ori.h | 1 | ||||
-rw-r--r-- | riscv/memtracer.h | 14 | ||||
-rw-r--r-- | riscv/mmu.h | 56 | ||||
-rw-r--r-- | riscv/processor.cc | 14 | ||||
-rw-r--r-- | riscv/processor.h | 7 | ||||
-rw-r--r-- | riscv/riscv.mk.in | 7 |
13 files changed, 146 insertions, 18 deletions
diff --git a/riscv/cachesim.cc b/riscv/cachesim.cc index 6e030d1..48840cb 100644 --- a/riscv/cachesim.cc +++ b/riscv/cachesim.cc @@ -159,6 +159,31 @@ void cache_sim_t::access(uint64_t addr, size_t bytes, bool store) *check_tag(addr) |= DIRTY; } +void cache_sim_t::clean_invalidate(uint64_t addr, size_t bytes, bool clean, bool inval) +{ + uint64_t start_addr = addr & ~(linesz-1); + uint64_t end_addr = (addr + bytes + linesz-1) & ~(linesz-1); + uint64_t cur_addr = start_addr; + while (cur_addr < end_addr) { + uint64_t* hit_way = check_tag(cur_addr); + if (likely(hit_way != NULL)) + { + if (clean) { + if (*hit_way & DIRTY) { + writebacks++; + *hit_way &= ~DIRTY; + } + } + + if (inval) + *hit_way &= ~VALID; + } + cur_addr += linesz; + } + if (miss_handler) + miss_handler->clean_invalidate(addr, bytes, clean, inval); +} + fa_cache_sim_t::fa_cache_sim_t(size_t ways, size_t linesz, const char* name) : cache_sim_t(1, ways, linesz, name) { diff --git a/riscv/cachesim.h b/riscv/cachesim.h index 259725a..b7f9014 100644 --- a/riscv/cachesim.h +++ b/riscv/cachesim.h @@ -27,6 +27,7 @@ class cache_sim_t virtual ~cache_sim_t(); void access(uint64_t addr, size_t bytes, bool store); + void clean_invalidate(uint64_t addr, size_t bytes, bool clean, bool inval); void print_stats(); void set_miss_handler(cache_sim_t* mh) { miss_handler = mh; } void set_log(bool _log) { log = _log; } @@ -90,6 +91,10 @@ class cache_memtracer_t : public memtracer_t { cache->set_miss_handler(mh); } + void clean_invalidate(uint64_t addr, size_t bytes, bool clean, bool inval) + { + cache->clean_invalidate(addr, bytes, clean, inval); + } void set_log(bool log) { cache->set_log(log); diff --git a/riscv/decode.h b/riscv/decode.h index c2912e4..6f99cf5 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -278,6 +278,15 @@ private: #define require_noover_widen(astart, asize, bstart, bsize) \ require(!is_overlapped_widen(astart, asize, bstart, bsize)) #define require_vm do { if (insn.v_vm() == 0) require(insn.rd() != 0);} while(0); +#define require_envcfg(field) \ + do { \ + if (((STATE.prv != PRV_M) && (m##field == 0)) || \ + ((STATE.prv == PRV_U && !STATE.v) && (s##field == 0))) \ + throw trap_illegal_instruction(insn.bits()); \ + else if (STATE.v && ((h##field == 0) || \ + ((STATE.prv == PRV_U) && (s##field == 0)))) \ + throw trap_virtual_instruction(insn.bits()); \ + } while(0); #define set_fp_exceptions ({ if (softfloat_exceptionFlags) { \ STATE.fflags->write(STATE.fflags->read() | softfloat_exceptionFlags); \ @@ -3038,6 +3047,11 @@ reg_t index[P.VU.vlmax]; \ WRITE_RD(sext_xlen(rd)); \ } +#define DECLARE_XENVCFG_VARS(field) \ + reg_t m##field = get_field(STATE.menvcfg->read(), MENVCFG_##field); \ + reg_t s##field = get_field(STATE.senvcfg->read(), SENVCFG_##field); \ + reg_t h##field = get_field(STATE.henvcfg->read(), HENVCFG_##field) + #define DEBUG_START 0x0 #define DEBUG_END (0x1000 - 1) diff --git a/riscv/insns/cbo_clean.h b/riscv/insns/cbo_clean.h new file mode 100644 index 0000000..201fa44 --- /dev/null +++ b/riscv/insns/cbo_clean.h @@ -0,0 +1,4 @@ +require_extension(EXT_ZICBOM); +DECLARE_XENVCFG_VARS(CBCFE); +require_envcfg(CBCFE); +MMU.clean_inval(RS1, true, false); diff --git a/riscv/insns/cbo_flush.h b/riscv/insns/cbo_flush.h new file mode 100644 index 0000000..b17f5cf --- /dev/null +++ b/riscv/insns/cbo_flush.h @@ -0,0 +1,4 @@ +require_extension(EXT_ZICBOM); +DECLARE_XENVCFG_VARS(CBCFE); +require_envcfg(CBCFE); +MMU.clean_inval(RS1, true, true); diff --git a/riscv/insns/cbo_inval.h b/riscv/insns/cbo_inval.h new file mode 100644 index 0000000..bd80a6f --- /dev/null +++ b/riscv/insns/cbo_inval.h @@ -0,0 +1,9 @@ +require_extension(EXT_ZICBOM); +DECLARE_XENVCFG_VARS(CBIE); +require_envcfg(CBIE); +if (((STATE.prv != PRV_M) && (mCBIE == 1)) || + ((!STATE.v && (STATE.prv == PRV_U)) && (sCBIE = 1)) || + (STATE.v && ((hCBIE == 1) || ((STATE.prv == PRV_U) && (sCBIE== 0))))) + MMU.clean_inval(RS1, true, true); +else + MMU.clean_inval(RS1, false, true); diff --git a/riscv/insns/cbo_zero.h b/riscv/insns/cbo_zero.h new file mode 100644 index 0000000..4bbe28d --- /dev/null +++ b/riscv/insns/cbo_zero.h @@ -0,0 +1,4 @@ +require_extension(EXT_ZICBOZ); +DECLARE_XENVCFG_VARS(CBZE); +require_envcfg(CBZE); +MMU.cbo_zero(RS1); diff --git a/riscv/insns/ori.h b/riscv/insns/ori.h index 6403c39..3aba1cb 100644 --- a/riscv/insns/ori.h +++ b/riscv/insns/ori.h @@ -1 +1,2 @@ +// prefetch.i/r/w hint when rd = 0 and i_imm[4:0] = 0/1/3 WRITE_RD(insn.i_imm() | RS1); diff --git a/riscv/memtracer.h b/riscv/memtracer.h index 6952e2f..72bb3a8 100644 --- a/riscv/memtracer.h +++ b/riscv/memtracer.h @@ -21,6 +21,7 @@ class memtracer_t virtual bool interested_in_range(uint64_t begin, uint64_t end, access_type type) = 0; virtual void trace(uint64_t addr, size_t bytes, access_type type) = 0; + virtual void clean_invalidate(uint64_t addr, size_t bytes, bool clean, bool inval) = 0; }; class memtracer_list_t : public memtracer_t @@ -29,15 +30,20 @@ class memtracer_list_t : public memtracer_t bool empty() { return list.empty(); } bool interested_in_range(uint64_t begin, uint64_t end, access_type type) { - for (std::vector<memtracer_t*>::iterator it = list.begin(); it != list.end(); ++it) - if ((*it)->interested_in_range(begin, end, type)) + for (auto it: list) + if (it->interested_in_range(begin, end, type)) return true; return false; } void trace(uint64_t addr, size_t bytes, access_type type) { - for (std::vector<memtracer_t*>::iterator it = list.begin(); it != list.end(); ++it) - (*it)->trace(addr, bytes, type); + for (auto it: list) + it->trace(addr, bytes, type); + } + void clean_invalidate(uint64_t addr, size_t bytes, bool clean, bool inval) + { + for (auto it: list) + it->clean_invalidate(addr, bytes, clean, inval); } void hook(memtracer_t* h) { diff --git a/riscv/mmu.h b/riscv/mmu.h index 0b86f6c..017b483 100644 --- a/riscv/mmu.h +++ b/riscv/mmu.h @@ -184,27 +184,30 @@ public: } \ } + // AMO/Zicbom faults should be reported as store faults + #define convert_load_traps_to_store_traps(BODY) \ + try { \ + BODY \ + } catch (trap_load_address_misaligned& t) { \ + /* Misaligned fault will not be triggered by Zicbom */ \ + throw trap_store_address_misaligned(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ + } catch (trap_load_page_fault& t) { \ + throw trap_store_page_fault(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ + } catch (trap_load_access_fault& t) { \ + throw trap_store_access_fault(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ + } catch (trap_load_guest_page_fault& t) { \ + throw trap_store_guest_page_fault(t.get_tval(), t.get_tval2(), t.get_tinst()); \ + } + // template for functions that perform an atomic memory operation #define amo_func(type) \ template<typename op> \ type##_t amo_##type(reg_t addr, op f) { \ - try { \ + convert_load_traps_to_store_traps({ \ auto lhs = load_##type(addr, true); \ store_##type(addr, f(lhs)); \ return lhs; \ - } catch (trap_load_address_misaligned& t) { \ - /* AMO faults should be reported as store faults */ \ - throw trap_store_address_misaligned(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ - } catch (trap_load_page_fault& t) { \ - /* AMO faults should be reported as store faults */ \ - throw trap_store_page_fault(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ - } catch (trap_load_access_fault& t) { \ - /* AMO faults should be reported as store faults */ \ - throw trap_store_access_fault(t.has_gva(), t.get_tval(), t.get_tval2(), t.get_tinst()); \ - } catch (trap_load_guest_page_fault& t) { \ - /* AMO faults should be reported as store faults */ \ - throw trap_store_guest_page_fault(t.get_tval(), t.get_tval2(), t.get_tinst()); \ - } \ + }) \ } void store_float128(reg_t addr, float128_t val) @@ -242,6 +245,25 @@ public: amo_func(uint32) amo_func(uint64) + void cbo_zero(reg_t addr) { + auto base = addr & ~(blocksz - 1); + for (size_t offset = 0; offset < blocksz; offset += 1) + store_uint8(base + offset, 0); + } + + void clean_inval(reg_t addr, bool clean, bool inval) { + convert_load_traps_to_store_traps({ + reg_t paddr = addr & ~(blocksz - 1); + paddr = translate(paddr, blocksz, LOAD, 0); + if (auto host_addr = sim->addr_to_mem(paddr)) { + if (tracer.interested_in_range(paddr, paddr + PGSIZE, LOAD)) + tracer.clean_invalidate(paddr, blocksz, clean, inval); + } else { + throw trap_store_access_fault((proc) ? proc->state.v : false, addr, 0, 0); + } + }) + } + inline void yield_load_reservation() { load_reservation_address = (reg_t)-1; @@ -389,12 +411,18 @@ public: return target_big_endian? target_endian<T>::to_be(n) : target_endian<T>::to_le(n); } + void set_cache_blocksz(uint64_t size) + { + blocksz = size; + } + private: simif_t* sim; processor_t* proc; memtracer_list_t tracer; reg_t load_reservation_address; uint16_t fetch_temp; + uint64_t blocksz; // implement an instruction cache for simulator performance icache_entry_t icache[ICACHE_ENTRIES]; diff --git a/riscv/processor.cc b/riscv/processor.cc index 415f2bb..a927acc 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -338,6 +338,11 @@ isa_parser_t::isa_parser_t(const char* str) extension_table[EXT_SVPBMT] = true; } else if (ext_str == "svinval") { extension_table[EXT_SVINVAL] = true; + } else if (ext_str == "zicbom") { + extension_table[EXT_ZICBOM] = true; + } else if (ext_str == "zicboz") { + extension_table[EXT_ZICBOZ] = true; + } else if (ext_str == "zicbop") { } else if (ext_str[0] == 'x') { max_isa |= 1L << ('x' - 'a'); extension_table[toupper('x')] = true; @@ -569,6 +574,15 @@ void state_t::reset(processor_t* const proc, reg_t max_isa) csrmap[CSR_MIMPID] = std::make_shared<const_csr_t>(proc, CSR_MIMPID, 0); csrmap[CSR_MVENDORID] = std::make_shared<const_csr_t>(proc, CSR_MVENDORID, 0); csrmap[CSR_MHARTID] = std::make_shared<const_csr_t>(proc, CSR_MHARTID, proc->get_id()); + const reg_t menvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? MENVCFG_CBCFE | MENVCFG_CBIE: 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? MENVCFG_CBZE: 0); + csrmap[CSR_MENVCFG] = menvcfg = std::make_shared<masked_csr_t>(proc, CSR_MENVCFG, menvcfg_mask, 0); + const reg_t senvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? SENVCFG_CBCFE | SENVCFG_CBIE: 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? SENVCFG_CBZE: 0); + csrmap[CSR_SENVCFG] = senvcfg = std::make_shared<masked_csr_t>(proc, CSR_SENVCFG, senvcfg_mask, 0); + const reg_t henvcfg_mask = (proc->extension_enabled(EXT_ZICBOM) ? HENVCFG_CBCFE | HENVCFG_CBIE: 0) | + (proc->extension_enabled(EXT_ZICBOZ) ? HENVCFG_CBZE: 0); + csrmap[CSR_HENVCFG] = henvcfg = std::make_shared<masked_csr_t>(proc, CSR_HENVCFG, henvcfg_mask, 0); serialized = false; diff --git a/riscv/processor.h b/riscv/processor.h index aa98644..d4a42b2 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -218,6 +218,11 @@ struct state_t csr_t_p fflags; csr_t_p frm; + + csr_t_p menvcfg; + csr_t_p senvcfg; + csr_t_p henvcfg; + bool serialized; // whether timer CSRs are in a well-defined state // When true, execute a single instruction and then enter debug mode. This @@ -273,6 +278,8 @@ typedef enum { EXT_ZHINX, EXT_ZHINXMIN, EXT_XBITMANIP, + EXT_ZICBOM, + EXT_ZICBOZ, } isa_extension_t; typedef enum { diff --git a/riscv/riscv.mk.in b/riscv/riscv.mk.in index 5601466..075179b 100644 --- a/riscv/riscv.mk.in +++ b/riscv/riscv.mk.in @@ -1260,6 +1260,12 @@ riscv_insn_svinval = \ hinval_vvma \ hinval_gvma \ +riscv_insn_ext_cmo = \ + cbo_clean \ + cbo_flush \ + cbo_inval \ + cbo_zero \ + riscv_insn_list = \ $(riscv_insn_ext_a) \ $(riscv_insn_ext_c) \ @@ -1276,6 +1282,7 @@ riscv_insn_list = \ $(riscv_insn_ext_p) \ $(riscv_insn_priv) \ $(riscv_insn_svinval) \ + $(riscv_insn_ext_cmo) \ riscv_gen_srcs = \ $(addsuffix .cc,$(riscv_insn_list)) |