15 memory_access_allocator(50, 30),
16 load_store_info_allocator(50, 30),
17 ldst_inst_queue_(
"lsu_inst_queue", p->ldst_inst_queue_size, getClock()),
18 ldst_inst_queue_size_(p->ldst_inst_queue_size),
20 tlb_always_hit_(p->tlb_always_hit),
21 dl1_always_hit_(p->dl1_always_hit),
23 issue_latency_(p->issue_latency),
24 mmu_latency_(p->mmu_latency),
25 cache_latency_(p->cache_latency),
26 complete_latency_(p->complete_latency)
41 in_biu_ack_.registerConsumerHandler
44 in_rob_retire_ack_.registerConsumerHandler
64 uev_cache_drive_biu_port_ >> uev_mmu_drive_biu_port_;
72 const uint64_t dl1_line_size = p->dl1_line_size;
73 const uint64_t dl1_size_kb = p->dl1_size_kb;
74 const uint64_t dl1_associativity = p->dl1_associativity;
75 std::unique_ptr<sparta::cache::ReplacementIF> repl(
new sparta::cache::TreePLRUReplacement
90 void LSU::sendInitialCredits_()
92 out_lsu_credits_.
send(ldst_inst_queue_size_);
96 info_logger_ <<
"LSU initial credits for Dispatch Unit: " << ldst_inst_queue_size_;
101 void LSU::getInstsFromDispatch_(
const ExampleInstPtr & inst_ptr)
104 MemoryAccessInfoPtr mem_info_ptr = sparta::allocate_sparta_shared_pointer<MemoryAccessInfo>(memory_access_allocator,
108 LoadStoreInstInfoPtr inst_info_ptr = sparta::allocate_sparta_shared_pointer<LoadStoreInstInfo>(load_store_info_allocator,
112 appendIssueQueue_(inst_info_ptr);
115 updateIssuePriorityAfterNewDispatch_(inst_ptr);
116 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
126 inst_ptr->setStatus(ExampleInst::Status::SCHEDULED);
141 void LSU::getAckFromBIU_(
const ExampleInstPtr & inst_ptr)
143 if (inst_ptr == mmu_pending_inst_ptr_) {
144 rehandleMMULookupReq_(inst_ptr);
146 else if (inst_ptr == cache_pending_inst_ptr_) {
147 rehandleCacheLookupReq_(inst_ptr);
155 void LSU::getAckFromROB_(
const ExampleInstPtr & inst_ptr)
157 sparta_assert(inst_ptr->getStatus() == ExampleInst::Status::RETIRED,
158 "Get ROB Ack, but the store inst hasn't retired yet!");
160 updateIssuePriorityAfterStoreInstRetire_(inst_ptr);
161 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
165 info_logger_ <<
"Get Ack from ROB! Retired store instruction: " << inst_ptr;
170 void LSU::issueInst_()
173 const LoadStoreInstInfoPtr & win_ptr = arbitrateInstIssue_();
179 ldst_pipeline_.
append(win_ptr->getMemoryAccessInfoPtr());
182 win_ptr->setState(LoadStoreInstInfo::IssueState::ISSUED);
183 win_ptr->setPriority(LoadStoreInstInfo::IssuePriority::LOWEST);
186 if (isReadyToIssueInsts_()) {
187 uev_issue_inst_.
schedule(sparta::Clock::Cycle(1));
192 info_logger_ <<
"Issue/Re-issue Instruction: " << win_ptr->getInstPtr();
197 void LSU::handleMMULookupReq_()
199 const auto stage_id =
static_cast<uint32_t
>(PipelineStage::MMU_LOOKUP);
202 if (!ldst_pipeline_.
isValid(stage_id)) {
207 const MemoryAccessInfoPtr & mem_access_info_ptr = ldst_pipeline_[stage_id];
208 bool isAlreadyHIT = (mem_access_info_ptr->getMMUState() == MemoryAccessInfo::MMUState::HIT);
209 bool MMUBypass = isAlreadyHIT;
214 info_logger_ <<
"MMU Lookup is skipped (TLB is already hit)!";
221 bool TLB_HIT = MMULookup_(mem_access_info_ptr);
225 mem_access_info_ptr->setMMUState(MemoryAccessInfo::MMUState::HIT);
227 mem_access_info_ptr->setPhyAddrStatus(
true);
231 mem_access_info_ptr->setMMUState(MemoryAccessInfo::MMUState::MISS);
233 if (mmu_busy_ ==
false) {
237 mmu_pending_inst_ptr_ = mem_access_info_ptr->getInstPtr();
245 uev_mmu_drive_biu_port_.
schedule(sparta::Clock::Cycle(0));
253 info_logger_ <<
"MMU is trying to drive BIU request port!";
260 <<
"MMU miss cannot be served right now due to another outstanding one!";
265 ldst_pipeline_.
invalidateStage(
static_cast<uint32_t
>(PipelineStage::MMU_LOOKUP));
270 void LSU::driveBIUPortFromMMU_()
272 bool succeed =
false;
275 if (!out_biu_req_.isDriven()) {
277 "Attempt to drive BIU port when no outstanding TLB miss exists!");
280 out_biu_req_.send(mmu_pending_inst_ptr_);
286 uev_mmu_drive_biu_port_.
schedule(sparta::Clock::Cycle(1));
295 info_logger_ <<
"MMU is waiting to drive the BIU request port!";
301 void LSU::handleCacheLookupReq_()
303 const auto stage_id =
static_cast<uint32_t
>(PipelineStage::CACHE_LOOKUP);
306 if (!ldst_pipeline_.
isValid(stage_id)) {
311 const MemoryAccessInfoPtr & mem_access_info_ptr = ldst_pipeline_[stage_id];
312 const ExampleInstPtr & inst_ptr = mem_access_info_ptr->getInstPtr();
314 const bool phyAddrIsReady =
315 mem_access_info_ptr->getPhyAddrStatus();
316 const bool isAlreadyHIT =
317 (mem_access_info_ptr->getCacheState() == MemoryAccessInfo::CacheState::HIT);
318 const bool isUnretiredStore =
319 inst_ptr->isStoreInst() && (inst_ptr->getStatus() != ExampleInst::Status::RETIRED);
320 const bool cacheBypass = isAlreadyHIT || !phyAddrIsReady || isUnretiredStore;
326 info_logger_ <<
"Cache Lookup is skipped (Cache already hit)!";
328 else if (!phyAddrIsReady) {
329 info_logger_ <<
"Cache Lookup is skipped (Physical address not ready)!";
331 else if (isUnretiredStore) {
332 info_logger_ <<
"Cache Lookup is skipped (Un-retired store instruction)!";
335 sparta_assert(
false,
"Cache access is bypassed without a valid reason!");
343 const bool CACHE_HIT = cacheLookup_(mem_access_info_ptr);
347 mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::HIT);
351 mem_access_info_ptr->setCacheState(MemoryAccessInfo::CacheState::MISS);
353 if (cache_busy_ ==
false) {
357 cache_pending_inst_ptr_ = mem_access_info_ptr->getInstPtr();
365 uev_cache_drive_biu_port_.
schedule(sparta::Clock::Cycle(0));
373 info_logger_ <<
"Cache is trying to drive BIU request port!";
379 info_logger_ <<
"Cache miss cannot be served right now due to another outstanding one!";
384 ldst_pipeline_.
invalidateStage(
static_cast<uint32_t
>(PipelineStage::CACHE_LOOKUP));
389 void LSU::driveBIUPortFromCache_()
391 bool succeed =
false;
394 if (!out_biu_req_.isDriven()) {
396 "Attempt to drive BIU port when no outstanding cache miss exists!");
399 out_biu_req_.send(cache_pending_inst_ptr_);
405 uev_cache_drive_biu_port_.
schedule(sparta::Clock::Cycle(1));
411 info_logger_ <<
"Cache is driving the BIU request port!";
414 info_logger_ <<
"Cache is waiting to drive the BIU request port!";
420 void LSU::completeInst_()
422 const auto stage_id =
static_cast<uint32_t
>(PipelineStage::COMPLETE);
425 if (!ldst_pipeline_.
isValid(stage_id)) {
430 const MemoryAccessInfoPtr & mem_access_info_ptr = ldst_pipeline_[stage_id];
431 const ExampleInstPtr & inst_ptr = mem_access_info_ptr->getInstPtr();
432 bool isStoreInst = inst_ptr->isStoreInst();
436 sparta_assert(mem_access_info_ptr->getCacheState() == MemoryAccessInfo::CacheState::HIT,
437 "Load instruction cannot complete when cache is still a miss!");
440 inst_ptr->setStatus(ExampleInst::Status::COMPLETED);
443 popIssueQueue_(inst_ptr);
446 out_lsu_credits_.
send(1, 0);
451 << inst_ptr->getMnemonic()
452 <<
" uid(" << inst_ptr->getUniqueID() <<
")";
460 if (inst_ptr->getStatus() != ExampleInst::Status::RETIRED) {
462 sparta_assert(mem_access_info_ptr->getMMUState() == MemoryAccessInfo::MMUState::HIT,
463 "Store instruction cannot complete when TLB is still a miss!");
466 inst_ptr->setStatus(ExampleInst::Status::COMPLETED);
471 << inst_ptr->getMnemonic()
472 <<
" uid(" << inst_ptr->getUniqueID() <<
")";
477 sparta_assert(mem_access_info_ptr->getCacheState() == MemoryAccessInfo::CacheState::HIT,
478 "Store inst cannot finish when cache is still a miss!");
481 popIssueQueue_(inst_ptr);
484 out_lsu_credits_.
send(1, 0);
501 void LSU::handleFlush_(
const FlushCriteria & criteria)
508 auto flush = [criteria] (
const uint64_t & id) ->
bool {
509 return id >=
static_cast<uint64_t
>(criteria);
513 flushLSPipeline_(flush);
516 if (mmu_busy_ && flush(mmu_pending_inst_ptr_->getUniqueID())) {
517 mmu_pending_inst_flushed =
true;
521 if (cache_busy_ && flush(cache_pending_inst_ptr_->getUniqueID())) {
522 cache_pending_inst_flushed_ =
true;
526 flushIssueQueue_(flush);
529 if (!isReadyToIssueInsts_()) {
546 void LSU::appendIssueQueue_(
const LoadStoreInstInfoPtr & inst_info_ptr)
549 "Appending issue queue causes overflows!");
552 ldst_inst_queue_.
push_back(inst_info_ptr);
556 info_logger_ <<
"Append new load/store instruction to issue queue!";
561 void LSU::popIssueQueue_(
const ExampleInstPtr & inst_ptr)
564 for (
auto iter = ldst_inst_queue_.
begin(); iter != ldst_inst_queue_.
end(); iter++) {
565 if ((*iter)->getInstPtr() == inst_ptr) {
566 ldst_inst_queue_.
erase(iter);
572 sparta_assert(
false,
"Attempt to complete instruction no longer exiting in issue queue!");
576 const LSU::LoadStoreInstInfoPtr & LSU::arbitrateInstIssue_()
578 sparta_assert(ldst_inst_queue_.
size() > 0,
"Arbitration fails: issue is empty!");
581 auto win_ptr_iter = ldst_inst_queue_.
begin();
584 for (
auto iter = ldst_inst_queue_.
begin(); iter != ldst_inst_queue_.
end(); iter++) {
586 if (!(*iter)->isReady()) {
591 if (!(*win_ptr_iter)->isReady() || (*iter)->winArb(*win_ptr_iter)) {
601 sparta_assert((*win_ptr_iter)->isReady(),
"Arbitration fails: no instruction is ready!");
603 return *win_ptr_iter;
607 bool LSU::isReadyToIssueInsts_()
const
609 bool isReady =
false;
612 for (
auto const &inst_info_ptr : ldst_inst_queue_) {
613 if (inst_info_ptr->isReady()) {
623 info_logger_ <<
"At least one more instruction is ready to be issued!";
626 info_logger_ <<
"No more instruction is ready to be issued!";
635 bool LSU::MMULookup_(
const MemoryAccessInfoPtr & mem_access_info_ptr)
637 const ExampleInstPtr & inst_ptr = mem_access_info_ptr->getInstPtr();
638 uint64_t vaddr = inst_ptr->getVAdr();
640 bool tlb_hit =
false;
643 if (tlb_hit = tlb_always_hit_, tlb_hit) {
646 auto tlb_entry = tlb_cache_->peekLine(vaddr);
647 tlb_hit = (tlb_entry !=
nullptr) && tlb_entry->isValid();
651 tlb_cache_->touch(*tlb_entry);
657 if (tlb_always_hit_) {
658 info_logger_ <<
"TLB HIT all the time: vaddr=0x" << std::hex << vaddr;
661 info_logger_ <<
"TLB HIT: vaddr=0x" << std::hex << vaddr;
664 info_logger_ <<
"TLB MISS: vaddr=0x" << std::hex << vaddr;
672 void LSU::rehandleMMULookupReq_(
const ExampleInstPtr & inst_ptr)
676 mmu_pending_inst_ptr_.
reset();
684 if (mmu_pending_inst_flushed) {
685 mmu_pending_inst_flushed =
false;
689 info_logger_ <<
"BIU Ack for a flushed MMU miss is received!";
695 updateIssuePriorityAfterTLBReload_(inst_ptr,
true);
696 if (isReadyToIssueInsts_()) {
697 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
704 info_logger_ <<
"BIU Ack for an outstanding MMU miss is received!";
708 reloadTLB_(inst_ptr->getVAdr());
711 updateIssuePriorityAfterTLBReload_(inst_ptr);
712 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
721 void LSU::reloadTLB_(uint64_t vaddr)
723 auto tlb_entry = &tlb_cache_->getLineForReplacementWithInvalidCheck(vaddr);
724 tlb_cache_->allocateWithMRUUpdate(*tlb_entry, vaddr);
733 bool LSU::cacheLookup_(
const MemoryAccessInfoPtr & mem_access_info_ptr)
735 const ExampleInstPtr & inst_ptr = mem_access_info_ptr->getInstPtr();
736 uint64_t phyAddr = inst_ptr->getRAdr();
738 bool cache_hit =
false;
740 if (dl1_always_hit_) {
744 auto cache_line = dl1_cache_->peekLine(phyAddr);
745 cache_hit = (cache_line !=
nullptr) && cache_line->isValid();
749 dl1_cache_->touchMRU(*cache_line);
755 if (dl1_always_hit_) {
756 info_logger_ <<
"DL1 Cache HIT all the time: phyAddr=0x" << std::hex << phyAddr;
758 else if (cache_hit) {
759 info_logger_ <<
"DL1 Cache HIT: phyAddr=0x" << std::hex << phyAddr;
762 info_logger_ <<
"DL1 Cache MISS: phyAddr=0x" << std::hex << phyAddr;
770 void LSU::rehandleCacheLookupReq_(
const ExampleInstPtr & inst_ptr)
774 cache_pending_inst_ptr_.
reset();
782 if (cache_pending_inst_flushed_) {
783 cache_pending_inst_flushed_ =
false;
786 info_logger_ <<
"BIU Ack for a flushed cache miss is received!";
792 updateIssuePriorityAfterCacheReload_(inst_ptr,
true);
793 if (isReadyToIssueInsts_()) {
794 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
802 info_logger_ <<
"BIU Ack for an outstanding cache miss is received!";
806 reloadCache_(inst_ptr->getRAdr());
809 updateIssuePriorityAfterCacheReload_(inst_ptr);
810 uev_issue_inst_.
schedule(sparta::Clock::Cycle(0));
819 void LSU::reloadCache_(uint64_t phyAddr)
821 auto dl1_cache_line = &dl1_cache_->getLineForReplacementWithInvalidCheck(phyAddr);
822 dl1_cache_->allocateWithMRUUpdate(*dl1_cache_line, phyAddr);
831 void LSU::updateIssuePriorityAfterNewDispatch_(
const ExampleInstPtr & inst_ptr)
833 for (
auto &inst_info_ptr : ldst_inst_queue_) {
834 if (inst_info_ptr->getInstPtr() == inst_ptr) {
836 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
837 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::NEW_DISP);
844 "Attempt to update issue priority for instruction not yet in the issue queue!");
848 void LSU::updateIssuePriorityAfterTLBReload_(
const ExampleInstPtr & inst_ptr,
849 const bool is_flushed_inst)
851 bool is_found =
false;
853 for (
auto &inst_info_ptr : ldst_inst_queue_) {
854 const MemoryAccessInfoPtr & mem_info_ptr = inst_info_ptr->getMemoryAccessInfoPtr();
856 if (mem_info_ptr->getMMUState() == MemoryAccessInfo::MMUState::MISS) {
858 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
859 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::MMU_PENDING);
865 if (inst_info_ptr->getInstPtr() == inst_ptr) {
867 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
868 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::MMU_RELOAD);
881 "Attempt to rehandle TLB lookup for instruction not yet in the issue queue!");
885 void LSU::updateIssuePriorityAfterCacheReload_(
const ExampleInstPtr & inst_ptr,
886 const bool is_flushed_inst)
888 bool is_found =
false;
890 for (
auto &inst_info_ptr : ldst_inst_queue_) {
891 const MemoryAccessInfoPtr & mem_info_ptr = inst_info_ptr->getMemoryAccessInfoPtr();
893 if (mem_info_ptr->getCacheState() == MemoryAccessInfo::CacheState::MISS) {
895 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
896 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::CACHE_PENDING);
902 if (inst_info_ptr->getInstPtr() == inst_ptr) {
904 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
905 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::CACHE_RELOAD);
918 "Attempt to rehandle cache lookup for instruction not yet in the issue queue!");
922 void LSU::updateIssuePriorityAfterStoreInstRetire_(
const ExampleInstPtr & inst_ptr)
924 for (
auto &inst_info_ptr : ldst_inst_queue_) {
925 if (inst_info_ptr->getInstPtr() == inst_ptr) {
927 inst_info_ptr->setState(LoadStoreInstInfo::IssueState::READY);
928 inst_info_ptr->setPriority(LoadStoreInstInfo::IssuePriority::CACHE_PENDING);
935 "Attempt to update issue priority for instruction not yet in the issue queue!");
940 template<
typename Comp>
941 void LSU::flushIssueQueue_(
const Comp & flush)
943 uint32_t credits_to_send = 0;
945 auto iter = ldst_inst_queue_.
begin();
946 while (iter != ldst_inst_queue_.
end()) {
947 auto inst_id = (*iter)->getInstPtr()->getUniqueID();
949 auto delete_iter = iter++;
951 if (flush(inst_id)) {
952 ldst_inst_queue_.
erase(delete_iter);
966 if (credits_to_send > 0) {
967 out_lsu_credits_.
send(credits_to_send);
971 info_logger_ <<
"Flush " << credits_to_send <<
" instructions in issue queue!";
977 template<
typename Comp>
978 void LSU::flushLSPipeline_(
const Comp & flush)
980 uint32_t stage_id = 0;
981 for (
auto iter = ldst_pipeline_.begin(); iter != ldst_pipeline_.end(); iter++, stage_id++) {
983 if (!iter.isValid()) {
987 auto inst_id = (*iter)->getInstPtr()->getUniqueID();
988 if (flush(inst_id)) {
994 <<
"], Instruction ID: " << inst_id;
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
#define CREATE_SPARTA_HANDLER_WITH_DATA(clname, meth, dataT)
#define CREATE_SPARTA_HANDLER(clname, meth)
Parameters for LSU model.
LSU(sparta::TreeNode *node, const LSUParameterSet *p)
Constructor for LSU.
static const char name[]
name of this resource.
void erase(uint32_t idx)
erase a position in the Buffer immediately.
size_type size() const
Return the number of valid entries.
iterator push_back(const value_type &dat)
Append data to the end of Buffer, and return a BufferIterator.
iterator begin()
Get the iterator pointing to the beginning of Buffer.
void enableCollection(TreeNode *parent)
Request that this queue begin collecting its contents for pipeline collection.
iterator end()
Returns an iterator referring to past-the-end element in the Buffer container.
void send(const DataT &dat, sparta::Clock::Cycle rel_time=0)
Send data to bound receivers.
void registerConsumerHandler(const SpartaHandler &handler)
Register a handler to this Port (must be Direction::IN) to handle data arrival.
bool observed() const noexcept
Is this NotificationSourceBase being observed at this node or an ancestor of any distance.
bool isValid(const uint32_t &stage_id) const
Indicate the validity of a specific pipeline stage.
void registerHandlerAtStage(const uint32_t &id, const SpartaHandler &handler)
Register event handler for a designated pipeline stage.
void append(const DataT &item)
Append data to the beginning of the pipeline.
void performOwnUpdates()
Ask pipeline to perform its own update.
void enableCollection(TreeNode *parent)
Enable pipeline collection.
void flushStage(const uint32_t &flush_stage_id)
Flush a specific stage of the pipeline using stage id.
void invalidateStage(const uint32_t &stage_id)
Invalidate a specific stage of the pipeline.
TreeNode * getContainer()
Gets the TreeNode (container) for this resource (if any)
void cancel()
Cancel all the times that this Scheduleable was placed on the Scheduler.
void reset(PointerT *p=nullptr)
Reset this shared pointer.
StartupEvent is a simple class for scheduling a starting event on the Scheduler. It does not support ...
Node in a composite tree representing a sparta Tree item.
group_idx_type getGroupIdx() const
Gets the group index of this node.
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
log::MessageSource info_logger_
Default info logger.
Macros for handling exponential backoff.