📄 l2cache.c
字号:
if (pmshr->releasing) { captr->pstats->l2stall.release++; return MSHR_STALL_RELEASE; } /* * Now we need to consider the possibility of a "WAR" stall. This is a * case where an MSHR has an exclusive-mode request wants to merge with a * shared-mode MSHR. Even if this is a read request to an MSHR with an * outstanding WAR, this request should be stalled, as otherwise the read * would be processed out-of-order with respect to the stalled write */ if (pmshr->stall_WAR) { captr->pstats->l2stall.war++; return MSHR_STALL_WAR; } if ((req->prcr_req_type != READ) && (pmshr->mainreq->prcr_req_type == READ)) { captr->pstats->l2stall.war++; pmshr->stall_WAR = 1; return MSHR_STALL_WAR; } /* * Too many requests coalesced with MSHR */ if (pmshr->counter == MAX_COALS-1) { captr->pstats->l2stall.coal++; return MSHR_STALL_COAL; } /* * No problems with coalescing the request, so coalesce it */ pmshr->coal_req[pmshr->counter++] = req; if (req->req_type == WRITE || req->req_type == RMW) pmshr->has_writes = 1; else pmshr->has_writes = 0; if (pmshr->only_prefs && !(req->prefetch & 10)) { /* * Hit a late prefetch. */ if (pmshr->mainreq->prefetch == 2) { captr->pstats->sl2.late++; captr->pstats->sl2.useful++; } else if (pmshr->mainreq->prefetch == 8) { captr->pstats->l2p.late++; captr->pstats->l2p.useful++; } pmshr->demand = YS__Simtime; /* use this to compute lateness factor */ pmshr->only_prefs = 0; } return MSHR_COAL;}/*=========================================================================== * Simulates access replies to the L2 cache tag array. * progress = 0: initial state * progress = 1: reply has been processed, but hasn't sent anything out. * progress = 2: the invalidation request has been sent up, if any. * progress = 3: the write-back request has been sent down, if any. * Returns 0 on failure; 1 on success. */static int L2ProcessTagReply(CACHE * captr, REQ * req){ int misscache, i; MISS_TYPE ccdres; cline_t *cline; MSHR *pmshr; REQ *ireq; if (req->type == WRITEBACK) { if (captr->pending_writeback) return 0; else { Cache_start_send_to_bus(captr, req); return 1; } } if (captr->stall_reply) return 0; if (req->progress == 0) { pmshr = req->l2mshr; if (pmshr == 0) YS__errmsg(captr->nodeid, "L2 Cache %i received a reply (0x%p 0x%08X) for a nonexistent MSHR\n", captr->procid, req, req->paddr); /* * Collect statistics about late prefetch. */ if (pmshr->demand > 0) { if (pmshr->mainreq->prefetch == 2) captr->pstats->sl2.lateness += YS__Simtime - pmshr->demand; else if (pmshr->mainreq->prefetch == 8) captr->pstats->l2p.lateness += YS__Simtime - pmshr->demand; pmshr->demand = -1; } /* * Does the MSHR have a coherence message merged into it? This happens * when MSHR receives a certain type of COHE while outstanding. In * this case, the line must transition to a different state than the * REPLY itself would indicate. Note: such merging is only allowed if * the merge will not require a copyback of any sort. And are there * any writes with this MSHR? If so, make sure to transition to * dirty.... */ cline = pmshr->cline; misscache = pmshr->misscache; req->invl_req = NULL; req->wrb_req = NULL; if (misscache == 0) { /* this was for an upgrade */ cline->state = PR_DY; cline->mshr_out = 0; } else { if (misscache == 1) { /* present miss */ Cache_pmiss_update(captr, req, cline->index, pmshr->only_prefs); req->miss_type2 = CACHE_MISS_COHE; } else { /* misscache == 2 : total miss */ /* * Finds a victim and updates ages. If no places are available, * wait. */ if (!Cache_miss_update(captr, req, &cline, pmshr->only_prefs)) { YS__warnmsg(captr->nodeid, "No replace for L2 cache_miss, possible deadlock"); return 0; } /* * capacity/conflict miss detector */ ccdres = CCD_InsertNewLine(captr->ccd, ADDR2BNUM2(req->paddr)); req->miss_type2 = req->line_cold ? CACHE_MISS_COLD : ccdres; pmshr->cline = cline; } if (cline->state != INVALID) { /* * In this case, some sort of replacement is needed. Gather all * information about line being replaced */ if (cline->state == SH_CL) captr->pstats->shcl_victims2++; else if (cline->state == PR_CL) captr->pstats->prcl_victims2++; else if (cline->state == PR_DY) captr->pstats->prdy_victims2++; if (cline->state == PR_DY) { /* * Need to send the private dirty line back to main memory. */ req->wrb_req = Cache_make_req(captr, cline, REPLY_EXCL); req->wrb_req->type = WRITEBACK; req->wrb_req->parent = 0; /* not associated with any cohe*/ } /* * Also an invalidation message is sent up to the L1 caches. */ req->invl_req = Cache_make_req(captr, cline, INVALIDATE); req->invl_req->type = COHE; req->invl_req->parent = req; ireq = Cache_make_req(captr, cline, INVALIDATE); ireq->type = COHE; ireq->parent = req; } /* * Set tags and states to reflect new line */ cline->tag = req->paddr >> captr->tag_shift; cline->vaddr = req->vaddr & block_mask2; if (pmshr->has_writes) cline->state = PR_DY; else cline->state = (req->req_type == REPLY_SH) ? SH_CL : PR_CL; } req->progress = 1; } if (req->progress == 1) { if (req->invl_req) { if ((lqueue_full(&(captr->l1i_partner->cohe_queue))) || (lqueue_full(&(captr->l1d_partner->cohe_queue)))) return 0; else { ireq->prcr_req_type = 0; ireq->wb_count = 0; lqueue_add(&(captr->l1i_partner->cohe_queue), ireq, captr->nodeid); captr->l1i_partner->inq_empty = 0; req->invl_req->prcr_req_type = 0; req->invl_req->wb_count = 0; lqueue_add(&(captr->l1d_partner->cohe_queue), req->invl_req, captr->nodeid); captr->l1d_partner->inq_empty = 0; } } if (cparam.L1D_writeback && req->invl_req) req->progress = 2; else req->progress = 3; } if (req->progress == 2) return 0; if (req->progress == 3) { /* * ready to send out a WRB to Data pipe or a REPL down, if any */ if (req->wrb_req) { if (AddToPipe(captr->data_pipe[L2ReqDATAPIPE], req->wrb_req)) { req->wrb_req->progress = 0; captr->num_in_pipes++; } else return 0; } req->progress = 4; /* ready to send REPLY to data pipe */ } if (AddToPipe(captr->data_pipe[L2ReqDATAPIPE], req)) { captr->num_in_pipes++; req->progress = 0; /* * Prepare release the request one by one, starting from the mainreq * (indicated by "next_move = -1". All the requests share the reply * type (REPLY_SH, REPLY_PR, or UPGRADE). */ pmshr = req->l2mshr; pmshr->next_move = -1; pmshr->releasing = 1; for (i = 0; i < pmshr->counter; i++) { REQ *tmpreq = pmshr->coal_req[i]; if ((tmpreq->hit_type != L1IHIT) && (tmpreq->hit_type != L1DHIT)) tmpreq->hit_type = L2HIT; tmpreq->req_type = req->req_type; tmpreq->line_cold = 0; } return 1; } /* couldn't go to Data pipe */ return 0;}int L2ProcessTagInvlReply(CACHE *captr, REQ *rtn_req){ REQ *req = rtn_req->parent; if (rtn_req->wb_count && req->wrb_req == 0) { req->wrb_req = Cache_make_req(captr, req->l2mshr->cline, REPLY_EXCL); req->wrb_req->type = WRITEBACK; req->wrb_req->parent = 0; /* not associated with any cohe */ } if (req) req->progress = 3; if (!req->cohe_count) YS__PoolReturnObj(&YS__ReqPool, rtn_req); return 1;}/*=========================================================================== * Uncoalesce each request coalesced in the specified MSHR. */static int L2Cache_uncoalesce_mshr(CACHE *captr, MSHR *pmshr){ HIT_TYPE hit_type = pmshr->mainreq->hit_type; int latepf = (pmshr->demand > 0.0); int i; REQ *tmpreq; /* * If this MSHR had a late prefetch, set prefetched_late field to allow * system to count every access coalesced into the MSHR as part of * "late PF" time in statistics. Is this reasonable? */ pmshr->mainreq->prefetched_late = latepf; if (pmshr->mainreq->prefetch == 8) { if (!pmshr->mainreq->cohe_count) YS__PoolReturnObj(&YS__ReqPool, pmshr->mainreq); } else Cache_global_perform(captr, pmshr->mainreq, 1); for (i = 0; i < pmshr->counter; i++) { REQ *req = pmshr->coal_req[i]; /* * In addition to latepf, also set hit_type of each coalesced REQUEST * to be L1HIT. This allows all of these times to be counted as the * appropriate component of execution time. */ if (req->ifetch) req->hit_type = L1IHIT; else req->hit_type = L1DHIT; req->prefetched_late = latepf; if (req->prefetch == 8) YS__errmsg(captr->nodeid, "L1Cache_uncoalesce_msrh: coalesced L1 prefetch"); Cache_global_perform(captr, req, 1); } /* * Take care of pending flush/purge requests. Generate a write-back * if flush hits a private dirty line. */ tmpreq = NULL; if (pmshr->pend_opers) { cline_t *cline = pmshr->cline; if (pmshr->pend_opers == FLUSHC && cline->state == PR_DY) { tmpreq = Cache_make_req(captr, cline, REPLY_EXCL); tmpreq->type = WRITEBACK; tmpreq->parent = 0; /* not associated with any cohe */ } if (cline->state != INVALID) { cline->state = INVALID; cline->tag = -1; if (cline->pref == 2) captr->pstats->sl2.useless++; else if (cline->pref == 8) captr->pstats->l2p.useless++; } } Cache_free_mshr(captr, pmshr); if (tmpreq) { if (lqueue_full(&(captr->outbuffer)) && captr->pending_writeback) { pmshr->mainreq->invl_req = tmpreq; return -1; } else Cache_start_send_to_bus(captr, tmpreq); } return 1;}/*=========================================================================== * L2ProcessTagReq: simulates accesses to the L2 cache tag array. * Its behavior depends on the type of message (i.e. type) received * This is very similar to L1ProcessTagReq, except where noted. * Returns 0 on failure; 1 on success. */int L2ProcessTagCohePipe(CACHE *captr, REQ *req){ switch (req->type) { case COHE: case REQUEST: return L2ProcessTagCohe(captr, req); case COHE_REPLY: if (req->prcr_req_type == FLUSHC) return L2ProcessTagFlushReply(captr, req); else if (captr->procid == req->src_proc) return L2ProcessTagInvlReply(captr, req); else return L2ProcessTagCoheReply(captr, req); } YS__errmsg(captr->nodeid, "L2TagProcessCohePipe: req not handled\n"); return 0;} int L2ProcessL1Reply(CACHE *captr, REQ *req){ if (req->prcr_req_type == FLUSHC) return L2ProcessTagFlushReply(captr, req); else if (captr->procid == req->src_proc) return L2ProcessTagInvlReply(captr, req); else return L2ProcessTagCoheReply(captr, req);} int L2ProcessTagCoheReply(CACHE *captr, REQ *req){ ReqType finalstate; if (req->parent->prcr_req_type == READ) finalstate = REPLY_SH; else finalstate = REPLY_EXCL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -