From 1672b01e62d6ba23fb51409e1f545f20563f3506 Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Thu, 27 Apr 2023 12:20:30 +0200 Subject: [PATCH] adds WT cache functionality as mixin --- src/iss/arch/riscv_hart_m_p.h | 19 +++- src/iss/arch/riscv_hart_msu_vp.h | 12 +-- src/iss/arch/riscv_hart_mu_p.h | 24 ++++- src/iss/arch/wt_cache.h | 172 +++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+), 12 deletions(-) create mode 100644 src/iss/arch/wt_cache.h diff --git a/src/iss/arch/riscv_hart_m_p.h b/src/iss/arch/riscv_hart_m_p.h index 74e20c0..2a39f83 100644 --- a/src/iss/arch/riscv_hart_m_p.h +++ b/src/iss/arch/riscv_hart_m_p.h @@ -422,6 +422,15 @@ protected: feature_config cfg; unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16}; inline bool debug_mode_active() {return this->reg.PRIV&0x4;} + std::pair, std::function> + replace_mem_access(std::function rd, std::function wr){ + std::pair, std::function> ret{hart_mem_rd_delegate, hart_mem_wr_delegate}; + hart_mem_rd_delegate = rd; + hart_mem_wr_delegate = wr; + return ret; + } + std::function hart_mem_rd_delegate; + std::function hart_mem_wr_delegate; }; template @@ -543,6 +552,12 @@ riscv_hart_m_p::riscv_hart_m_p(feature_config cfg) csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr; csr_rd_cb[dcsr] = &this_class::read_dcsr_reg; } + hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { + return this->read_mem(a, l, d); + }; + hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { + return this->write_mem(a, l, d); + }; } template std::pair riscv_hart_m_p::load_file(std::string name, int type) { @@ -663,9 +678,9 @@ iss::status riscv_hart_m_p::read(const address_type type, const acce auto idx = std::distance(std::begin(memfn_range), it); res = memfn_read[idx](phys_addr, length, data); } else - res = read_mem( phys_addr, length, data); + res = hart_mem_rd_delegate( phys_addr, length, data); } else { - res = read_mem( phys_addr, length, data); + res = hart_mem_rd_delegate( phys_addr, length, data); } if (unlikely(res != iss::Ok)){ this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault diff --git a/src/iss/arch/riscv_hart_msu_vp.h b/src/iss/arch/riscv_hart_msu_vp.h index f09ea99..5936329 100644 --- a/src/iss/arch/riscv_hart_msu_vp.h +++ b/src/iss/arch/riscv_hart_msu_vp.h @@ -845,7 +845,7 @@ template iss::status riscv_hart_msu_vp::write_reg(unsigned return iss::Ok; } -template iss::status riscv_hart_m_p::read_cycle(unsigned addr, reg_t &val) { +template iss::status riscv_hart_msu_vp::read_cycle(unsigned addr, reg_t &val) { auto cycle_val = this->icount + cycle_offset; if (addr == mcycle) { val = static_cast(cycle_val); @@ -856,7 +856,7 @@ template iss::status riscv_hart_m_p::read_cycle(unsigned a return iss::Ok; } -template iss::status riscv_hart_m_p::write_cycle(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_cycle(unsigned addr, reg_t val) { if (sizeof(typename traits::reg_t) != 4) { if (addr == mcycleh) return iss::Err; @@ -872,7 +872,7 @@ template iss::status riscv_hart_m_p::write_cycle(unsigned return iss::Ok; } -template iss::status riscv_hart_m_p::read_instret(unsigned addr, reg_t &val) { +template iss::status riscv_hart_msu_vp::read_instret(unsigned addr, reg_t &val) { if ((addr&0xff) == (minstret&0xff)) { val = static_cast(this->reg.instret); } else if ((addr&0xff) == (minstreth&0xff)) { @@ -882,7 +882,7 @@ template iss::status riscv_hart_m_p::read_instret(unsigned return iss::Ok; } -template iss::status riscv_hart_m_p::write_instret(unsigned addr, reg_t val) { +template iss::status riscv_hart_msu_vp::write_instret(unsigned addr, reg_t val) { if (sizeof(typename traits::reg_t) != 4) { if ((addr&0xff) == (minstreth&0xff)) return iss::Err; @@ -898,7 +898,7 @@ template iss::status riscv_hart_m_p::write_instret(unsigne return iss::Ok; } -template iss::status riscv_hart_m_p::read_time(unsigned addr, reg_t &val) { +template iss::status riscv_hart_msu_vp::read_time(unsigned addr, reg_t &val) { uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052; if (addr == time) { val = static_cast(time_val); @@ -909,7 +909,7 @@ template iss::status riscv_hart_m_p::read_time(unsigned ad return iss::Ok; } -template iss::status riscv_hart_m_p::read_tvec(unsigned addr, reg_t &val) { +template iss::status riscv_hart_msu_vp::read_tvec(unsigned addr, reg_t &val) { val = csr[addr] & ~2; return iss::Ok; } diff --git a/src/iss/arch/riscv_hart_mu_p.h b/src/iss/arch/riscv_hart_mu_p.h index 040999d..06c8830 100644 --- a/src/iss/arch/riscv_hart_mu_p.h +++ b/src/iss/arch/riscv_hart_mu_p.h @@ -449,6 +449,16 @@ protected: feature_config cfg; unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16}; inline bool debug_mode_active() {return this->reg.PRIV&0x4;} + + std::pair, std::function> + replace_mem_access(std::function rd, std::function wr){ + std::pair, std::function> ret{hart_mem_rd_delegate, hart_mem_wr_delegate}; + hart_mem_rd_delegate = rd; + hart_mem_wr_delegate = wr; + return ret; + } + std::function hart_mem_rd_delegate; + std::function hart_mem_wr_delegate; }; template @@ -612,6 +622,12 @@ riscv_hart_mu_p::riscv_hart_mu_p(feature_config cfg) csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr; csr_rd_cb[dcsr] = &this_class::read_dcsr_reg; } + hart_mem_rd_delegate = [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { + return this->read_mem(a, l, d); + }; + hart_mem_wr_delegate = [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { + return this->write_mem(a, l, d); + }; } template std::pair riscv_hart_mu_p::load_file(std::string name, int type) { @@ -829,9 +845,9 @@ iss::status riscv_hart_mu_p::read(const address_type type, const acc auto idx = std::distance(std::begin(memfn_range), it); res = memfn_read[idx](phys_addr, length, data); } else - res = read_mem( phys_addr, length, data); + res = hart_mem_rd_delegate( phys_addr, length, data); } else { - res = read_mem( phys_addr, length, data); + res = hart_mem_rd_delegate( phys_addr, length, data); } if (unlikely(res != iss::Ok)){ this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault @@ -930,9 +946,9 @@ iss::status riscv_hart_mu_p::write(const address_type type, const ac auto idx = std::distance(std::begin(memfn_range), it); res = memfn_write[idx]( phys_addr, length, data); } else - res = write_mem( phys_addr, length, data); + res = hart_mem_wr_delegate( phys_addr, length, data); } else { - res = write_mem( phys_addr, length, data); + res = hart_mem_wr_delegate( phys_addr, length, data); } if (unlikely(res != iss::Ok)) { this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault) diff --git a/src/iss/arch/wt_cache.h b/src/iss/arch/wt_cache.h new file mode 100644 index 0000000..d5acf3c --- /dev/null +++ b/src/iss/arch/wt_cache.h @@ -0,0 +1,172 @@ +/******************************************************************************* + * Copyright (C) 2023 MINRES Technologies GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Contributors: + * eyck@minres.com - initial implementation + ******************************************************************************/ + +#ifndef _RISCV_HART_M_P_WT_CACHE_H +#define _RISCV_HART_M_P_WT_CACHE_H + +#include +#include +#include +#include +#include + +namespace iss { +namespace arch { +namespace cache { + +enum class state { INVALID, VALID}; +struct line { + uint64_t tag_addr{0}; + state st{state::INVALID}; + std::vector data; + line(unsigned line_sz): data(line_sz) {} +}; +struct set { + std::vector ways; + set(unsigned ways_count, line const& l): ways(ways_count, l) {} +}; +struct cache { + std::vector sets; + + cache(unsigned size, unsigned line_sz, unsigned ways) { + line const ref_line{line_sz}; + set const ref_set{ways, ref_line}; + sets.resize(size/(ways*line_sz), ref_set); + } +}; + +struct wt_policy { + bool is_cacheline_hit(cache& c ); +}; +} + +// write thru, allocate on read, direct mapped or set-associative with round-robin replacement policy +template class wt_cache : public BASE { +public: + using base_class = BASE; + using this_class = wt_cache; + using reg_t = typename BASE::reg_t; + using mem_read_f = typename BASE::mem_read_f; + using mem_write_f = typename BASE::mem_write_f; + using phys_addr_t = typename BASE::phys_addr_t; + + wt_cache(); + virtual ~wt_cache() = default; + + unsigned size{4096}; + unsigned line_sz{32}; + unsigned ways{1}; + uint64_t io_address{0xf0000000}; + uint64_t io_addr_mask{0xf0000000}; +protected: + iss::status read_cache(phys_addr_t addr, unsigned, uint8_t *const); + iss::status write_cache(phys_addr_t addr, unsigned, uint8_t const *const); + std::function cache_mem_rd_delegate; + std::function cache_mem_wr_delegate; + std::unique_ptr dcache_ptr; + std::unique_ptr icache_ptr; + size_t get_way_select() { + return 0; + } +}; + + +template +inline wt_cache::wt_cache() { + auto cb = base_class::replace_mem_access( + [this](phys_addr_t a, unsigned l, uint8_t* const d) -> iss::status { return read_cache(a, l,d);}, + [this](phys_addr_t a, unsigned l, uint8_t const* const d) -> iss::status { return write_cache(a, l,d);}); + cache_mem_rd_delegate = cb.first; + cache_mem_wr_delegate = cb.second; +} + +template +iss::status iss::arch::wt_cache::read_cache(phys_addr_t a, unsigned l, uint8_t* const d) { + if(!icache_ptr) { + icache_ptr.reset(new cache::cache(size, line_sz, ways)); + dcache_ptr.reset(new cache::cache(size, line_sz, ways)); + } + if((a.val&io_addr_mask) != io_address) { + auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways); + auto tag_addr=a.val>>util::ilog2(line_sz); + auto& set = (a.access==access_type::FETCH?icache_ptr:dcache_ptr)->sets[set_addr]; + for(auto& cl: set.ways) { + if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) { + auto start_addr = a.val&(line_sz-1); + for(auto i = 0U; i +iss::status iss::arch::wt_cache::write_cache(phys_addr_t a, unsigned l, const uint8_t* const d) { + if(!dcache_ptr) + dcache_ptr.reset(new cache::cache(size, line_sz, ways)); + auto res = cache_mem_wr_delegate(a, l, d); + if(res == iss::Ok && ((a.val&io_addr_mask) != io_address)) { + auto set_addr=(a.val&(size-1))>>util::ilog2(line_sz*ways); + auto tag_addr=a.val>>util::ilog2(line_sz); + auto& set = dcache_ptr->sets[set_addr]; + for(auto& cl: set.ways) { + if(cl.st==cache::state::VALID && cl.tag_addr==tag_addr) { + auto start_addr = a.val&(line_sz-1); + for(auto i = 0U; i