41 #ifndef __CPU_O3_MEM_DEP_UNIT_IMPL_HH__ 42 #define __CPU_O3_MEM_DEP_UNIT_IMPL_HH__ 49 #include "debug/MemDepUnit.hh" 50 #include "params/DerivO3CPU.hh" 52 template <
class MemDepPred,
class Impl>
58 template <
class MemDepPred,
class Impl>
61 depPred(params->store_set_clear_period, params->SSITSize,
68 template <
class MemDepPred,
class Impl>
71 for (
ThreadID tid = 0; tid < Impl::MaxThreads; tid++) {
78 hash_it =
memDepHash.find((*inst_list_it)->seqNum);
89 assert(MemDepEntry::memdep_count == 0);
93 template <
class MemDepPred,
class Impl>
102 depPred.init(params->store_set_clear_period, params->SSITSize,
106 template <
class MemDepPred,
class Impl>
112 .
desc(
"Number of loads inserted to the mem dependence unit.");
116 .
desc(
"Number of stores inserted to the mem dependence unit.");
120 .
desc(
"Number of conflicting loads.");
123 .
name(
name() +
".conflictingStores")
124 .
desc(
"Number of conflicting stores.");
127 template <
class MemDepPred,
class Impl>
134 for (
int i = 0;
i < Impl::MaxThreads; ++
i)
135 drained = drained &&
instList[
i].empty();
140 template <
class MemDepPred,
class Impl>
146 for (
int i = 0;
i < Impl::MaxThreads; ++
i)
152 template <
class MemDepPred,
class Impl>
162 template <
class MemDepPred,
class Impl>
169 template <
class MemDepPred,
class Impl>
175 if (barr_inst->isMemBarrier()) {
179 barr_inst->pcState(), barr_sn);
180 }
else if (barr_inst->isWriteBarrier()) {
183 barr_inst->pcState(), barr_sn);
187 "store barriers = %d\n",
192 template <
class MemDepPred,
class Impl>
204 MemDepEntry::memdep_insert++;
209 inst_entry->listIt = --(
instList[tid].end());
217 producing_stores.insert(std::end(producing_stores),
220 }
else if ((inst->isStore() || inst->isAtomic()) &&
hasStoreBarrier()) {
223 producing_stores.insert(std::end(producing_stores),
229 producing_stores.push_back(dep);
235 for (
auto producing_store : producing_stores) {
241 store_entries.push_back((*hash_it).second);
248 if (store_entries.empty()) {
250 "%s [sn:%lli].\n", inst->pcState(), inst->seqNum);
252 assert(inst_entry->memDeps == 0);
254 if (inst->readyToIssue()) {
255 inst_entry->regsReady =
true;
262 for (
auto M5_VAR_USED producing_store : producing_stores)
264 inst->pcState(), producing_store);
266 if (inst->readyToIssue()) {
267 inst_entry->regsReady =
true;
271 inst->clearCanIssue();
274 for (
auto store_entry : store_entries)
275 store_entry->dependInsts.push_back(inst_entry);
277 inst_entry->memDeps = store_entries.size();
279 if (inst->isLoad()) {
289 if (inst->isStore() || inst->isAtomic()) {
291 inst->pcState(), inst->seqNum);
293 depPred.insertStore(inst->instAddr(), inst->seqNum, inst->threadNumber);
296 }
else if (inst->isLoad()) {
299 panic(
"Unknown type! (most likely a barrier).");
303 template <
class MemDepPred,
class Impl>
311 if (inst->isStore() || inst->isAtomic()) {
313 inst->pcState(), inst->seqNum);
315 depPred.insertStore(inst->instAddr(), inst->seqNum, inst->threadNumber);
318 }
else if (inst->isLoad()) {
321 panic(
"Unknown type! (most likely a barrier).");
325 template <
class MemDepPred,
class Impl>
329 ThreadID tid = barr_inst->threadNumber;
331 MemDepEntryPtr inst_entry = std::make_shared<MemDepEntry>(barr_inst);
337 MemDepEntry::memdep_insert++;
343 inst_entry->listIt = --(
instList[tid].end());
348 template <
class MemDepPred,
class Impl>
353 "instruction PC %s [sn:%lli].\n",
354 inst->pcState(), inst->seqNum);
358 inst_entry->regsReady =
true;
360 if (inst_entry->memDeps == 0) {
362 "dependencies resolved, adding it to the ready list.\n");
367 "memory dependency.\n");
371 template <
class MemDepPred,
class Impl>
376 "instruction PC %s as ready [sn:%lli].\n",
377 inst->pcState(), inst->seqNum);
384 template <
class MemDepPred,
class Impl>
391 template <
class MemDepPred,
class Impl>
404 temp_inst->pcState(), temp_inst->seqNum);
412 template <
class MemDepPred,
class Impl>
417 inst->pcState(), inst->seqNum);
426 instList[tid].erase((*hash_it).second->listIt);
428 (*hash_it).second = NULL;
432 MemDepEntry::memdep_erase++;
436 template <
class MemDepPred,
class Impl>
443 if (inst->isMemBarrier()) {
449 inst->pcState(), inst->seqNum);
450 }
else if (inst->isWriteBarrier()) {
454 inst->pcState(), inst->seqNum);
458 template <
class MemDepPred,
class Impl>
463 if (!inst->isStore() && !inst->isAtomic() && !inst->isMemBarrier() &&
464 !inst->isWriteBarrier()) {
470 for (
int i = 0;
i < inst_entry->dependInsts.size(); ++
i ) {
473 if (!woken_inst->inst) {
480 woken_inst->inst->seqNum);
482 assert(woken_inst->memDeps > 0);
483 woken_inst->memDeps -= 1;
485 if ((woken_inst->memDeps == 0) &&
486 woken_inst->regsReady &&
487 !woken_inst->squashed) {
492 inst_entry->dependInsts.clear();
495 template <
class MemDepPred,
class Impl>
503 if ((*replay_it)->threadNumber == tid &&
504 (*replay_it)->seqNum > squashed_num) {
518 (*squash_it)->seqNum > squashed_num) {
521 (*squash_it)->seqNum);
527 hash_it =
memDepHash.find((*squash_it)->seqNum);
531 (*hash_it).second->squashed =
true;
533 (*hash_it).second = NULL;
537 MemDepEntry::memdep_erase++;
544 depPred.squash(squashed_num, tid);
547 template <
class MemDepPred,
class Impl>
553 " load: %#x, store: %#x\n", violating_load->instAddr(),
554 store_inst->instAddr());
556 depPred.violation(store_inst->instAddr(), violating_load->instAddr());
559 template <
class MemDepPred,
class Impl>
564 inst->instAddr(), inst->seqNum);
566 depPred.issued(inst->instAddr(), inst->seqNum, inst->isStore());
569 template <
class MemDepPred,
class Impl>
577 return (*hash_it).second;
580 template <
class MemDepPred,
class Impl>
585 "to the ready list.\n", woken_inst_entry->inst->seqNum);
587 assert(!woken_inst_entry->squashed);
589 iqPtr->addReadyMemInst(woken_inst_entry->inst);
593 template <
class MemDepPred,
class Impl>
597 for (
ThreadID tid = 0; tid < Impl::MaxThreads; tid++) {
598 cprintf(
"Instruction list %i size: %i\n",
604 while (inst_list_it !=
instList[tid].end()) {
605 cprintf(
"Instruction:%i\nPC: %s\n[sn:%llu]\n[tid:%i]\nIssued:%i\n" 607 num, (*inst_list_it)->pcState(),
608 (*inst_list_it)->seqNum,
609 (*inst_list_it)->threadNumber,
610 (*inst_list_it)->isIssued(),
611 (*inst_list_it)->isSquashed());
620 cprintf(
"Memory dependence entries: %i\n", MemDepEntry::memdep_count);
624 #endif//__CPU_O3_MEM_DEP_UNIT_IMPL_HH__ #define panic(...)
This implements a cprintf based panic() function.
MemDepHash memDepHash
A hash map of all memory dependence entries.
void completed(const DynInstPtr &inst)
Completes a memory instruction.
std::unordered_set< InstSeqNum > storeBarrierSNs
Sequence numbers of outstanding store barriers.
std::shared_ptr< MemDepEntry > MemDepEntryPtr
void violation(const DynInstPtr &store_inst, const DynInstPtr &violating_load)
Indicates an ordering violation between a store and a younger load.
bool hasLoadBarrier() const
Is there an outstanding load barrier that loads must wait on.
std::list< DynInstPtr >::iterator ListIt
void regStats()
Registers statistics.
void replay()
Replays all instructions that have been rescheduled by moving them to the ready list.
void setIQ(InstructionQueue< Impl > *iq_ptr)
Sets the pointer to the IQ.
Impl::DynInstConstPtr DynInstConstPtr
std::unordered_set< InstSeqNum > loadBarrierSNs
Sequence numbers of outstanding load barriers.
void wakeDependents(const DynInstPtr &inst)
Wakes any dependents of a memory instruction.
~MemDepUnit()
Frees up any memory allocated.
bool isDrained() const
Determine if we are drained.
Stats::Scalar insertedLoads
Stat for number of inserted loads.
void nonSpecInstReady(const DynInstPtr &inst)
Indicate that a non-speculative instruction is ready.
InstructionQueue< Impl > * iqPtr
Pointer to the IQ.
void takeOverFrom()
Takes over from another CPU's thread.
std::string csprintf(const char *format, const Args &...args)
Impl::DynInstPtr DynInstPtr
void insertNonSpec(const DynInstPtr &inst)
Inserts a non-speculative memory instruction.
Stats::Scalar conflictingStores
Stat for number of conflicting stores that had to wait for a store.
void issue(const DynInstPtr &inst)
Issues the given instruction.
Stats::Scalar conflictingLoads
Stat for number of conflicting loads that had to wait for a store.
void moveToReady(MemDepEntryPtr &ready_inst_entry)
Moves an entry to the ready list.
void regsReady(const DynInstPtr &inst)
Indicate that an instruction has its registers ready.
void dumpLists()
Debugging function to dump the lists of instructions.
Stats::Scalar insertedStores
Stat for number of inserted stores.
std::list< DynInstPtr > instList[Impl::MaxThreads]
A list of all instructions in the memory dependence unit.
void reschedule(const DynInstPtr &inst)
Reschedules an instruction to be re-executed.
bool hasStoreBarrier() const
Is there an outstanding store barrier that loads must wait on.
MemDepEntryPtr & findInHash(const DynInstConstPtr &inst)
Finds the memory dependence entry in the hash map.
MemDepPred depPred
The memory dependence predictor.
void insert(const DynInstPtr &inst)
Inserts a memory instruction.
Memory dependency unit class.
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
int16_t ThreadID
Thread index/ID type.
void init(DerivO3CPUParams *params, ThreadID tid)
Initializes the unit with parameters and a thread id.
void squash(const InstSeqNum &squashed_num, ThreadID tid)
Squashes all instructions up until a given sequence number for a specific thread. ...
std::list< DynInstPtr > instsToReplay
A list of all instructions that are going to be replayed.
void drainSanityCheck() const
Perform sanity checks after a drain.
std::string name() const
Returns the name of the memory dependence unit.
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
void insertBarrierSN(const DynInstPtr &barr_inst)
Inserts the SN of a barrier inst.
MemDepUnit()
Empty constructor.
void insertBarrier(const DynInstPtr &barr_inst)
Inserts a barrier instruction.
void completeInst(const DynInstPtr &inst)
Notifies completion of an instruction.
A standard instruction queue class.
void cprintf(const char *format, const Args &...args)
MemDepHash::iterator MemDepHashIt