adds WT cache functionality as mixin
This commit is contained in:
parent
00b0f101ac
commit
1672b01e62
|
@ -422,6 +422,15 @@ protected:
|
||||||
feature_config cfg;
|
feature_config cfg;
|
||||||
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
||||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
|
||||||
|
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
|
||||||
|
hart_mem_rd_delegate = rd;
|
||||||
|
hart_mem_wr_delegate = wr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::function<mem_read_f> hart_mem_rd_delegate;
|
||||||
|
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
|
@ -543,6 +552,12 @@ riscv_hart_m_p<BASE, FEAT>::riscv_hart_m_p(feature_config cfg)
|
||||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
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 <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
|
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_m_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||||
|
@ -663,9 +678,9 @@ iss::status riscv_hart_m_p<BASE, FEAT>::read(const address_type type, const acce
|
||||||
auto idx = std::distance(std::begin(memfn_range), it);
|
auto idx = std::distance(std::begin(memfn_range), it);
|
||||||
res = memfn_read[idx](phys_addr, length, data);
|
res = memfn_read[idx](phys_addr, length, data);
|
||||||
} else
|
} else
|
||||||
res = read_mem( phys_addr, length, data);
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
} else {
|
} else {
|
||||||
res = read_mem( phys_addr, length, data);
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
}
|
}
|
||||||
if (unlikely(res != iss::Ok)){
|
if (unlikely(res != iss::Ok)){
|
||||||
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
|
|
|
@ -845,7 +845,7 @@ template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_reg(unsigned
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_cycle(unsigned addr, reg_t &val) {
|
||||||
auto cycle_val = this->icount + cycle_offset;
|
auto cycle_val = this->icount + cycle_offset;
|
||||||
if (addr == mcycle) {
|
if (addr == mcycle) {
|
||||||
val = static_cast<reg_t>(cycle_val);
|
val = static_cast<reg_t>(cycle_val);
|
||||||
|
@ -856,7 +856,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_cycle(unsigned a
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_cycle(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if (addr == mcycleh)
|
if (addr == mcycleh)
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
|
@ -872,7 +872,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_cycle(unsigned
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_instret(unsigned addr, reg_t &val) {
|
||||||
if ((addr&0xff) == (minstret&0xff)) {
|
if ((addr&0xff) == (minstret&0xff)) {
|
||||||
val = static_cast<reg_t>(this->reg.instret);
|
val = static_cast<reg_t>(this->reg.instret);
|
||||||
} else if ((addr&0xff) == (minstreth&0xff)) {
|
} else if ((addr&0xff) == (minstreth&0xff)) {
|
||||||
|
@ -882,7 +882,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_instret(unsigned
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigned addr, reg_t val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::write_instret(unsigned addr, reg_t val) {
|
||||||
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
if (sizeof(typename traits<BASE>::reg_t) != 4) {
|
||||||
if ((addr&0xff) == (minstreth&0xff))
|
if ((addr&0xff) == (minstreth&0xff))
|
||||||
return iss::Err;
|
return iss::Err;
|
||||||
|
@ -898,7 +898,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::write_instret(unsigne
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_time(unsigned addr, reg_t &val) {
|
||||||
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
uint64_t time_val = this->icount / (100000000 / 32768 - 1); //-> ~3052;
|
||||||
if (addr == time) {
|
if (addr == time) {
|
||||||
val = static_cast<reg_t>(time_val);
|
val = static_cast<reg_t>(time_val);
|
||||||
|
@ -909,7 +909,7 @@ template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_time(unsigned ad
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename BASE> iss::status riscv_hart_m_p<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
template <typename BASE> iss::status riscv_hart_msu_vp<BASE>::read_tvec(unsigned addr, reg_t &val) {
|
||||||
val = csr[addr] & ~2;
|
val = csr[addr] & ~2;
|
||||||
return iss::Ok;
|
return iss::Ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -449,6 +449,16 @@ protected:
|
||||||
feature_config cfg;
|
feature_config cfg;
|
||||||
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
unsigned mcause_max_irq{(FEAT&features_e::FEAT_CLIC)?4096:16};
|
||||||
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
inline bool debug_mode_active() {return this->reg.PRIV&0x4;}
|
||||||
|
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>>
|
||||||
|
replace_mem_access(std::function<mem_read_f> rd, std::function<mem_write_f> wr){
|
||||||
|
std::pair<std::function<mem_read_f>, std::function<mem_write_f>> ret{hart_mem_rd_delegate, hart_mem_wr_delegate};
|
||||||
|
hart_mem_rd_delegate = rd;
|
||||||
|
hart_mem_wr_delegate = wr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
std::function<mem_read_f> hart_mem_rd_delegate;
|
||||||
|
std::function<mem_write_f> hart_mem_wr_delegate;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename BASE, features_e FEAT>
|
template <typename BASE, features_e FEAT>
|
||||||
|
@ -612,6 +622,12 @@ riscv_hart_mu_p<BASE, FEAT>::riscv_hart_mu_p(feature_config cfg)
|
||||||
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
csr_wr_cb[dcsr] = &this_class::write_dcsr_dcsr;
|
||||||
csr_rd_cb[dcsr] = &this_class::read_dcsr_reg;
|
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 <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
|
template <typename BASE, features_e FEAT> std::pair<uint64_t, bool> riscv_hart_mu_p<BASE, FEAT>::load_file(std::string name, int type) {
|
||||||
|
@ -829,9 +845,9 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::read(const address_type type, const acc
|
||||||
auto idx = std::distance(std::begin(memfn_range), it);
|
auto idx = std::distance(std::begin(memfn_range), it);
|
||||||
res = memfn_read[idx](phys_addr, length, data);
|
res = memfn_read[idx](phys_addr, length, data);
|
||||||
} else
|
} else
|
||||||
res = read_mem( phys_addr, length, data);
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
} else {
|
} else {
|
||||||
res = read_mem( phys_addr, length, data);
|
res = hart_mem_rd_delegate( phys_addr, length, data);
|
||||||
}
|
}
|
||||||
if (unlikely(res != iss::Ok)){
|
if (unlikely(res != iss::Ok)){
|
||||||
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
this->trap_state = (1UL << 31) | (5 << 16); // issue trap 5 (load access fault
|
||||||
|
@ -930,9 +946,9 @@ iss::status riscv_hart_mu_p<BASE, FEAT>::write(const address_type type, const ac
|
||||||
auto idx = std::distance(std::begin(memfn_range), it);
|
auto idx = std::distance(std::begin(memfn_range), it);
|
||||||
res = memfn_write[idx]( phys_addr, length, data);
|
res = memfn_write[idx]( phys_addr, length, data);
|
||||||
} else
|
} else
|
||||||
res = write_mem( phys_addr, length, data);
|
res = hart_mem_wr_delegate( phys_addr, length, data);
|
||||||
} else {
|
} else {
|
||||||
res = write_mem( phys_addr, length, data);
|
res = hart_mem_wr_delegate( phys_addr, length, data);
|
||||||
}
|
}
|
||||||
if (unlikely(res != iss::Ok)) {
|
if (unlikely(res != iss::Ok)) {
|
||||||
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
this->trap_state = (1UL << 31) | (7 << 16); // issue trap 7 (Store/AMO access fault)
|
||||||
|
|
|
@ -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 <iss/vm_types.h>
|
||||||
|
#include <util/ities.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace arch {
|
||||||
|
namespace cache {
|
||||||
|
|
||||||
|
enum class state { INVALID, VALID};
|
||||||
|
struct line {
|
||||||
|
uint64_t tag_addr{0};
|
||||||
|
state st{state::INVALID};
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
line(unsigned line_sz): data(line_sz) {}
|
||||||
|
};
|
||||||
|
struct set {
|
||||||
|
std::vector<line> ways;
|
||||||
|
set(unsigned ways_count, line const& l): ways(ways_count, l) {}
|
||||||
|
};
|
||||||
|
struct cache {
|
||||||
|
std::vector<set> 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 <typename BASE> class wt_cache : public BASE {
|
||||||
|
public:
|
||||||
|
using base_class = BASE;
|
||||||
|
using this_class = wt_cache<BASE>;
|
||||||
|
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<mem_read_f> cache_mem_rd_delegate;
|
||||||
|
std::function<mem_write_f> cache_mem_wr_delegate;
|
||||||
|
std::unique_ptr<cache::cache> dcache_ptr;
|
||||||
|
std::unique_ptr<cache::cache> icache_ptr;
|
||||||
|
size_t get_way_select() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
inline wt_cache<BASE>::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<typename BASE>
|
||||||
|
iss::status iss::arch::wt_cache<BASE>::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<l; ++i)
|
||||||
|
d[i] = cl.data[start_addr+i];
|
||||||
|
return iss::Ok;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto& cl = set.ways[get_way_select()];
|
||||||
|
phys_addr_t cl_addr{a};
|
||||||
|
cl_addr.val=tag_addr<<util::ilog2(line_sz);
|
||||||
|
cache_mem_rd_delegate(cl_addr, line_sz, cl.data.data());
|
||||||
|
cl.tag_addr=tag_addr;
|
||||||
|
cl.st=cache::state::VALID;
|
||||||
|
auto start_addr = a.val&(line_sz-1);
|
||||||
|
for(auto i = 0U; i<l; ++i)
|
||||||
|
d[i] = cl.data[start_addr+i];
|
||||||
|
return iss::Ok;
|
||||||
|
} else
|
||||||
|
return cache_mem_rd_delegate(a, l, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename BASE>
|
||||||
|
iss::status iss::arch::wt_cache<BASE>::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<l; ++i)
|
||||||
|
cl.data[start_addr+1] = d[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace arch
|
||||||
|
} // namespace iss
|
||||||
|
|
||||||
|
#endif /* _RISCV_HART_M_P_H */
|
Loading…
Reference in New Issue