diff --git a/core/CacheFuncModel.hpp b/core/CacheFuncModel.hpp index 61f8e2e8..749fa1b1 100644 --- a/core/CacheFuncModel.hpp +++ b/core/CacheFuncModel.hpp @@ -59,7 +59,9 @@ namespace olympia bool isValid() const { return valid_; } // Required by SimpleCache2 - void setModified(bool m) { (void) m; } + void setModified(bool m) { modified_ = m; } + + bool isModified() const { return modified_; } // Required by SimpleCache2 bool read(uint64_t offset, uint32_t size, uint32_t *buf) const @@ -84,6 +86,7 @@ namespace olympia private: uint64_t line_size_ = 0; bool valid_ = false; + bool modified_ = false; }; // class SimpleCacheLine diff --git a/core/DCache.cpp b/core/DCache.cpp index af8f0e37..11b9fa40 100644 --- a/core/DCache.cpp +++ b/core/DCache.cpp @@ -1,29 +1,61 @@ #include "DCache.hpp" +#include "OlympiaAllocators.hpp" -namespace olympia { +namespace olympia +{ const char DCache::name[] = "cache"; - DCache::DCache(sparta::TreeNode *n, const CacheParameterSet *p) : - sparta::Unit(n), - l1_always_hit_(p->l1_always_hit), - cache_latency_(p->cache_latency) { + DCache::DCache(sparta::TreeNode* n, const CacheParameterSet* p) : + sparta::Unit(n), + l1_always_hit_(p->l1_always_hit), + cache_line_size_(p->l1_line_size), + num_mshr_entries_(p->mshr_entries), + mshr_file_("mshr_file", p->mshr_entries, getClock()), + mshr_entry_allocator_( + sparta::notNull(OlympiaAllocators::getOlympiaAllocators(n))->mshr_entry_allocator) + { + sparta_assert(num_mshr_entries_ > 0, "There must be atleast 1 MSHR entry"); + + in_lsu_lookup_req_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(DCache, receiveMemReqFromLSU_, MemoryAccessInfoPtr)); + + in_l2cache_resp_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(DCache, receiveRespFromL2Cache_, MemoryAccessInfoPtr)); + + in_l2cache_ack_.registerConsumerHandler( + CREATE_SPARTA_HANDLER_WITH_DATA(DCache, receiveAckFromL2Cache_, uint32_t)); - in_lsu_lookup_req_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(DCache, getInstsFromLSU_, MemoryAccessInfoPtr)); + in_lsu_lookup_req_.registerConsumerEvent(in_l2_cache_resp_receive_event_); + in_l2cache_resp_.registerConsumerEvent(in_l2_cache_resp_receive_event_); + setupL1Cache_(p); - in_l2cache_ack_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(DCache, getAckFromL2Cache_, uint32_t)); + // Pipeline config + cache_pipeline_.enableCollection(n); + cache_pipeline_.performOwnUpdates(); + cache_pipeline_.setContinuing(true); - in_l2cache_resp_.registerConsumerHandler - (CREATE_SPARTA_HANDLER_WITH_DATA(DCache, getRespFromL2Cache_, MemoryAccessInfoPtr)); + // Pipeline Handlers + cache_pipeline_.registerHandlerAtStage(static_cast(PipelineStage::LOOKUP), + CREATE_SPARTA_HANDLER(DCache, handleLookup_)); + + cache_pipeline_.registerHandlerAtStage(static_cast(PipelineStage::DATA_READ), + CREATE_SPARTA_HANDLER(DCache, handleDataRead_)); + + cache_pipeline_.registerHandlerAtStage(static_cast(PipelineStage::DEALLOCATE), + CREATE_SPARTA_HANDLER(DCache, handleDeallocate_)); + + mshr_file_.enableCollection(n); + } - // DL1 cache config + void DCache::setupL1Cache_(const CacheParameterSet* p) + { // DL1 cache config const uint32_t l1_line_size = p->l1_line_size; const uint32_t l1_size_kb = p->l1_size_kb; const uint32_t l1_associativity = p->l1_associativity; - std::unique_ptr repl(new sparta::cache::TreePLRUReplacement - (l1_associativity)); + std::unique_ptr repl( + new sparta::cache::TreePLRUReplacement(l1_associativity)); l1_cache_.reset(new CacheFuncModel(getContainer(), l1_size_kb, l1_line_size, *repl)); + addr_decoder_ = l1_cache_->getAddrDecoder(); } // Reload cache line @@ -35,7 +67,7 @@ namespace olympia { ILOG("DCache reload complete!"); } - // Access DCache + // Access L1Cache bool DCache::dataLookup_(const MemoryAccessInfoPtr & mem_access_info_ptr) { const InstPtr & inst_ptr = mem_access_info_ptr->getInstPtr(); @@ -43,28 +75,34 @@ namespace olympia { bool cache_hit = false; - if (l1_always_hit_) { + if (l1_always_hit_) + { cache_hit = true; } - else { + else + { auto cache_line = l1_cache_->peekLine(phyAddr); cache_hit = (cache_line != nullptr) && cache_line->isValid(); // Update MRU replacement state if DCache HIT - if (cache_hit) { + if (cache_hit) + { l1_cache_->touchMRU(*cache_line); } } - if (l1_always_hit_) { + if (l1_always_hit_) + { ILOG("DL1 DCache HIT all the time: phyAddr=0x" << std::hex << phyAddr); dl1_cache_hits_++; } - else if (cache_hit) { + else if (cache_hit) + { ILOG("DL1 DCache HIT: phyAddr=0x" << std::hex << phyAddr); dl1_cache_hits_++; } - else { + else + { ILOG("DL1 DCache MISS: phyAddr=0x" << std::hex << phyAddr); dl1_cache_misses_++; } @@ -72,34 +110,190 @@ namespace olympia { return cache_hit; } - void DCache::getInstsFromLSU_(const MemoryAccessInfoPtr &memory_access_info_ptr){ - const bool hit = dataLookup_(memory_access_info_ptr); - if(hit){ - memory_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::HIT); - }else{ - memory_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::MISS); - // Poll on dcache_l2cache_credits_ > 0 which means - // that L2Cache can accept requests from DCache. - // Provide a corresponsing backpressure mechanism up the pipeline. - if(!busy_) { - busy_ = true; - cache_pending_inst_ = memory_access_info_ptr; - out_l2cache_req_.send(cache_pending_inst_); - - // Set the --dcache_l2cache_credits_ here. + // The lookup stage + void DCache::handleLookup_() + { + ILOG("Lookup stage"); + const auto stage_id = static_cast(PipelineStage::LOOKUP); + const MemoryAccessInfoPtr & mem_access_info_ptr = cache_pipeline_[stage_id]; + ILOG(mem_access_info_ptr << " in Lookup stage"); + // If the mem request is a refill we dont do anything in the lookup stage + if (mem_access_info_ptr->isRefill()) + { + ILOG("Incoming cache refill " << mem_access_info_ptr); + return; + } + + const bool hit = dataLookup_(mem_access_info_ptr); + ILOG(mem_access_info_ptr << " performing lookup " << hit); + if (hit) + { + mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::HIT); + out_lsu_lookup_ack_.send(mem_access_info_ptr); + return; + } + + // Check MSHR Entries for address match + const auto & mshr_itb = mem_access_info_ptr->getMSHRInfoIterator(); + + if (!mshr_itb.isValid() && mshr_file_.numFree() == 0) + { + // Should be Nack but miss should work for now + mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::MISS); + out_lsu_lookup_ack_.send(mem_access_info_ptr); + return; + } + + if (!mshr_itb.isValid()) + { + if (!mem_access_info_ptr->getMSHRInfoIterator().isValid()) + { + ILOG("Creating new MSHR Entry " << mem_access_info_ptr); + allocateMSHREntry_(mem_access_info_ptr); } } + + const auto & mshr_it = mem_access_info_ptr->getMSHRInfoIterator(); + const uint64_t block_addr = getBlockAddr(mem_access_info_ptr); + const bool data_arrived = (*mshr_it)->isDataArrived(); + const bool is_store_inst = mem_access_info_ptr->getInstPtr()->isStoreInst(); + + // All ST are considered Hit + if (is_store_inst) + { + // Update Line fill buffer only if ST + ILOG("Write to Line fill buffer (ST), block address:0x" << std::hex << block_addr); + (*mshr_it)->setModified(true); + (*mshr_it)->setMemRequest(mem_access_info_ptr); + mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::HIT); + } + else if (data_arrived) + { + ILOG("Hit on Line fill buffer (LD), block address:0x" << std::hex << block_addr); + mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::HIT); + } + else + { + // Enqueue Load in LMQ + ILOG("Load miss inst to LMQ; block address:0x" << std::hex << block_addr); + (*mshr_it)->setMemRequest(mem_access_info_ptr); + mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::MISS); + } + out_lsu_lookup_ack_.send(mem_access_info_ptr); + } + + uint64_t DCache::getBlockAddr(const MemoryAccessInfoPtr & mem_access_info_ptr) const + { + const InstPtr & inst_ptr = mem_access_info_ptr->getInstPtr(); + const auto & inst_target_addr = inst_ptr->getRAdr(); + return addr_decoder_->calcBlockAddr(inst_target_addr); + } + + // Data read stage + void DCache::handleDataRead_() + { + ILOG("Data Read stage"); + const auto stage_id = static_cast(PipelineStage::DATA_READ); + const MemoryAccessInfoPtr & mem_access_info_ptr = cache_pipeline_[stage_id]; + ILOG(mem_access_info_ptr << " in read stage"); + if (mem_access_info_ptr->isRefill()) + { + reloadCache_(mem_access_info_ptr->getPhyAddr()); + return; + } + + if (mem_access_info_ptr->isCacheHit()) + { + mem_access_info_ptr->setDataReady(true); + } + else + { + if (!l2cache_busy_) + { + out_l2cache_req_.send(mem_access_info_ptr); + l2cache_busy_ = true; + } + else + { + uev_mshr_request_.schedule(sparta::Clock::Cycle(1)); + } + } + out_lsu_lookup_ack_.send(mem_access_info_ptr); + } + + void DCache::mshrRequest_() + { + ILOG("Send mshr req"); + if (!l2cache_busy_) + { + auto iter = mshr_file_.begin(); + while (iter != mshr_file_.end()) + { + + if (iter.isValid()) + { + const auto & mshr_entry = *iter; + auto mem_info = mshr_entry->getMemRequest(); + if (mshr_entry->isValid() && !mshr_entry->isDataArrived() && mem_info) + { + ILOG("Sending mshr request when not busy " << mem_info); + out_l2cache_req_.send(mem_info); + l2cache_busy_ = true; + break; + } + } + ++iter; + } + } + } + + void DCache::handleDeallocate_() + { + ILOG("Data Dellocate stage"); + const auto stage_id = static_cast(PipelineStage::DEALLOCATE); + const MemoryAccessInfoPtr & mem_access_info_ptr = cache_pipeline_[stage_id]; + ILOG(mem_access_info_ptr << " in deallocate stage"); + if (mem_access_info_ptr->isRefill()) + { + const auto & mshr_it = mem_access_info_ptr->getMSHRInfoIterator(); + if (mshr_it.isValid()) + { + MemoryAccessInfoPtr dependant_load_inst = (*mshr_it)->getMemRequest(); + out_lsu_lookup_ack_.send(dependant_load_inst); + + ILOG("Removing mshr entry for " << mem_access_info_ptr); + mshr_file_.erase(mem_access_info_ptr->getMSHRInfoIterator()); + } + return; + } + ILOG("Deallocating pipeline for " << mem_access_info_ptr); + } + + void DCache::receiveMemReqFromLSU_(const MemoryAccessInfoPtr & memory_access_info_ptr) + { + ILOG("Received memory access request from LSU " << memory_access_info_ptr); out_lsu_lookup_ack_.send(memory_access_info_ptr); + in_l2_cache_resp_receive_event_.schedule(); + lsu_mem_access_info_ = memory_access_info_ptr; } - void DCache::getRespFromL2Cache_(const MemoryAccessInfoPtr &memory_access_info_ptr) { - out_lsu_lookup_req_.send(cache_pending_inst_); - reloadCache_(memory_access_info_ptr->getPhyAddr()); - cache_pending_inst_.reset(); - busy_ = false; + void DCache::receiveRespFromL2Cache_(const MemoryAccessInfoPtr & memory_access_info_ptr) + { + ILOG("Received cache refill " << memory_access_info_ptr); + // We mark the mem access to refill, this could be moved to the lower level caches later + memory_access_info_ptr->setIsRefill(true); + l2_mem_access_info_ = memory_access_info_ptr; + const auto & mshr_itb = memory_access_info_ptr->getMSHRInfoIterator(); + if(mshr_itb.isValid()){ + ILOG("Removing mshr entry for " << memory_access_info_ptr); + mshr_file_.erase(memory_access_info_ptr->getMSHRInfoIterator()); + } + l2cache_busy_ = false; + in_l2_cache_resp_receive_event_.schedule(); } - void DCache::getAckFromL2Cache_(const uint32_t &ack) { + void DCache::receiveAckFromL2Cache_(const uint32_t & ack) + { // When DCache sends the request to L2Cache for a miss, // This bool will be set to false, and Dcache should wait for ack from // L2Cache notifying DCache that there is space in it's dcache request buffer @@ -108,4 +302,16 @@ namespace olympia { dcache_l2cache_credits_ = ack; } -} + // MSHR Entry allocation in case of miss + void DCache::allocateMSHREntry_(const MemoryAccessInfoPtr & mem_access_info_ptr) + { + sparta_assert(mshr_file_.size() <= num_mshr_entries_, "Appending mshr causes overflows!"); + + MSHREntryInfoPtr mshr_entry = sparta::allocate_sparta_shared_pointer( + mshr_entry_allocator_, cache_line_size_, getClock()); + + const auto & it = mshr_file_.push_back(mshr_entry); + mem_access_info_ptr->setMSHREntryInfoIterator(it); + } + +} // namespace olympia diff --git a/core/DCache.hpp b/core/DCache.hpp index e5982cbd..36d0349d 100644 --- a/core/DCache.hpp +++ b/core/DCache.hpp @@ -1,14 +1,16 @@ #pragma once -#include "sparta/simulation/Unit.hpp" #include "sparta/ports/DataPort.hpp" #include "sparta/ports/SignalPort.hpp" +#include "sparta/resources/Pipeline.hpp" #include "sparta/simulation/ParameterSet.hpp" +#include "sparta/simulation/Unit.hpp" #include "sparta/utils/LogUtils.hpp" #include "CacheFuncModel.hpp" #include "Inst.hpp" #include "cache/TreePLRUReplacement.hpp" #include "MemoryAccessInfo.hpp" +#include "MSHREntryInfo.hpp" namespace olympia { @@ -24,31 +26,69 @@ namespace olympia PARAMETER(uint32_t, l1_line_size, 64, "DL1 line size (power of 2)") PARAMETER(uint32_t, l1_size_kb, 32, "Size of DL1 in KB (power of 2)") PARAMETER(uint32_t, l1_associativity, 8, "DL1 associativity (power of 2)") - PARAMETER(uint32_t, cache_latency, 1, "Assumed latency of the memory system") PARAMETER(bool, l1_always_hit, false, "DL1 will always hit") + PARAMETER(uint32_t, mshr_entries, 8, "Number of MSHR Entries") }; static const char name[]; DCache(sparta::TreeNode* n, const CacheParameterSet* p); private: + //////////////////////////////////////////////////////////////////////////////// + // L1 Data Cache Handling + //////////////////////////////////////////////////////////////////////////////// + using L1Handle = CacheFuncModel::Handle; + L1Handle l1_cache_; + const bool l1_always_hit_; + const uint64_t cache_line_size_; + const sparta::cache::AddrDecoderIF* addr_decoder_; + // Keep track of the instruction that causes current outstanding cache miss + // MemoryAccessInfoPtr cache_pending_inst_ = nullptr; + + const uint32_t num_mshr_entries_; + + void setupL1Cache_(const CacheParameterSet* p); + bool dataLookup_(const MemoryAccessInfoPtr & mem_access_info_ptr); void reloadCache_(uint64_t phy_addr); - void getInstsFromLSU_(const MemoryAccessInfoPtr & memory_access_info_ptr); + uint64_t getBlockAddr(const MemoryAccessInfoPtr & mem_access_info_ptr) const; - void getAckFromL2Cache_(const uint32_t & ack); + using MSHREntryInfoPtr = sparta::SpartaSharedPointer; + using MSHREntryIterator = sparta::Buffer::const_iterator; + // Ongoing Refill request + MSHREntryIterator current_refill_mshr_entry_; - void getRespFromL2Cache_(const MemoryAccessInfoPtr & memory_access_info_ptr); + // Cache Pipeline + enum class PipelineStage + { + LOOKUP = 0, + DATA_READ = 1, + DEALLOCATE = 2, + NUM_STAGES + }; - using L1Handle = CacheFuncModel::Handle; - L1Handle l1_cache_; - const bool l1_always_hit_; - bool busy_ = false; - uint32_t cache_latency_ = 0; - // Keep track of the instruction that causes current outstanding cache miss - MemoryAccessInfoPtr cache_pending_inst_ = nullptr; + sparta::Pipeline cache_pipeline_{ + "DCachePipeline", static_cast(PipelineStage::NUM_STAGES), getClock()}; + + void handleLookup_(); + void handleDataRead_(); + void handleDeallocate_(); + + //////////////////////////////////////////////////////////////////////////////// + // Handle requests + //////////////////////////////////////////////////////////////////////////////// + + void receiveMemReqFromLSU_(const MemoryAccessInfoPtr & memory_access_info_ptr); + + void receiveAckFromL2Cache_(const uint32_t & ack); + + void receiveRespFromL2Cache_(const MemoryAccessInfoPtr & memory_access_info_ptr); + + void mshrRequest_(); + + bool l2cache_busy_ = false; // Credit bool for sending miss request to L2Cache uint32_t dcache_l2cache_credits_ = 0; @@ -57,12 +97,12 @@ namespace olympia // Input Ports //////////////////////////////////////////////////////////////////////////////// sparta::DataInPort in_lsu_lookup_req_{&unit_port_set_, - "in_lsu_lookup_req", 0}; + "in_lsu_lookup_req", 1}; sparta::DataInPort in_l2cache_ack_{&unit_port_set_, "in_l2cache_ack", 1}; - sparta::DataInPort in_l2cache_resp_{&unit_port_set_, - "in_l2cache_resp", 1}; + sparta::DataInPort in_l2cache_resp_{&unit_port_set_, "in_l2cache_resp", + 1}; //////////////////////////////////////////////////////////////////////////////// // Output Ports @@ -81,6 +121,40 @@ namespace olympia //////////////////////////////////////////////////////////////////////////////// // Events //////////////////////////////////////////////////////////////////////////////// + sparta::UniqueEvent<> uev_mshr_request_{&unit_event_set_, "mshr_request", + CREATE_SPARTA_HANDLER(DCache, mshrRequest_)}; + + sparta::utils::ValidValue l2_mem_access_info_; + sparta::utils::ValidValue lsu_mem_access_info_; + + void arbitrateL2LsuReq_() + { + if (l2_mem_access_info_.isValid()) + { + auto mem_access_info_ptr = l2_mem_access_info_.getValue(); + ILOG("Received Refill request " << mem_access_info_ptr); + cache_pipeline_.append(mem_access_info_ptr); + } + else + { + auto mem_access_info_ptr = lsu_mem_access_info_.getValue(); + ILOG("Received LSU request " << mem_access_info_ptr); + cache_pipeline_.append(mem_access_info_ptr); + } + if (l2_mem_access_info_.isValid()) + { + l2_mem_access_info_.clearValid(); + } + if (lsu_mem_access_info_.isValid()) + { + lsu_mem_access_info_.clearValid(); + } + uev_mshr_request_.schedule(1); + } + + sparta::UniqueEvent<> in_l2_cache_resp_receive_event_{ + &unit_event_set_, "in_l2_cache_resp_receive_event", + CREATE_SPARTA_HANDLER(DCache, arbitrateL2LsuReq_)}; //////////////////////////////////////////////////////////////////////////////// // Counters @@ -91,6 +165,14 @@ namespace olympia sparta::Counter dl1_cache_misses_{getStatisticSet(), "dl1_cache_misses", "Number of DL1 cache misses", sparta::Counter::COUNT_NORMAL}; + + sparta::StatisticDef dl1_hit_miss_ratio_{getStatisticSet(), "dl1_hit_miss_ratio", + "DL1 HIT/MISS Ratio", getStatisticSet(), + "dl1_cache_hits/dl1_cache_misses"}; + + sparta::Buffer mshr_file_; + MSHREntryInfoAllocator & mshr_entry_allocator_; + void allocateMSHREntry_(const MemoryAccessInfoPtr & mem_access_info_ptr); }; } // namespace olympia diff --git a/core/LSU.cpp b/core/LSU.cpp index edc45eeb..2324cddd 100644 --- a/core/LSU.cpp +++ b/core/LSU.cpp @@ -518,7 +518,34 @@ namespace olympia out_cache_lookup_req_.send(mem_access_info_ptr); } - void LSU::getAckFromCache_(const MemoryAccessInfoPtr & updated_memory_access_info_ptr) {} + void LSU::getAckFromCache_(const MemoryAccessInfoPtr & mem_access_info_ptr) + { + const LoadStoreInstIterator & iter = mem_access_info_ptr->getIssueQueueIterator(); + if (!iter.isValid()) + { + return; + } + + // Is its a cache miss we dont need to rechedule the instruction + if (!mem_access_info_ptr->isCacheHit()) + { + return; + } + + const LoadStoreInstInfoPtr & inst_info_ptr = *(iter); + + // Update issue priority for this outstanding cache miss + if (inst_info_ptr->getState() != LoadStoreInstInfo::IssueState::ISSUED) + { + inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY); + } + + inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::CACHE_RELOAD); + if (!inst_info_ptr->isInReadyQueue()) + { + uev_append_ready_.preparePayload(inst_info_ptr)->schedule(sparta::Clock::Cycle(0)); + } + } void LSU::handleCacheReadyReq_(const MemoryAccessInfoPtr & memory_access_info_ptr) { diff --git a/core/MSHREntryInfo.hpp b/core/MSHREntryInfo.hpp new file mode 100644 index 00000000..f2e37845 --- /dev/null +++ b/core/MSHREntryInfo.hpp @@ -0,0 +1,44 @@ +#pragma once + +#include "CacheFuncModel.hpp" + +namespace olympia +{ + class MSHREntryInfo + { + public: + MSHREntryInfo(const uint64_t & line_size, const sparta::Clock* clock) : + line_fill_buffer_(line_size) + { + line_fill_buffer_.setValid(true); + } + + ~MSHREntryInfo() {} + + SimpleCacheLine & getLineFillBuffer() { return line_fill_buffer_; } + + bool isValid() const { return line_fill_buffer_.isValid(); } + + void setValid(bool v) { line_fill_buffer_.setValid(v); } + + bool isModified() const { return line_fill_buffer_.isModified(); } + + void setModified(bool m) { line_fill_buffer_.setModified(m); } + + void setDataArrived(bool v) { data_arrived_ = v; } + + bool isDataArrived() { return data_arrived_; } + + void setMemRequest(const MemoryAccessInfoPtr & new_memory_access_info) + { + memory_access_info_ = new_memory_access_info; + } + + MemoryAccessInfoPtr & getMemRequest() { return memory_access_info_; } + + private: + SimpleCacheLine line_fill_buffer_; + MemoryAccessInfoPtr memory_access_info_; + bool data_arrived_ = false; + }; +} // namespace olympia \ No newline at end of file diff --git a/core/MemoryAccessInfo.hpp b/core/MemoryAccessInfo.hpp index 50a04b31..f0d2cf6b 100644 --- a/core/MemoryAccessInfo.hpp +++ b/core/MemoryAccessInfo.hpp @@ -17,10 +17,15 @@ namespace olympia class MemoryAccessInfoPairDef; class MemoryAccessInfo; + class MSHREntryInfo; using MemoryAccessInfoPtr = sparta::SpartaSharedPointer; using MemoryAccessInfoAllocator = sparta::SpartaSharedPointerAllocator; + using MSHREntryInfoPtr = sparta::SpartaSharedPointer; + using MSHREntryInfoIterator = sparta::Buffer::const_iterator; + using MSHREntryInfoAllocator = sparta::SpartaSharedPointerAllocator; + class MemoryAccessInfo { public: @@ -75,6 +80,7 @@ namespace olympia // Construct the State object here cache_access_state_(CacheState::NO_ACCESS), cache_data_ready_(false), + is_refill_(false), src_(ArchUnit::NO_ACCESS), dest_(ArchUnit::NO_ACCESS) { @@ -136,6 +142,10 @@ namespace olympia const LoadStoreInstIterator getIssueQueueIterator() const { return issue_queue_iterator_; } + bool isRefill() const { return is_refill_; } + + void setIsRefill(bool is_refill) { is_refill_ = is_refill; } + void setIssueQueueIterator(const LoadStoreInstIterator & iter) { issue_queue_iterator_ = iter; @@ -151,6 +161,16 @@ namespace olympia replay_queue_iterator_ = iter; } + const MSHREntryInfoIterator & getMSHRInfoIterator() const + { + return mshr_entry_info_iterator_; + } + + void setMSHREntryInfoIterator(const MSHREntryInfoIterator & iter) + { + mshr_entry_info_iterator_ = iter; + } + private: // load/store instruction pointer InstPtr ldst_inst_ptr_; @@ -165,6 +185,8 @@ namespace olympia CacheState cache_access_state_; bool cache_data_ready_; + + bool is_refill_; // Src and destination unit name for the packet ArchUnit src_ = ArchUnit::NO_ACCESS; ArchUnit dest_ = ArchUnit::NO_ACCESS; @@ -176,6 +198,7 @@ namespace olympia LoadStoreInstIterator issue_queue_iterator_; LoadStoreInstIterator replay_queue_iterator_; + MSHREntryInfoIterator mshr_entry_info_iterator_; }; using MemoryAccessInfoPtr = sparta::SpartaSharedPointer; diff --git a/docs/dcache.md b/docs/dcache.md new file mode 100644 index 00000000..107a29c7 --- /dev/null +++ b/docs/dcache.md @@ -0,0 +1,51 @@ +# DCACHE + +### Ports + + +in_lsu_lookup_req <-- Input from LSU ( Receive memory request ) + +in_l2cache_ack <-- Input from L2Cache ( Receive acknowledgement from cache ) + +in_l2cache_resp <-- Input from L2Cache ( Receive data for the l2 cache lookup request) + +out_lsu_free_req <-- Output to LSU ( Send cache available for requests signal ) + +out_lsu_lookup_ack <-- Output to LSU ( Send acknowledgement for the memory reques to the LSU ) + +out_lsu_lookup_req <-- Output to LSU ( Send data for the LSU memory request ) + +out_l2cache_req <-- Output to L2Cache ( Send dirty cacheline to L2cache ) + +### Configuration parameters + +`l1_line_size` - Size of the DL1 cache line (power of 2) + +`l1_size_kb` - Size of DL1 in KB (power of 2) + +`l1_associativity` - DL1 associativity (power of 2) + +`l1_always_hit` - DL1 will always hit + +`mshr_entries` - Number of MSHR Entries + +### Available counters +`dl1_cache_hits` - Number of DL1 cache hits + +`dl1_cache_misses` - Number of DL1 cache misses + +`dl1_hit_miss_ratio` - Ratio between the DL1 HIT/MISS + +### Microarchitecture +The dcache has configurable number of mshr entries to handle requests in a non blocking manner. + +The Dcache arbitrates requests from LSU and cache refill response from L2 Cache. +The Dcache prioritizes cache refill request over incoming memory requests from the LSU. + +The Dcache has one only pipeline with 3 different stages + +| Stage | Cache Refill | Memory lookup request | +|------------|-------------------------------------------------|-------------------------| +| LOOKUP | Do nothing | Create MSHR entry | +| DATA READ | Update cache with refill information | Send L2 request if miss | +| DEALLOCATE | Deallocate mshr entries linked to the cacheline | Do nothing | diff --git a/sim/OlympiaAllocators.hpp b/sim/OlympiaAllocators.hpp index 5f408973..38b05281 100644 --- a/sim/OlympiaAllocators.hpp +++ b/sim/OlympiaAllocators.hpp @@ -13,6 +13,7 @@ #include "Inst.hpp" #include "LoadStoreInstInfo.hpp" #include "MemoryAccessInfo.hpp" +#include "MSHREntryInfo.hpp" namespace olympia { @@ -54,8 +55,9 @@ namespace olympia InstArchInfoAllocator inst_arch_info_allocator{3000, 2500}; // For LSU/MSS - LoadStoreInstInfoAllocator load_store_info_allocator{128, 80}; - MemoryAccessInfoAllocator memory_access_allocator {128, 80}; + LoadStoreInstInfoAllocator load_store_info_allocator{128, 80}; + MemoryAccessInfoAllocator memory_access_allocator {128, 80}; + MSHREntryInfoAllocator mshr_entry_allocator {300, 150}; }; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e4364e7a..f715dbd5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,5 +33,6 @@ add_subdirectory(core/rename) add_subdirectory(core/lsu) add_subdirectory(core/issue_queue) add_subdirectory(core/branch_pred) +add_subdirectory(core/dcache) add_subdirectory(core/vector) add_subdirectory(fusion) diff --git a/test/core/dcache/CMakeLists.txt b/test/core/dcache/CMakeLists.txt new file mode 100644 index 00000000..a8bce09d --- /dev/null +++ b/test/core/dcache/CMakeLists.txt @@ -0,0 +1,12 @@ +project(Dcache_test) + +add_executable(Dcache_test Dcache_test.cpp) + +target_link_libraries(Dcache_test core common_test mss ${STF_LINK_LIBS} SPARTA::sparta) +file(CREATE_LINK ${SIM_BASE}/mavis/json ${CMAKE_CURRENT_BINARY_DIR}/mavis_isa_files SYMBOLIC) +file(CREATE_LINK ${SIM_BASE}/arches ${CMAKE_CURRENT_BINARY_DIR}/arches SYMBOLIC) +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/test_arches ${CMAKE_CURRENT_BINARY_DIR}/test_arches SYMBOLIC) +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/expected_output ${CMAKE_CURRENT_BINARY_DIR}/expected_output SYMBOLIC) +file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/next_lvl_cache_refill.json ${CMAKE_CURRENT_BINARY_DIR}/next_lvl_cache_refill.json SYMBOLIC) + +sparta_named_test(Dcache_test_arbitrate Dcache_test arbitrate.out -c test_arches/1_src_Dcache.yaml --input-file next_lvl_cache_refill.json) \ No newline at end of file diff --git a/test/core/dcache/Dcache_test.cpp b/test/core/dcache/Dcache_test.cpp new file mode 100644 index 00000000..42101d04 --- /dev/null +++ b/test/core/dcache/Dcache_test.cpp @@ -0,0 +1,151 @@ + +#include "DCache.hpp" +#include +#include +#include "sparta/utils/SpartaTester.hpp" +#include "test/core/dcache/NextLvlSourceSinkUnit.hpp" +#include "test/core/dcache/SourceUnit.hpp" +#include "sparta/utils/LogUtils.hpp" +#include "OlympiaAllocators.hpp" + +class DCacheSim : public sparta::app::Simulation +{ + public: + DCacheSim(sparta::Scheduler* sched, const std::string & mavis_isa_files, + const std::string & mavis_uarch_files, const std::string & output_file, + const std::string & input_file) : + sparta::app::Simulation("DCacheSim", sched), + input_file_(input_file), + test_tap_(getRoot(), "info", output_file) + { + } + + ~DCacheSim() { getRoot()->enterTeardown(); } + + void runRaw(uint64_t run_time) override final + { + (void)run_time; + + sparta::app::Simulation::runRaw(run_time); + } + + private: + void buildTree_() override + { + auto rtn = getRoot(); + + allocators_tn_.reset(new olympia::OlympiaAllocators(rtn)); + + sparta::ResourceTreeNode* mavis = new sparta::ResourceTreeNode( + rtn, olympia::MavisUnit::name, sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "Mavis Unit", &mavis_fact); + tns_to_delete_.emplace_back(mavis); + + // Create a Source Units that represents DCache and ICache + sparta::ResourceTreeNode* Test_Lsu = + new sparta::ResourceTreeNode(rtn, "lsu", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "lsu", &lsu_fact); + + Test_Lsu->getParameterSet()->getParameter("input_file")->setValueFromString(input_file_); + tns_to_delete_.emplace_back(Test_Lsu); + + sparta::ResourceTreeNode* Test_DCache = + new sparta::ResourceTreeNode(rtn, "dcache", sparta::TreeNode::GROUP_NAME_NONE, + sparta::TreeNode::GROUP_IDX_NONE, "dcache", &dcache_fact); + tns_to_delete_.emplace_back(Test_DCache); + + sparta::ResourceTreeNode* Test_Next_Lvl = new sparta::ResourceTreeNode( + rtn, "next_lvl", sparta::TreeNode::GROUP_NAME_NONE, sparta::TreeNode::GROUP_IDX_NONE, + "next_lvl", &next_lvl_fact); + tns_to_delete_.emplace_back(Test_Next_Lvl); + } + + void configureTree_() override {} + + void bindTree_() override + { + auto* root_node = getRoot(); + + sparta::bind(root_node->getChildAs("lsu.ports.out_source_req"), + root_node->getChildAs("dcache.ports.in_lsu_lookup_req")); + sparta::bind(root_node->getChildAs("lsu.ports.in_source_resp"), + root_node->getChildAs("dcache.ports.out_lsu_lookup_req")); + sparta::bind(root_node->getChildAs("lsu.ports.in_source_ack"), + root_node->getChildAs("dcache.ports.out_lsu_lookup_ack")); + + sparta::bind(root_node->getChildAs("next_lvl.ports.in_biu_req"), + root_node->getChildAs("dcache.ports.out_l2cache_req")); + sparta::bind(root_node->getChildAs("next_lvl.ports.out_biu_resp"), + root_node->getChildAs("dcache.ports.in_l2cache_resp")); + sparta::bind(root_node->getChildAs("next_lvl.ports.out_biu_ack"), + root_node->getChildAs("dcache.ports.in_l2cache_ack")); + } + + std::unique_ptr allocators_tn_; + + sparta::ResourceFactory + lsu_fact; + + sparta::ResourceFactory dcache_fact; + + sparta::ResourceFactory + next_lvl_fact; + + olympia::MavisFactory mavis_fact; + std::vector> tns_to_delete_; + + const std::string input_file_; + sparta::log::Tap test_tap_; +}; + +const char USAGE[] = "Usage:\n" + " \n" + "\n"; +sparta::app::DefaultValues DEFAULTS; + +void runTest(int argc, char** argv) +{ + DEFAULTS.auto_summary_default = "off"; + std::vector datafiles; + std::string input_file; + + sparta::app::CommandLineSimulator cls(USAGE, DEFAULTS); + auto & app_opts = cls.getApplicationOptions(); + app_opts.add_options()( + "output_file", + sparta::app::named_value>("output_file", &datafiles), + "Specifies the output file")( + "input-file", + sparta::app::named_value("INPUT_FILE", &input_file)->default_value(""), + "Provide a JSON instruction stream", + "Provide a JSON file with instructions to run through Execute"); + + po::positional_options_description & pos_opts = cls.getPositionalOptions(); + pos_opts.add("output_file", -1); // example, look for the at the end + + int err_code = 0; + if (!cls.parse(argc, argv, err_code)) + { + sparta_assert(false, "Command line parsing failed"); // Any errors already printed to cerr + } + + sparta_assert(false == datafiles.empty(), + "Need an output file as the last argument of the test"); + + sparta::Scheduler sched; + DCacheSim dcache_sim(&sched, "mavis_isa_files", "arches/isa_json", datafiles[0], input_file); + + cls.populateSimulation(&dcache_sim); + + cls.runSimulator(&dcache_sim); + + EXPECT_FILES_EQUAL(datafiles[0], "expected_output/" + datafiles[0] + ".EXPECTED"); +} + +int main(int argc, char** argv) +{ + runTest(argc, argv); + REPORT_ERROR; + return (int)ERROR_CODE; +} diff --git a/test/core/dcache/NextLvlSourceSinkUnit.hpp b/test/core/dcache/NextLvlSourceSinkUnit.hpp new file mode 100644 index 00000000..e808370f --- /dev/null +++ b/test/core/dcache/NextLvlSourceSinkUnit.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include +#include "sparta/utils/SpartaSharedPointer.hpp" +#include "sparta/simulation/TreeNode.hpp" +#include "sparta/utils/LogUtils.hpp" +#include "core/MemoryAccessInfo.hpp" +#include "core/MavisUnit.hpp" + +namespace dcache_test +{ + class NextLvlSourceSinkUnit : public sparta::Unit + { + public: + static constexpr char name[] = "NextLvlSourceSinkUnit"; + + class NextLvlSinkUnitParameters : public sparta::ParameterSet + { + public: + explicit NextLvlSinkUnitParameters(sparta::TreeNode* n) : sparta::ParameterSet(n) {} + PARAMETER(std::string, purpose, "grp", "Purpose of this SinkUnit: grp, single") + PARAMETER(sparta::Clock::Cycle, sink_latency, 1, "Latency of this SinkUnit") + }; + + NextLvlSourceSinkUnit(sparta::TreeNode* n, const NextLvlSinkUnitParameters* params) : + sparta::Unit(n) + { + + purpose_ = params->purpose; + sink_latency_ = params->sink_latency; + + in_biu_req_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + NextLvlSourceSinkUnit, sinkInst_, olympia::MemoryAccessInfoPtr)); + } + + private: + void sinkInst_(const olympia::MemoryAccessInfoPtr & mem_access_info_ptr) + { + ILOG("Instruction: '" << mem_access_info_ptr->getInstPtr() << "' sinked"); + + out_biu_resp_.send(mem_access_info_ptr, 2 * sink_latency_); + } + + sparta::DataInPort in_biu_req_{ + &unit_port_set_, "in_biu_req", sparta::SchedulingPhase::Tick, 1}; + sparta::DataOutPort out_biu_resp_{&unit_port_set_, + "out_biu_resp"}; + sparta::DataOutPort out_biu_ack_{&unit_port_set_, "out_biu_ack"}; + + std::string purpose_; + sparta::Clock::Cycle sink_latency_; + }; +} // namespace dcache_test \ No newline at end of file diff --git a/test/core/dcache/SourceUnit.hpp b/test/core/dcache/SourceUnit.hpp new file mode 100644 index 00000000..d5e1a345 --- /dev/null +++ b/test/core/dcache/SourceUnit.hpp @@ -0,0 +1,123 @@ +#pragma once + +#include "sparta/utils/LogUtils.hpp" +#include "core/MemoryAccessInfo.hpp" +#include "core/InstGenerator.hpp" +#include "sparta/utils/LogUtils.hpp" + +namespace dcache_test +{ + class SourceUnit : public sparta::Unit + { + public: + static constexpr char name[] = "SourceUnit"; + + class SourceUnitParameters : public sparta::ParameterSet + { + public: + explicit SourceUnitParameters(sparta::TreeNode* n) : sparta::ParameterSet(n) {} + PARAMETER(std::string, input_file, "", "Input file: STF or JSON") + PARAMETER(sparta::Clock::Cycle, delay_btwn_insts, 1, + "Clock delay between instruction/requests to DCache") + }; + + SourceUnit(sparta::TreeNode* n, const SourceUnitParameters* params) : + sparta::Unit(n), + mavis_facade_(olympia::getMavis(n)), + delay_btwn_insts_(params->delay_btwn_insts) + { + + sparta_assert(mavis_facade_ != nullptr, "Could not find the Mavis Unit"); + + in_source_resp_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + SourceUnit, ReceiveInst_, olympia::MemoryAccessInfoPtr)); + in_source_ack_.registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA( + SourceUnit, ReceiveAck_, olympia::MemoryAccessInfoPtr)); + + if (params->input_file != "") + { + inst_generator_ = olympia::InstGenerator::createGenerator( + mavis_facade_, params->input_file, false); + } + + sparta::StartupEvent(n, CREATE_SPARTA_HANDLER(SourceUnit, sendInitialInst_)); + } + + ~SourceUnit() {} + + void onStartingTeardown_() override {} + + private: + void sendInitialInst_() { injectInsts_(); } + + void injectInsts_() + { + olympia::InstPtr dinst; + + if (inst_generator_) + { + + while (!inst_generator_->isDone()) + { + + dinst = inst_generator_->getNextInst(getClock()); + dinst->setUniqueID(unique_id_++); + + olympia::MemoryAccessInfoPtr mem_info_ptr(new olympia::MemoryAccessInfo(dinst)); + + req_inst_queue_.emplace_back(mem_info_ptr); + ev_req_inst_.schedule(schedule_time_); + + schedule_time_ += delay_btwn_insts_; + } + } + } + + void req_inst_() + { + + ILOG("Instruction: '" << req_inst_queue_.front()->getInstPtr() << "' Requested"); + + pending_reqs_++; + pending_acks_++; + + out_source_req_.send(req_inst_queue_.front()); + req_inst_queue_.erase(req_inst_queue_.begin()); + } + + void ReceiveInst_(const olympia::MemoryAccessInfoPtr & mem_info_ptr) + { + pending_reqs_--; + ILOG("Instruction: '" << mem_info_ptr->getInstPtr() << "' Received"); + } + + void ReceiveAck_(const olympia::MemoryAccessInfoPtr & mem_info_ptr) + { + pending_acks_--; + ILOG("Ack: '" << mem_info_ptr << "' Received"); + } + + sparta::DataInPort in_source_resp_{ + &unit_port_set_, "in_source_resp", sparta::SchedulingPhase::Tick, 1}; + sparta::DataInPort in_source_ack_{&unit_port_set_, + "in_source_ack"}; + + sparta::DataOutPort out_source_req_{&unit_port_set_, + "out_source_req"}; + + uint32_t pending_acks_ = 1; + uint32_t pending_reqs_ = 0; + + uint32_t unique_id_ = 0; + + olympia::MavisType* mavis_facade_ = nullptr; + std::unique_ptr inst_generator_; + + sparta::UniqueEvent<> ev_req_inst_{&unit_event_set_, "req_inst", + CREATE_SPARTA_HANDLER(SourceUnit, req_inst_)}; + + std::vector req_inst_queue_; + sparta::Clock::Cycle schedule_time_ = 0; + sparta::Clock::Cycle delay_btwn_insts_ = 0; + }; +} // namespace dcache_test \ No newline at end of file diff --git a/test/core/dcache/expected_output/arbitrate.out.EXPECTED b/test/core/dcache/expected_output/arbitrate.out.EXPECTED new file mode 100644 index 00000000..12179a3c --- /dev/null +++ b/test/core/dcache/expected_output/arbitrate.out.EXPECTED @@ -0,0 +1,41 @@ +#Name: +#Cmdline: +#Exe: +#SimulatorVersion: +#Repro: +#Start: Wednesday Wed Jul 31 16:59:06 2024 +#Elapsed: 0.002178s +{0000000000 00000000 top.lsu info} req_inst_: Instruction: 'uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' ' Requested +{0000000001 00000001 top.dcache info} receiveMemReqFromLSU_: Received memory access request from LSU memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000001 00000001 top.lsu info} ReceiveAck_: Ack: 'memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' ' Received +{0000000001 00000001 top.dcache info} arbitrateL2LsuReq_: Received LSU request memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000002 00000002 top.dcache info} mshrRequest_: Send mshr req +{0000000002 00000002 top.dcache info} handleLookup_: Lookup stage +{0000000002 00000002 top.dcache info} handleLookup_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in Lookup stage +{0000000002 00000002 top.dcache info} dataLookup_: DL1 DCache MISS: phyAddr=0xdeadbeef +{0000000002 00000002 top.dcache info} handleLookup_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' performing lookup 0 +{0000000002 00000002 top.dcache info} handleLookup_: Creating new MSHR Entry memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000002 00000002 top.dcache info} handleLookup_: Load miss inst to LMQ; block address:0xdeadbee0 +{0000000002 00000002 top.lsu info} ReceiveAck_: Ack: 'memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' ' Received +{0000000003 00000003 top.dcache info} handleDataRead_: Data Read stage +{0000000003 00000003 top.dcache info} handleDataRead_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in read stage +{0000000003 00000003 top.lsu info} ReceiveAck_: Ack: 'memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' ' Received +{0000000004 00000004 top.next_lvl info} sinkInst_: Instruction: 'uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' ' sinked +{0000000004 00000004 top.dcache info} handleDeallocate_: Data Dellocate stage +{0000000004 00000004 top.dcache info} handleDeallocate_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in deallocate stage +{0000000004 00000004 top.dcache info} handleDeallocate_: Deallocating pipeline for memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000008 00000008 top.lsu info} req_inst_: Instruction: 'uid: 1 FETCHED 0 pid: 2 uopid: 0 'lw 5,3' ' Requested +{0000000009 00000009 top.dcache info} receiveRespFromL2Cache_: Received cache refill memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000009 00000009 top.dcache info} receiveRespFromL2Cache_: Removing mshr entry for memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000009 00000009 top.dcache info} receiveMemReqFromLSU_: Received memory access request from LSU memptr: uid: 1 FETCHED 0 pid: 2 uopid: 0 'lw 5,3' +{0000000009 00000009 top.dcache info} arbitrateL2LsuReq_: Received Refill request memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000009 00000009 top.lsu info} ReceiveAck_: Ack: 'memptr: uid: 1 FETCHED 0 pid: 2 uopid: 0 'lw 5,3' ' Received +{0000000010 00000010 top.dcache info} mshrRequest_: Send mshr req +{0000000010 00000010 top.dcache info} handleLookup_: Lookup stage +{0000000010 00000010 top.dcache info} handleLookup_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in Lookup stage +{0000000010 00000010 top.dcache info} handleLookup_: Incoming cache refill memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' +{0000000011 00000011 top.dcache info} handleDataRead_: Data Read stage +{0000000011 00000011 top.dcache info} handleDataRead_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in read stage +{0000000011 00000011 top.dcache info} reloadCache_: DCache reload complete! +{0000000012 00000012 top.dcache info} handleDeallocate_: Data Dellocate stage +{0000000012 00000012 top.dcache info} handleDeallocate_: memptr: uid: 0 FETCHED 0 pid: 1 uopid: 0 'lw 5,3' in deallocate stage diff --git a/test/core/dcache/next_lvl_cache_refill.json b/test/core/dcache/next_lvl_cache_refill.json new file mode 100644 index 00000000..4633535c --- /dev/null +++ b/test/core/dcache/next_lvl_cache_refill.json @@ -0,0 +1,14 @@ +[ + { + "mnemonic": "lw", + "rs1": 3, + "rd": 5, + "vaddr" : "0xdeadbeef" + }, + { + "mnemonic": "lw", + "rs1": 3, + "rd": 5, + "vaddr" : "0xdeedbeef" + } +] \ No newline at end of file diff --git a/test/core/dcache/test_arches/1_src_Dcache.yaml b/test/core/dcache/test_arches/1_src_Dcache.yaml new file mode 100644 index 00000000..1f728dea --- /dev/null +++ b/test/core/dcache/test_arches/1_src_Dcache.yaml @@ -0,0 +1,14 @@ +top: + lsu: + params: + delay_btwn_insts: 8 + dcache: + params: + l1_size_kb: 64 + l1_line_size: 32 + l1_associativity: 8 + l1_always_hit: false + mshr_entries: 8 + next_lvl: + params: + sink_latency: 2 diff --git a/test/core/lsu/Lsu_test.cpp b/test/core/lsu/Lsu_test.cpp index def392ec..a4dfe5dd 100644 --- a/test/core/lsu/Lsu_test.cpp +++ b/test/core/lsu/Lsu_test.cpp @@ -110,7 +110,7 @@ void runTest(int argc, char **argv) cls.runSimulator(&sim, 7); lsupipe_tester.test_inst_issue(*my_lsu, 2); // Loads operand dependency meet cls.runSimulator(&sim, 52); - lsupipe_tester.test_replay_issue_abort(*my_lsu, 2); // Loads operand dependency meet + lsupipe_tester.test_replay_issue_abort(*my_lsu, 3); // Loads operand dependency meet cls.runSimulator(&sim); }