📄 memunit.cc
字号:
if (!simulate_ilp && IsStore(inst) && !IsRMW(inst)) { proc->active_list.mark_done_in_active_list(inst->tag, inst->exception_code, proc->curr_cycle - 1); return 0; }#endif proc->MemDoneHeap.insert(proc->curr_cycle + 1, inst, inst->tag); return 0; }#ifndef STORE_ORDERING if (!simulate_ilp && IsStore(inst) && !IsRMW(inst)) { inst->in_memunit = 0; instance *memop = new instance(inst); proc->StoreQueue.Replace(inst, memop); inst = memop; }#endif if (inst->code.instruction == iPREFETCH) { // send out a prefetch int excl = inst->code.aux2 == PREF_1WT || inst->code.aux2 == PREF_NWT; int level = 1 + (Prefetch == 2 || inst->code.aux2 == PREF_1WT || inst->code.aux2 == PREF_1RD); if (!drop_all_sprefs) IssuePrefetch(proc, inst->addr, level, excl, inst->tag); // the prefetch instruction itself should return instantly a pref isn't // like other memops; it can return even without paying cache time inst->memprogress = 1; PerformMemOp(inst, proc);#if 0#ifdef COREFILE OpCompletionMessage(inst, proc);#endif#endif proc->DoneHeap.insert(proc->curr_cycle + 1, inst, inst->tag); return 0; } if (StartUpMemRef(proc, inst) == -1) /* not accepted -- should never happen */ YS__errmsg(proc->proc_id / ARCH_cpus, "StartUpMemRef rejected an operation.\n"); return 0;}/*=========================================================================== * Takes entries off the MemDoneHeap and if they are valid, inserts them * on the running queue called by RSIM_EVENT(). */void CompleteMemQueue(ProcState * proc){ instance *inst; long long inst_tag; if ((proc->MemDoneHeap.num() == 0) || (proc->MemDoneHeap.PeekMin() > proc->curr_cycle)) return; do { proc->MemDoneHeap.GetMin(inst, inst_tag); if (inst->tag == inst_tag) // hasn't been flushed CompleteMemOp(inst, proc); // this will insert completions // on running q#ifdef COREFILE else { if (proc->curr_cycle > DEBUG_TIME) fprintf(corefile, "Got nonmatching tag %lld off memheap\n", inst_tag); }#endif } while (proc->MemDoneHeap.num() != 0 && proc->MemDoneHeap.PeekMin() <= proc->curr_cycle);}/**************************************************************************//* CompleteMemOp : Perform the operations on completion of a memory instr *//* : and add to DoneHeap *//**************************************************************************/int CompleteMemOp(instance * inst, ProcState * proc){#ifdef DEBUG if (inst->memprogress == 2) YS__errmsg(proc->proc_id / ARCH_cpus, "Flushed operation should not come to CompleteMemOp.");#endif if (IsStore(inst)) { //-------------------------------------------------------------------- // STORE: Completes perfectly. Mark it done in some way, and if it's // the first instruction in the store q, mark all in-order dones // possible // -- Note that in the SC world, all Stores are like RMWs#ifdef DEBUG if (inst->memprogress == 2) // it has been flushed YS__errmsg(proc->proc_id / ARCH_cpus, "Flushed operation %s (tag=%lld) should never come to CompleteMemOp.\n", inames[inst->code.instruction], inst->tag);#endif inst->memprogress = 1; #ifdef DEBUG if (!inst->global_perform && inst->exception_code == OK) YS__errmsg(proc->proc_id / ARCH_cpus, "Tag %lld (0x%08X) Processor %d was never globally performed! (addr 0x%08X)\n", inst->tag, inst->pc, proc->proc_id, inst->addr);#endif // we need to move this to the issue stage, // to handle proper simulation of RAW, etc if (IsRMW(inst)#ifdef STORE_ORDERING || (!SC_NBWrites && !Processor_Consistency)#endif ) { if (inst->memprogress <= 0) { inst->issuetime = LLONG_MAX; return 0; // not yet accepted } PerformMemOp(inst, proc); // use this so that it's clearly done in the memory unit#if 0 #ifdef COREFILE OpCompletionMessage(inst,proc);#endif#endif proc->DoneHeap.insert(proc->curr_cycle, inst, inst->tag); } else // an ordinary write in RC or PC or SC w/nb writes {#ifndef STORE_ORDERING proc->StoresToMem--;#endif PerformMemOp(inst, proc); // use this so that it's clearly done in the memory unit#if 0 #ifdef COREFILE OpCompletionMessage(inst, proc);#endif#endif if (inst->inuse == 2) { inst->inuse = 0; proc->meminstances.Putback(inst); } else DeleteInstance(inst, proc); } return 0; } else { //--------------------------------------------------------------------- // LOAD: On completion, first see if there are any items in // store q with lower tag that has same addr or unknown addr. If // so, we may need to redo operation. If not, mark it done and // if first instr in store q, mark all in-order completes possible#ifdef DEBUG if (inst->memprogress == 2) YS__errmsg(proc->proc_id / ARCH_cpus, "Flushed operation should not come to CompleteMemOp.\n"); else#endif if (inst->code.instruction == iPREFETCH) { YS__logmsg(proc->proc_id / ARCH_cpus, "Why did we enter Complete Mem Op on a prefetch???\n"); inst->memprogress = 1; // don't check limbos, spec_stores, etc. PerformMemOp(inst, proc); } else { if (inst->exception_code == SOFT_SL_COHE || inst->exception_code == SOFT_SL_REPL || inst->exception_code == SOFT_LIMBO) // footnote 5 implementation -- we'll need to redo it. { if (inst->exception_code == SOFT_LIMBO) proc->redos++; inst->prefetched = 0; inst->memprogress = 0; inst->vsbfwd = 0; inst->global_perform = 0; inst->exception_code = OK; inst->issuetime = LLONG_MAX; return 0; } int redo = 0; instance *sts; long long lowambig; if (inst->kill == 1) { redo = 1; inst->kill = 0; } if (spec_stores == SPEC_LIMBO && proc->ambig_st_tags.GetMin(lowambig) && lowambig < inst->tag) // ambiguous store before this load... { proc->limbos++; inst->limbo++; // Set the limbo bit on to remember to check for this } // if so, this is all taken care of before Issue if (spec_stores != SPEC_STALL) { MemQLink<instance *> *stindex = NULL;#ifndef STORE_ORDERING while ((stindex = proc->StoreQueue.GetNext(stindex)) != NULL)#else while ((stindex = proc->MemQueue.GetNext(stindex)) != NULL)#endif { sts = stindex->d; if (sts->tag > inst->tag) break;#ifdef STORE_ORDERING if (!IsStore(sts)) continue;#endif // if we got a forward, then we can ignore the other cases here if (inst->memprogress <= -sts->tag-3) // we got a forward from an op with greater tag continue; if (!sts->addr_ready && spec_stores == SPEC_EXCEPT) { if (inst->limbo == 0) proc->limbos++; inst->limbo++;#ifdef COREFILE if (proc->curr_cycle > DEBUG_TIME) fprintf(corefile, "P%d,%lld Gambling to avoid a limbo on %lld\n", proc->proc_id, inst->tag, sts->tag);#endif continue; } if (overlap(sts, inst) && (inst->issuetime < sts->issuetime)) { proc->redos++; redo = 1; break; } } } if (redo) { inst->memprogress = 0; // in other words, start all over inst->vsbfwd = 0; inst->issuetime = LLONG_MAX; inst->limbo--; return 0; } else {#ifdef DEBUG if (inst->memprogress == -1 ) // non-forwarded { if (!inst->global_perform && inst->exception_code == OK) YS__errmsg(proc->proc_id / ARCH_cpus, "Tag %lld (0x%08X) Processor %d was never globally performed (addr 0x%08X)!\n", inst->tag, inst->pc, proc->proc_id, inst->addr); } if (inst->memprogress == 0) // should not ever happen YS__errmsg(proc->proc_id / ARCH_cpus, "How is memprogress 0 at Complete?\n");#endif if (!inst->limbo || spec_stores == SPEC_EXCEPT) // only_specs { if (!inst->limbo) inst->memprogress = 1; PerformMemOp(inst, proc); if (!inst->limbo) {#if 0#ifdef COREFILE OpCompletionMessage(inst, proc);#endif#endif proc->DoneHeap.insert(proc->curr_cycle, inst, inst->tag); } } } } return 0; }}/*************************************************************************//* PerformMemOp : Possibly remove memory operation from queue and free *//* : up slot in memory system. If aggressive use of load *//* : values supported past ambiguous stores, update *//* : register values, but keep load in queue *//*************************************************************************/void PerformMemOp(instance * inst, ProcState * proc){#ifdef STORE_ORDERING instance *i;#endif#ifndef STORE_ORDERING if (IsRMW(inst)) // RMW ----------------------------------- { proc->rmw_tags.Remove(inst->tag); proc->StoreQueue.Remove(inst); inst->in_memunit = 0; } else if (IsStore(inst)) // stores -------------------------------- { proc->st_tags.Remove(inst->tag); proc->StoreQueue.Remove(inst); // Don't add anything to memory system here because this wasn't still // sitting in the "real" memory queue in RC } else // loads --------------------------------- { if (inst->code.instruction == iPREFETCH || (!inst->limbo && (!Speculative_Loads || (!(proc->minstore < proc->SLtag && inst->tag > proc->SLtag) && !(proc->minload < proc->LLtag && inst->tag > proc->LLtag))))) // we enter here ordinarily, for loads that are only preceded by // disambiguated stores and which are not speculative { proc->LoadQueue.Remove(inst); inst->in_memunit = 0; }#else /* Is STORE_ORDERING! */ if (IsStore(inst)) { // RMW is nothing special here.... // In sequential consistency, memory operations are not removed // from the memory queue until the operations above them have // all finished. int keepgoing = proc->MemQueue.GetMin(i); while (keepgoing) // find other ones to remove also { if (i->memprogress > 0) { proc->MemQueue.Remove(i); if (simulate_ilp && !Processor_Consistency && IsStore(i)) proc->ReadyUnissuedStores--; i->in_memunit = 0; } else break; keepgoing = proc->MemQueue.GetMin(i); } } //------------------------------------------------------------------------- // Load Instruction else { if (!inst->limbo || inst->code.instruction == iPREFETCH) { // we enter here ordinarily, for accesses past // disambiguated stores MemQLink<instance *> *stepper = NULL, *oldstepper; i = stepper->d; while (stepper = proc->MemQueue.GetNext(stepper)) { if (i->memprogress > 0) { if (simulate_ilp && !Processor_Consistency && IsStore(i)) proc->ReadyUnissuedStores--; oldstepper = stepper; stepper = proc->MemQueue.GetPrev(stepper); proc->MemQueue.Remove(oldstepper); i->in_memunit = 0; } else if (!(Processor_Consistency && IsStore(i) && !IsRMW(i))) break; if ((stepper=proc->MemQueue.GetNext(stepper)) != NULL) i = stepper->d; } }#endif // STORE_ORDERING else { // when we do have a limbo, we need to just pass the value on, by // setting the dest reg val. The instance remains in the MemQueus#ifdef DEBUG if (inst->limbo && spec_stores != SPEC_EXCEPT) /* We come here only for SPEC_EXCEPT */ YS__errmsg(proc->proc_id / ARCH_cpus, "%s:%d -- should only be entered with SPEC_EXCEPT." " P%d,%lld\n", __FILE__, __LINE__, proc->proc_id, inst->tag);#endif #ifdef COREFILE if (proc->curr_cycle > DEBUG_TIME) fprintf(corefile, "Sending value down from %s-load tag %lld\n", inst->limbo ? "limbo" : "spec", inst->tag);#endif switch (inst->code.rd_regtype) { case REG_INT: case REG_INT64: if (inst->prd != 0) proc->phy_int_reg_file[inst->prd] = inst->rdvali; proc->intregbusy[inst->prd] = 0; proc->dist_stallq_int[inst->prd].ClearAll(proc); break; case REG_FP: proc->phy_fp_reg_file[inst->prd] = inst->rdvalf; proc->fpregbusy[inst->prd] = 0; proc->dist_stallq_fp[inst->prd].ClearAll(proc); break; case REG_FPHALF: { proc->phy_fp_reg_file[inst->prd] = inst->rsdvalf; float *address = (float *) (&proc->phy_fp_reg_file[inst->prd]); if (inst->code.rd & 1) /* the odd half */ address += 1; *address = inst->rdvalfh; proc->fpregbusy[inst->prd] = 0; proc->dist_stallq_fp[inst->prd].ClearAll(proc); break; } case REG_INTPAIR:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -