The Sparta Modeling Framework
Loading...
Searching...
No Matches
LSU.hpp
1
2#pragma once
3
16#include "sparta/pairs/SpartaKeyPairs.hpp"
17#include "sparta/simulation/State.hpp"
19#include "sparta/utils/SpartaSharedPointerAllocator.hpp"
20
21#include "cache/TreePLRUReplacement.hpp"
22
23#include "CoreTypes.hpp"
24#include "FlushManager.hpp"
25#include "SimpleTLB.hpp"
26#include "SimpleDL1.hpp"
27
28namespace core_example
29{
30 class LSU : public sparta::Unit
31 {
32 public:
38 {
39 public:
45
46 // Parameters for ldst_inst_queue
47 PARAMETER(uint32_t, ldst_inst_queue_size, 8, "LSU ldst inst queue size")
48 // Parameters for the TLB cache
49 PARAMETER(bool, tlb_always_hit, false, "L1 TLB will always hit")
50 // Parameters for the DL1 cache
51 PARAMETER(uint64_t, dl1_line_size, 64, "DL1 line size (power of 2)")
52 PARAMETER(uint64_t, dl1_size_kb, 32, "Size of DL1 in KB (power of 2)")
53 PARAMETER(uint64_t, dl1_associativity, 8, "DL1 associativity (power of 2)")
54 PARAMETER(bool, dl1_always_hit, false, "DL1 will always hit")
55 // Parameters for event scheduling
56 PARAMETER(uint32_t, issue_latency, 1, "Instruction issue latency")
57 PARAMETER(uint32_t, mmu_latency, 1, "MMU/TLB access latency")
58 PARAMETER(uint32_t, cache_latency, 1, "Cache access latency")
59 PARAMETER(uint32_t, complete_latency, 1, "Instruction complete latency")
60 };
61
67 LSU(sparta::TreeNode* node, const LSUParameterSet* p);
68
69 ~LSU() {
71 << ": "
72 << load_store_info_allocator.getNumAllocated()
73 << " LoadStoreInstInfo objects allocated/created"
74 << std::endl;
76 << ": "
77 << memory_access_allocator.getNumAllocated()
78 << " MemoryAccessInfo objects allocated/created"
79 << std::endl;
80 }
81
83 static const char name[];
84
85
87 // Type Name/Alias Declaration
89
90
92 class MemoryAccessInfo;
93
96 using FlushCriteria = FlushManager::FlushingCriteria;
97
98 enum class PipelineStage
99 {
100 MMU_LOOKUP = 0, //1,
101 CACHE_LOOKUP = 1, //3,
102 COMPLETE = 2, //4
103 NUM_STAGES
104 };
105
106 // Forward declaration of the Pair Definition class is must as we are friending it.
107 class MemoryAccessInfoPairDef;
108 // Keep record of memory access information in LSU
110 public:
111
112 // The modeler needs to alias a type called "SpartaPairDefinitionType" to the Pair Definition class of itself
114
115 enum class MMUState : std::uint32_t {
116 NO_ACCESS = 0,
117 __FIRST = NO_ACCESS,
118 MISS,
119 HIT,
120 NUM_STATES,
121 __LAST = NUM_STATES
122 };
123
124 enum class CacheState : std::uint64_t {
125 NO_ACCESS = 0,
126 __FIRST = NO_ACCESS,
127 MISS,
128 HIT,
129 NUM_STATES,
130 __LAST = NUM_STATES
131 };
132
133 MemoryAccessInfo() = delete;
134
135 MemoryAccessInfo(const ExampleInstPtr & inst_ptr) :
136 ldst_inst_ptr_(inst_ptr),
137 phyAddrIsReady_(false),
138 mmu_access_state_(MMUState::NO_ACCESS),
139
140 // Construct the State object here
141 cache_access_state_(CacheState::NO_ACCESS) {}
142
143 virtual ~MemoryAccessInfo() {}
144
145 // This ExampleInst pointer will act as our portal to the ExampleInst class
146 // and we will use this pointer to query values from functions of ExampleInst class
147 const ExampleInstPtr & getInstPtr() const { return ldst_inst_ptr_; }
148
149 // This is a function which will be added in the SPARTA_ADDPAIRs API.
150 uint64_t getInstUniqueID() const {
151 const ExampleInstPtr &inst_ptr = getInstPtr();
152
153 return inst_ptr == nullptr ? 0 : inst_ptr->getUniqueID();
154 }
155
156 void setPhyAddrStatus(bool isReady) { phyAddrIsReady_ = isReady; }
157 bool getPhyAddrStatus() const { return phyAddrIsReady_; }
158
159 const MMUState & getMMUState() const {
160 return mmu_access_state_.getEnumValue();
161 }
162
163 void setMMUState(const MMUState & state) {
164 mmu_access_state_.setValue(state);
165 }
166
167 const CacheState & getCacheState() const {
168 return cache_access_state_.getEnumValue();
169 }
170 void setCacheState(const CacheState & state) {
171 cache_access_state_.setValue(state);
172 }
173
174 // This is a function which will be added in the addArgs API.
175 bool getPhyAddrIsReady() const{
176 return phyAddrIsReady_;
177 }
178
179
180 private:
181 // load/store instruction pointer
182 ExampleInstPtr ldst_inst_ptr_;
183
184 // Indicate MMU address translation status
185 bool phyAddrIsReady_;
186
187 // MMU access status
188 sparta::State<MMUState> mmu_access_state_;
189
190 // Cache access status
191 sparta::State<CacheState> cache_access_state_;
192
193 }; // class MemoryAccessInfo
194
195 // allocator for this object type
197
203 // This is the definition of the PairDefinition class of MemoryAccessInfo.
204 // This PairDefinition class could be named anything but it needs to inherit
205 // publicly from sparta::PairDefinition templatized on the actual class MemoryAcccessInfo.
206 class MemoryAccessInfoPairDef : public sparta::PairDefinition<MemoryAccessInfo>{
207 public:
208
209 // The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
210 MemoryAccessInfoPairDef() : PairDefinition<MemoryAccessInfo>(){
211 SPARTA_INVOKE_PAIRS(MemoryAccessInfo);
212 }
213 SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &MemoryAccessInfo::getInstUniqueID),
214 SPARTA_ADDPAIR("valid", &MemoryAccessInfo::getPhyAddrIsReady),
215 SPARTA_ADDPAIR("mmu", &MemoryAccessInfo::getMMUState),
216 SPARTA_ADDPAIR("cache", &MemoryAccessInfo::getCacheState),
217 SPARTA_FLATTEN( &MemoryAccessInfo::getInstPtr))
218 };
219
220 // Forward declaration of the Pair Definition class is must as we are friending it.
222 // Keep record of instruction issue information
224 {
225 public:
226 // The modeler needs to alias a type called "SpartaPairDefinitionType" to the Pair Definition class of itself
228 enum class IssuePriority : std::uint16_t
229 {
230 HIGHEST = 0,
231 __FIRST = HIGHEST,
232 CACHE_RELOAD, // Receive mss ack, waiting for cache re-access
233 CACHE_PENDING, // Wait for another outstanding miss finish
234 MMU_RELOAD, // Receive for mss ack, waiting for mmu re-access
235 MMU_PENDING, // Wait for another outstanding miss finish
236 NEW_DISP, // Wait for new issue
237 LOWEST,
238 NUM_OF_PRIORITIES,
239 __LAST = NUM_OF_PRIORITIES
240 };
241
242 enum class IssueState : std::uint32_t
243 {
244 READY = 0, // Ready to be issued
245 __FIRST = READY,
246 ISSUED, // On the flight somewhere inside Load/Store Pipe
247 NOT_READY, // Not ready to be issued
248 NUM_STATES,
249 __LAST = NUM_STATES
250 };
251
252 LoadStoreInstInfo() = delete;
253 LoadStoreInstInfo(const MemoryAccessInfoPtr & info_ptr) :
254 mem_access_info_ptr_(info_ptr),
255 rank_(IssuePriority::LOWEST),
256 state_(IssueState::NOT_READY) {}
257
258 // This ExampleInst pointer will act as one of the two portals to the ExampleInst class
259 // and we will use this pointer to query values from functions of ExampleInst class
260 const ExampleInstPtr & getInstPtr() const {
261 return mem_access_info_ptr_->getInstPtr();
262 }
263
264 // This MemoryAccessInfo pointer will act as one of the two portals to the MemoryAccesInfo class
265 // and we will use this pointer to query values from functions of MemoryAccessInfo class
266 const MemoryAccessInfoPtr & getMemoryAccessInfoPtr() const {
267 return mem_access_info_ptr_;
268 }
269
270 // This is a function which will be added in the SPARTA_ADDPAIRs API.
271 uint64_t getInstUniqueID() const {
272 const MemoryAccessInfoPtr &mem_access_info_ptr = getMemoryAccessInfoPtr();
273
274 return mem_access_info_ptr == nullptr ? 0 : mem_access_info_ptr->getInstUniqueID();
275 }
276
277 void setPriority(const IssuePriority & rank) {
278 rank_.setValue(rank);
279 }
280
281 const IssuePriority & getPriority() const {
282 return rank_.getEnumValue();
283 }
284
285 void setState(const IssueState & state) {
286 state_.setValue(state);
287 }
288
289 const IssueState & getState() const {
290 return state_.getEnumValue();
291 }
292
293
294 bool isReady() const { return (getState() == IssueState::READY); }
295
296 bool winArb(const LoadStoreInstInfoPtr & that) const
297 {
298 if (that == nullptr) {
299 return true;
300 }
301
302 return (static_cast<uint32_t>(this->getPriority())
303 < static_cast<uint32_t>(that->getPriority()));
304 }
305
306 private:
307 MemoryAccessInfoPtr mem_access_info_ptr_;
310
311 }; // class LoadStoreInstInfo
312
314
319 // This is the definition of the PairDefinition class of LoadStoreInstInfo.
320 // This PairDefinition class could be named anything but it needs to inherit
321 // publicly from sparta::PairDefinition templatized on the actual class LoadStoreInstInfo.
322 class LoadStoreInstInfoPairDef : public sparta::PairDefinition<LoadStoreInstInfo>{
323 public:
324
325 // The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
326 LoadStoreInstInfoPairDef() : PairDefinition<LoadStoreInstInfo>(){
327 SPARTA_INVOKE_PAIRS(LoadStoreInstInfo);
328 }
329 SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &LoadStoreInstInfo::getInstUniqueID),
330 SPARTA_ADDPAIR("rank", &LoadStoreInstInfo::getPriority),
331 SPARTA_ADDPAIR("state", &LoadStoreInstInfo::getState),
332 SPARTA_FLATTEN( &LoadStoreInstInfo::getMemoryAccessInfoPtr))
333 };
334
335 void setTLB(SimpleTLB& tlb)
336 {
337 tlb_cache_ = &tlb;
338 }
339 private:
341 // Input Ports
344 {&unit_port_set_, "in_lsu_insts", 1};
345
347 {&unit_port_set_, "in_biu_ack", 1};
348
349 sparta::DataInPort<ExampleInstPtr> in_rob_retire_ack_
350 {&unit_port_set_, "in_rob_retire_ack", 1};
351
352 sparta::DataInPort<FlushCriteria> in_reorder_flush_
353 {&unit_port_set_, "in_reorder_flush", sparta::SchedulingPhase::Flush, 1};
354
355
357 // Output Ports
359 sparta::DataOutPort<uint32_t> out_lsu_credits_
360 {&unit_port_set_, "out_lsu_credits"};
361
363 {&unit_port_set_, "out_biu_req"};
364
365
367 // Internal States
369
370 // Issue Queue
371 using LoadStoreIssueQueue = sparta::Buffer<LoadStoreInstInfoPtr>;
372 LoadStoreIssueQueue ldst_inst_queue_;
373 const uint32_t ldst_inst_queue_size_;
374
375 // TLB Cache
376 SimpleTLB* tlb_cache_ = nullptr;
377 const bool tlb_always_hit_;
378 bool mmu_busy_ = false;
379 bool mmu_pending_inst_flushed = false;
380 // Keep track of the instruction that causes current outstanding TLB miss
381 ExampleInstPtr mmu_pending_inst_ptr_ = nullptr;
382
383 // NOTE:
384 // Depending on how many outstanding TLB misses the MMU could handle at the same time
385 // This single slot could potentially be extended to a mmu pending miss queue
386
387
388 // L1 Data Cache
389 using DL1Handle = SimpleDL1::Handle;
390 DL1Handle dl1_cache_;
391 const bool dl1_always_hit_;
392 bool cache_busy_ = false;
393 bool cache_pending_inst_flushed_ = false;
394 // Keep track of the instruction that causes current outstanding cache miss
395 ExampleInstPtr cache_pending_inst_ptr_ = nullptr;
396
397 sparta::collection::Collectable<bool> cache_busy_collectable_{
398 getContainer(), "dcache_busy", &cache_busy_};
399
400 // NOTE:
401 // Depending on which kind of cache (e.g. blocking vs. non-blocking) is being used
402 // This single slot could potentially be extended to a cache pending miss queue
403
404
405 // Load/Store Pipeline
406 using LoadStorePipeline = sparta::Pipeline<MemoryAccessInfoPtr>;
407 LoadStorePipeline ldst_pipeline_
408 {"LoadStorePipeline", static_cast<uint32_t>(PipelineStage::NUM_STAGES), getClock()};
409
410 // Event Scheduling Parameters
411 const uint32_t issue_latency_;
412 const uint32_t mmu_latency_;
413 const uint32_t cache_latency_;
414 const uint32_t complete_latency_;
415
416
418 // Event Handlers
420
421 // Event to issue instruction
422 sparta::UniqueEvent<> uev_issue_inst_{&unit_event_set_, "issue_inst",
423 CREATE_SPARTA_HANDLER(LSU, issueInst_)};
424
425 // Event to drive BIU request port from MMU
426 sparta::UniqueEvent<> uev_mmu_drive_biu_port_ {&unit_event_set_, "mmu_drive_biu_port",
427 CREATE_SPARTA_HANDLER(LSU, driveBIUPortFromMMU_)};
428
429 // Event to drive BIU request port from Cache
430 sparta::UniqueEvent<> uev_cache_drive_biu_port_ {&unit_event_set_, "cache_drive_biu_port",
431 CREATE_SPARTA_HANDLER(LSU, driveBIUPortFromCache_)};
432
433
435 // Callbacks
437
438 // Send initial credits (ldst_inst_queue_size_) to Dispatch Unit
439 void sendInitialCredits_();
440
441 // Receive new load/store Instruction from Dispatch Unit
442 void getInstsFromDispatch_(const ExampleInstPtr &);
443
444 // Receive MSS access acknowledge from Bus Interface Unit
445 void getAckFromBIU_(const ExampleInstPtr &);
446
447 // Receive update from ROB whenever store instructions retire
448 void getAckFromROB_(const ExampleInstPtr &);
449
450 // Issue/Re-issue ready instructions in the issue queue
451 void issueInst_();
452
453 // Handle MMU access request
454 void handleMMULookupReq_();
455
456 // Drive BIU request port from MMU
457 void driveBIUPortFromMMU_();
458
459 // Handle cache access request
460 void handleCacheLookupReq_();
461
462 // Drive BIU request port from cache
463 void driveBIUPortFromCache_();
464
465 // Retire load/store instruction
466 void completeInst_();
467
468 // Handle instruction flush in LSU
469 void handleFlush_(const FlushCriteria &);
470
471
473 // Regular Function/Subroutine Call
475
476 // Append new load/store instruction into issue queue
477 void appendIssueQueue_(const LoadStoreInstInfoPtr &);
478
479 // Pop completed load/store instruction out of issue queue
480 void popIssueQueue_(const ExampleInstPtr &);
481
482 // Arbitrate instruction issue from ldst_inst_queue
483 const LoadStoreInstInfoPtr & arbitrateInstIssue_();
484
485 // Check for ready to issue instructions
486 bool isReadyToIssueInsts_() const;
487
488 // Access MMU/TLB
489 bool MMULookup_(const MemoryAccessInfoPtr &);
490
491 // Re-handle outstanding MMU access request
492 void rehandleMMULookupReq_(const ExampleInstPtr &);
493
494 // Reload TLB entry
495 void reloadTLB_(uint64_t);
496
497 // Access Cache
498 bool cacheLookup_(const MemoryAccessInfoPtr &);
499
500 // Re-handle outstanding cache access request
501 void rehandleCacheLookupReq_(const ExampleInstPtr &);
502
503 // Reload cache line
504 void reloadCache_(uint64_t);
505
506 // Update issue priority after dispatch
507 void updateIssuePriorityAfterNewDispatch_(const ExampleInstPtr &);
508
509 // Update issue priority after TLB reload
510 void updateIssuePriorityAfterTLBReload_(const ExampleInstPtr &,
511 const bool = false);
512
513 // Update issue priority after cache reload
514 void updateIssuePriorityAfterCacheReload_(const ExampleInstPtr &,
515 const bool = false);
516
517 // Update issue priority after store instruction retires
518 void updateIssuePriorityAfterStoreInstRetire_(const ExampleInstPtr &);
519
520 // Flush instruction issue queue
521 template<typename Comp>
522 void flushIssueQueue_(const Comp &);
523
524 // Flush load/store pipeline
525 template<typename Comp>
526 void flushLSPipeline_(const Comp &);
527 };
528
529 inline std::ostream & operator<<(std::ostream & os,
530 const core_example::LSU::MemoryAccessInfo::MMUState & mmu_access_state){
531 switch(mmu_access_state){
532 case LSU::MemoryAccessInfo::MMUState::NO_ACCESS:
533 os << "no_access";
534 break;
535 case LSU::MemoryAccessInfo::MMUState::MISS:
536 os << "miss";
537 break;
538 case LSU::MemoryAccessInfo::MMUState::HIT:
539 os << "hit";
540 break;
541 case LSU::MemoryAccessInfo::MMUState::NUM_STATES:
542 throw sparta::SpartaException("NUM_STATES cannot be a valid enum state.");
543 }
544 return os;
545 }
546
547 inline std::ostream & operator<<(std::ostream & os,
548 const core_example::LSU::MemoryAccessInfo::CacheState & cache_access_state){
549 switch(cache_access_state){
550 case LSU::MemoryAccessInfo::CacheState::NO_ACCESS:
551 os << "no_access";
552 break;
553 case LSU::MemoryAccessInfo::CacheState::MISS:
554 os << "miss";
555 break;
556 case LSU::MemoryAccessInfo::CacheState::HIT:
557 os << "hit";
558 break;
559 case LSU::MemoryAccessInfo::CacheState::NUM_STATES:
560 throw sparta::SpartaException("NUM_STATES cannot be a valid enum state.");
561 }
562 return os;
563 }
564
565 inline std::ostream& operator<<(std::ostream& os,
566 const core_example::LSU::LoadStoreInstInfo::IssuePriority& rank){
567 switch(rank){
568 case LSU::LoadStoreInstInfo::IssuePriority::HIGHEST:
569 os << "(highest)";
570 break;
571 case LSU::LoadStoreInstInfo::IssuePriority::CACHE_RELOAD:
572 os << "($_reload)";
573 break;
574 case LSU::LoadStoreInstInfo::IssuePriority::CACHE_PENDING:
575 os << "($_pending)";
576 break;
577 case LSU::LoadStoreInstInfo::IssuePriority::MMU_RELOAD:
578 os << "(mmu_reload)";
579 break;
580 case LSU::LoadStoreInstInfo::IssuePriority::MMU_PENDING:
581 os << "(mmu_pending)";
582 break;
583 case LSU::LoadStoreInstInfo::IssuePriority::NEW_DISP:
584 os << "(new_disp)";
585 break;
586 case LSU::LoadStoreInstInfo::IssuePriority::LOWEST:
587 os << "(lowest)";
588 break;
589 case LSU::LoadStoreInstInfo::IssuePriority::NUM_OF_PRIORITIES:
590 throw sparta::SpartaException("NUM_OF_PRIORITIES cannot be a valid enum state.");
591 }
592 return os;
593 }
594
595 inline std::ostream& operator<<(std::ostream& os,
596 const core_example::LSU::LoadStoreInstInfo::IssueState& state){
597 // Print instruction issue state
598 switch(state){
599 case LSU::LoadStoreInstInfo::IssueState::READY:
600 os << "(ready)";
601 break;
602 case LSU::LoadStoreInstInfo::IssueState::ISSUED:
603 os << "(issued)";
604 break;
605 case LSU::LoadStoreInstInfo::IssueState::NOT_READY:
606 os << "(not_ready)";
607 break;
608 case LSU::LoadStoreInstInfo::IssueState::NUM_STATES:
609 throw sparta::SpartaException("NUM_STATES cannot be a valid enum state.");
610 }
611 return os;
612 }
613} // namespace core_example
Defines the Buffer class used for buffering data.
Implementation of the Collectable class that allows a user to collect an object into an pipeViewer pi...
File that defines Data[In,Out]Port<DataT>
File that defines the EventSet class.
A set of sparta::Parameters per sparta::ResourceTreeNode.
#define PARAMETER(type, name, def, doc)
Parameter declaration.
Defines the Pipeline class.
File that defines the PortSet class.
File that defines the SignalInPort.
#define CREATE_SPARTA_HANDLER(clname, meth)
Defines the SpartaSharedPointer class used for garbage collection.
File that defines the StartupEvent class.
Basic Node framework in sparta device tree composite pattern.
File that defines the UniqueEvent class.
File that defines the Unit class, a common grouping of sets and loggers.
Parameters for LSU model.
Definition LSU.hpp:38
LSUParameterSet(sparta::TreeNode *n)
Constructor for LSUParameterSet.
Definition LSU.hpp:41
Pair Definition class of the load store instruction that flows through the example/CoreModel.
Definition LSU.hpp:322
Pair Definition class of the Memory Access Information that flows through the example/CoreModel.
Definition LSU.hpp:206
static const char name[]
name of this resource.
Definition LSU.hpp:83
A data structure allowing appending at the end, beginning, or middle, but erase anywhere with collaps...
Definition Buffer.hpp:74
DataInPort receives data from sender using a DataOutPort.
Definition DataPort.hpp:289
DataOutPort is used for transferring any data to another module.
Definition DataPort.hpp:77
Generic container of Parameters.
ParameterSet()=delete
Default constructor disabled.
A simple pipeline.
Definition Pipeline.hpp:63
TreeNode * getContainer()
Gets the TreeNode (container) for this resource (if any)
Used to construct and throw a standard C++ exception. Inherits from std::exception.
A memory allocator complementing SpartaSharedPointer that reuses old memory.
Used for garbage collection, will delete the object it points to when all objects are finished using ...
The State class for watching transition between enum states.
Definition State.hpp:123
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
std::string getLocation() const override final
TreeNode()=delete
Not default-constructable.
const Clock * getClock() override
Walks up parents (starting with self) until a parent with an associated local clock is found,...
A type of Event that uniquely schedules itself on the schedule within a single time quantum....
The is the base class for user defined blocks in simulation.
Definition Unit.hpp:38
sparta::EventSet unit_event_set_
The Unit's event set.
Definition Unit.hpp:114
log::MessageSource debug_logger_
Default debug logger.
Definition Unit.hpp:162
sparta::PortSet unit_port_set_
The Unit's Ports.
Definition Unit.hpp:111
Class used to either manually or auto-collect an Annotation String object in a pipeline database.
Macros for handling exponential backoff.
std::ostream & operator<<(std::ostream &o, const SimulationInfo &info)
ostream insertion operator for SimulationInfo
@ Flush
Phase where flushing of pipelines, etc can occur.