📄 memunit.cc
字号:
/* first do loads, then stores */ instance *memop; int confstore = 0; MemQLink<instance *> *stindex = NULL, *stindex2 = NULL; /* NOTE: DON'T ISSUE ANY STORES SPECULATIVELY */ while ((proc->UnitsFree[uMEM]) && ((stindex = proc->StoreQueue.GetNext(stindex)) != NULL)) { memop = stindex->d; /* Is the instruction already issued? */ if (memop->memprogress) continue; /* All memory issues are prohibited? */ if (proc->MEMISSUEtag >= 0 && memop->tag > proc->MEMISSUEtag) break; if (!memop->mem_ready || confstore) { if (CanPrefetch(proc, memop)) /* Prefetch subsequent ones, regardless of whether we could or couldn't for this one... */ proc->prefrdy[proc->prefs++] = memop; continue; } if (!memop->addr_ready) {#ifdef COREFILE if (proc->curr_cycle > DEBUG_TIME) fprintf(corefile, "store tag %lld store ready but not address " "ready!\n", memop->tag);#endif /* Found the first non-read writes. We might be able to prefetch some later ones, but don't issue any demand stores */ confstore = 1; continue; } int canissue = 1; instance *conf; stindex2 = NULL; while ((stindex2 = proc->StoreQueue.GetNext(stindex2)) != NULL) { conf = stindex2->d; if (conf->tag >= memop->tag) break; // block this one if there is a previous unissued one with // overlapping address.... if (conf->memprogress == 0 && overlap(conf, memop)) { canissue = 0; break; } } if (canissue) { /* the following checks to implement MEMBAR consistency */ if (((memop->tag > proc->SStag && proc->minstore < proc->SStag) || (memop->tag > proc->LStag && proc->minload < proc->LStag) || (IsRMW(memop) && (memop->tag > proc->SLtag && proc->minstore < proc->SLtag) || (memop->tag > proc->LLtag && proc->minload < proc->LLtag)))) { canissue = 0; if (CanPrefetch(proc, memop)) proc->prefrdy[proc->prefs++] = memop; continue; } } // Now we've passed all the semantic reasons why we can't issue it. // So, now we need to check for hardware constraints // check for structural hazards on input ports of cache if (L1DQ_FULL[proc->proc_id]) { canissue = 0; memop->memprogress = 0; break; } if (canissue) { if (!IsRMW(memop)) proc->StoresToMem++; if (simulate_ilp) proc->ReadyUnissuedStores--; IssueOp(memop, proc); } }}/*************************************************************************//* IssueLoads : Get elements from load queue and check for forwarding *//* : resource availability and issue it *//*************************************************************************/void IssueLoads(ProcState * proc){ instance *memop; MemQLink<instance *> *stindex = NULL, *ldindex = NULL; while ((proc->UnitsFree[uMEM]) && ((ldindex = proc->LoadQueue.GetNext(ldindex)) != NULL)) { memop = ldindex->d; if (memop->memprogress) // instruction is already issued continue; if (proc->MEMISSUEtag >= 0 && memop->tag > proc->MEMISSUEtag) break; if ((IsUncached(memop)) && (((proc->SStag > 0) && (memop->tag > proc->SStag)) || ((proc->LStag > 0) && (memop->tag > proc->LStag)) || ((proc->LLtag > 0) && (memop->tag > proc->LLtag)))) break; if (memop->addr_ready && memop->truedep != 0) { /* a load of an fp-half can have a true dependence on the rest of the fp register. In the future, it's possible that such a load should be allowed to issue but not to complete. */ /* The processor should try to prefetch it, if it has that support. Otherwise, this one can't issue yet. In the case of stat_sched, neither can anything after it. */ if (CanPrefetch(proc, memop)) { proc->prefrdy[proc->prefs++] = memop; continue; /* can issue or prefetch later loads */ } if (stat_sched) break; } /*********************************************/ /* Memory operations that are ready to issue */ /*********************************************/ if ((memop->truedep == 0) && (memop->addr_ready) && ((IsUncached(memop) && memop->mem_ready) || (!IsUncached(memop)))) { int canissue = 1; int specing = 0; unsigned instaddr = memop->addr; instance *conf; unsigned confaddr; stindex = NULL; //----------------------------------------------------------------- // prefetches if (memop->code.instruction == iPREFETCH) { if (L1DQ_FULL[proc->proc_id]) /* ports are taken */ break; // no further accesses will be allowed till ports free up else { ldindex = proc->LoadQueue.GetPrev(ldindex); /* do this because we're going to be removing this entry in the loadqueue in the IssueOp function */ IssueOp(memop, proc); continue; } } //----------------------------------------------------------------- // check for earlier (non-issued) stores while ((stindex = proc->StoreQueue.GetNext(stindex)) != NULL) { conf = stindex->d; if (conf->tag > memop->tag) break; if (!conf->addr_ready) { specing = 1; if (spec_stores == SPEC_STALL) { // now's the time to give up, if so memop->memprogress = 0; memop->vsbfwd = 0; return; } continue; } confaddr = conf->addr; if (overlap(conf, memop)) { // ok, either we stall or we have a chance for a quick // forwarding. if (confaddr == instaddr && conf->truedep == 0 && MemMatch(memop, conf) && !((!Speculative_Loads && ((memop->tag > proc->SLtag && conf->tag < proc->SLtag) || (memop->tag > proc->LLtag && proc->minload < proc->LLtag))))) // no forward across membar unless there is specload // support. note: specload membar is "speculative" across // a LL or SL, but we _actually_ enforce the MemIssue ones { if (conf->memprogress != 0) { // a forward from VSB of something that actually // will be GloballyPerformed memop->vsbfwd = -conf->tag - 3; memop->memprogress = 0; } else { // if we accidentally counted it as a vsbfwd earlier, // count it properly now memop->vsbfwd = 0; // varies from -3 on down! memop->memprogress = -conf->tag - 3; } canissue = 1; // we can definitely use it continue; } else if (conf->code.instruction == iSTDF && memop->code.instruction == iLDUW && conf->truedep == 0 && ((memop->addr == conf->addr) || (memop->addr == conf->addr + sizeof(int))) && !((!Speculative_Loads && ((memop->tag > proc->SLtag && conf->tag < proc->SLtag) || (memop->tag > proc->LLtag && proc->minload < proc->LLtag))))) { // here's a case where we can forward just like the // regular case, even if it's a partial overlap. // I mention this case because it's // so common, appearing in some libraries all the time if (conf->memprogress != 0) { // a forward from VSB of something that actually will be // GloballyPerformed -- only way it won't is if it gets // flushed memop->vsbfwd = -conf->tag - 3; memop->memprogress = 0; } else { // if we accidentally counted it as a vsbfwd earlier, // count it properly now memop->vsbfwd = 0; // varies from -3 on down! memop->memprogress = -conf->tag - 3; } if (memop->addr == conf->addr) { int *ip = (int*)(&conf->rs1valf); int *dp = &(memop->rdvali); *dp = *ip; } else if (memop->addr == conf->addr + sizeof(int)) { int *ip = (int*)(&conf->rs1valf) + 1; int *dp = &(memop->rdvali); *dp = *ip; // memop->rdvali = *(((int *) (&conf->rs1valf)) + 1); }#ifdef DEBUG else /* a partial overlap of STDF and LDUW that can't be handled. Most probably misalignment or other problems involved. Checked for this case before entering here. */ YS__errmsg(proc->proc_id / ARCH_cpus, "Partial overlap of STDF and LDUW which " "couldn't be recognized: should've been checked.\n");#endif canissue = 1; // we can definitely use it continue; } else if (conf->memprogress == 0) { // the store hasn't been issued yet memop->memprogress = 0; memop->vsbfwd = 0; canissue = 0; continue; } else if (IsRMW(conf)) { // you can't go in parallel with any RMW (except of // course for simple LDSTUBs which you forward) memop->memprogress = 0; memop->vsbfwd = 0; canissue = 0; continue; } else if (!(((memop->tag > proc->SLtag && proc->minstore < proc->SLtag) || (memop->tag > proc->LLtag && proc->minload < proc->LLtag)))) { /* in other words, this isn't a case of trying to forward across a membar for now we'll actually block out partial overlaps (except for the special case we handled above STDF-LDUW), and count them when they graduate */ memop->memprogress = 0; memop->vsbfwd = 0; canissue = 0; memop->partial_overlap = 1;#ifdef COREFILE if (YS__Simtime > DEBUG_TIME) fprintf(corefile, "P%d @<%d>: Partially overlapping " "load tag %d[%s] @(%d) conflicts with tag " "%d[%s] @(%d)\n", proc->proc_id, proc->curr_cycle, memop->tag, inames[memop->code.instruction], instaddr, conf->tag, inames[conf->code.instruction], confaddr);#endif continue; } } } if (canissue && memop->memprogress > -3) { if ((!Speculative_Loads && ((memop->tag > proc->SLtag && proc->minstore < proc->SLtag) || (memop->tag > proc->LLtag && proc->minload < proc->LLtag)))) { // so we're stuck at an ACQ membar well, if we have prefetch, // let's go ahead and prefetch reads memop->vsbfwd = 0; memop->memprogress = 0; canissue = 0; if (CanPrefetch(proc, memop)) { proc->prefrdy[proc->prefs++] = memop; continue; } continue; /* in case we have some prefetches or anything like that */ } // Check if L1 ports are busy before issuing if (L1DQ_FULL[proc->proc_id]) { canissue = 0; memop->vsbfwd = 0; memop->memprogress = 0; break; } } if (canissue) { proc->ldissues++; if (specing) proc->ldspecs++; if (memop->memprogress < 0) // we got a quick forward { proc->fwds++; memop->issuetime = proc->curr_cycle; // WE GET THE FORWARD VALUE IN THE MemMatch FUNCTION proc->MemDoneHeap.insert(proc->curr_cycle + 1, memop, memop->tag); } else IssueOp(memop, proc); } } }}#endif#ifdef COREFILE/*************************************************************************//* OpCompletionMessage : print debug information at inst completion time *//*************************************************************************/static void OpCompletionMessage(instance * inst, ProcState * proc){ if (proc->curr_cycle > DEBUG_TIME) { fprintf(corefile, "Completed executing tag = %lld, %s, ", inst->tag, inames[inst->code.instruction]); switch (inst->code.rd_regtype) { case REG_INT: fprintf(corefile, "rdi = %d, ", inst->rdvali); break; case REG_FP: fprintf(corefile, "rdf = %f, ", inst->rdvalf); break; case REG_FPHALF: fprintf(corefile, "rdfh = %f, ", double (inst->rdvalfh)); break; case REG_INTPAIR: fprintf(corefile, "rdp = %d/%d, ", inst->rdvalipair.a, inst->rdvalipair.b); break; case REG_INT64: fprintf(corefile, "rdll = %lld, ", inst->rdvalll); break; default: fprintf(corefile, "rdX = XXX, "); break; } fprintf(corefile, "rccvali = %d \n", inst->rccvali); }}static void IssueOpMessage(ProcState *proc, instance *memop){ if (proc->curr_cycle > DEBUG_TIME) { fprintf(corefile, "Consuming memunit for tag %lld\n", memop->tag); fprintf(corefile, "Issue tag = %lld, %s, ", memop->tag, inames[memop->code.instruction]); switch (memop->code.rs1_regtype) { case REG_INT: fprintf(corefile, "rs1i = %d, ", memop->rs1vali); break; case REG_FP: fprintf(corefile, "rs1f = %f, ", memop->rs1valf); break; case REG_FPHALF: fprintf(corefile, "rs1fh = %f, ", double (memop->rs1valfh)); break; case REG_INTPAIR: fprintf(corefile, "rs1p = %d/%d, ", memop->rs1valipair.a, memop->rs1valipair.b); break; case REG_INT64: fprintf(corefile, "rs1ll = %lld, ", memop->rs1valll); break; default: fprintf(corefile, "rs1X = XXX, "); break; } switch (memop->code.rs2_regtype) { case REG_INT: fprintf(corefile, "rs2i = %d, ", memop->rs2vali); break; case REG_FP: fprintf(corefile, "rs2f = %f, ", memop->rs2valf); break; case REG_FPHALF: fprintf(corefile, "rs2fh = %f, ", double (memop->rs2valfh)); break; case REG_INTPAIR: fprintf(corefile, "rs2pair unsupported"); break; case REG_INT64: fprintf(corefile, "rs2ll = %lld, ", memop->rs2valll); break; default: fprintf(corefile, "rs2X = XXX, "); break; } fprintf(corefile, "rscc = %d, imm = %d\n", memop->rsccvali, memop->code.imm); }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -