📄 l2cache.c
字号:
/* * Tell MMC the coherence results. Note: do this before sending * cache-to-cache copy. */ if ((req->type == COHE) && (req->wb_count || req->wrb_req)) { REQ *blw_req = Cache_make_wb_req(captr, req->parent, finalstate); /* * cache-to-cache transaction needs to access the data SRAM array. */ if (!AddToPipe(captr->data_pipe[L2ReqDATAPIPE], blw_req)) { if (captr->data_cohe_pending) YS__errmsg(captr->nodeid, "Something is wrong: two data_cohe_pendings."); captr->data_cohe_pending = blw_req; captr->inq_empty = 0; } else captr->num_in_pipes++; } Bus_send_cohe_response(req->parent, finalstate); YS__PoolReturnObj(&YS__ReqPool, req); return 1;}/*=========================================================================== * L2ProcessTagCohe: simulates coherence accesses to the L2 cache tag array. * Returns 0 on failure; 1 on success. */static int L2ProcessTagCohe(CACHE * captr, REQ *req){ int i, misscache; cline_state_t oldstate; MSHR *pmshr; cline_t *cline; REQ *blw_req, *abvi_req, *abvd_req; if (cparam.L2_perfect) { Bus_send_cohe_response(req, REPLY_EXCL); return 1; } if (captr->stall_cohe || captr->cohe_reply) return 0; /* * Was the request initiated by this processor? If yes, there is * nothing to do here, except setting pending_cohe. To put own requests * into coherence waiting queue just to keep the order of coherence * requests. */ if (req->src_proc == captr->procid) { req->issued = 1; if (req->l2mshr->pending_cohe) return 0; else { if (req->progress == 0) { req->l2mshr->pending_cohe = req; req->stalled_mshrs[captr->procid] = req->l2mshr; } Bus_send_cohe_response(req, REPLY_EXCL); return 1; } } /* * First, check if the line is in the L1 write back buffer. If yes, * stall the cohe until the write has been moved to L2 cache. */ if (!cparam.L1D_writeback && L1DCache_wbuffer_search(PID2WBUF(0, captr->procid), req, 1) != 0) { captr->stall_cohe++; return 0; } /* * Then, check if the line is in the outgoing buffer. If yes, * convert the write request to coherency data response. */ if (Cache_check_outbuffer(captr, req) != NULL) return 0; /* * Determine if there is a matched MSHR. Note: only one coherence * request -- the first one -- is allowed to overpass any coalesced * requests of an MSHR. Too strict? */ pmshr = 0; if (captr->mshr_count > 0) { unsigned blocknum = ADDR2BNUM2(req->paddr); for (i = 0; i < captr->max_mshrs; i++) { if ((captr->mshrs[i].valid) && (blocknum == captr->mshrs[i].blocknum)) { pmshr = &(captr->mshrs[i]); break; } } } if ((pmshr != 0) && (req->progress == 0)) { if ((!pmshr->pending_cohe)) { pmshr->pending_cohe = req; req->stalled_mshrs[captr->procid] = pmshr; } if (pmshr->mainreq->issued) return(0); } /* * Calls Cache_search to find out if the line is present. * If the line isn't present, just send the cohe response. * If the line is present, inform L1 caches if the line state is changed; * and generate a cache-to-cache copy if the line is in dirty state. */ misscache = Cache_search(captr, req->vaddr, req->paddr, &cline); if (misscache) { /* missing in L2 cache implies missing in L1 cache. */ Bus_send_cohe_response(req, REPLY_EXCL); return 1; } oldstate = cline->state; if ((req->type == REQUEST) && (req->req_type == READ_SH)) cline->state = SH_CL; if (((req->type == REQUEST) && ((req->req_type == READ_OWN) || req->req_type == UPGRADE)) || (req->type == WRITEPURGE)) { cline->state = INVALID; if (cline->pref == 2) captr->pstats->sl2.useless++; else if (cline->pref == 8) captr->pstats->l2p.useless++; } blw_req = NULL; abvi_req = NULL; abvd_req = NULL; if (cparam.L1D_writeback) { abvi_req = Cache_make_cohe_to_l1(captr, req, cline->state); abvi_req->parent = req; abvi_req->wrb_req = (REQ*)(oldstate == PR_DY); abvd_req = Cache_make_cohe_to_l1(captr, req, cline->state); abvd_req->parent = req; abvd_req->wrb_req = (REQ*)(oldstate == PR_DY); } else { if ((oldstate == PR_DY) && (req->type == REQUEST) && ((req->req_type == READ_OWN) || (req->req_type == READ_SH) || (req->req_type == READ_CURRENT) || (req->req_type == UPGRADE))) blw_req = Cache_make_wb_req(captr, req, (cline->state == SH_CL) ? REPLY_SH : REPLY_EXCL); if (cline->state != oldstate) { abvi_req = Cache_make_cohe_to_l1(captr, req, cline->state); abvi_req->parent = req; abvd_req = Cache_make_cohe_to_l1(captr, req, cline->state); abvd_req->parent = req; } } /* * L1 cohe_queue is as big as L2 reply queue and L1 is faster than L2, * so, theorertically, L1 cohe_queue will never overflow. */ if (abvd_req) { if ((lqueue_full(&(captr->l1i_partner->cohe_queue))) || (lqueue_full(&(captr->l1d_partner->cohe_queue)))) YS__errmsg(captr->nodeid, "Somehow, the L1 cohe_queue is full"); abvi_req->wb_count = 0; abvi_req->prcr_req_type = 0; abvd_req->wb_count = 0; abvd_req->prcr_req_type = 0; lqueue_add(&(captr->l1i_partner->cohe_queue), abvi_req, captr->nodeid); captr->l1i_partner->inq_empty = 0; lqueue_add(&(captr->l1d_partner->cohe_queue), abvd_req, captr->nodeid); captr->l1d_partner->inq_empty = 0; } /* * For write-back L1 cache, the cohe responese will be sent during * CoheReply */ if (cparam.L1D_writeback) return 1; /* * Tell MMC the coherence results. Note: do this before sending * cache-to-cache copy. */ if (req->req_type == READ_CURRENT) Bus_send_cohe_response(req, REPLY_EXCL); else if (cline->state == SH_CL) Bus_send_cohe_response(req, REPLY_SH); else if (cline->state == INVALID) /* && (req->type != WRITEPURGE)) */ Bus_send_cohe_response(req, REPLY_EXCL); /* * cache-to-cache transaction needs to access the data SRAM array. */ if (blw_req) { if (!AddToPipe(captr->data_pipe[L2ReqDATAPIPE], blw_req)) { if (captr->data_cohe_pending) YS__errmsg(captr->nodeid, "Something is wrong: two data_cohe_pendings at L2 Cache #%i.", captr->gid); captr->data_cohe_pending = blw_req; captr->inq_empty = 0; } else captr->num_in_pipes++; } return 1;}/*=========================================================================== * Make a cache-to-cache transfer reply. */static REQ *Cache_make_wb_req(CACHE *captr, REQ *req, ReqType req_type){ REQ *tmpreq; req->c2c_copy = 1; tmpreq = (REQ *) YS__PoolGetObj(&YS__ReqPool); tmpreq->node = captr->nodeid; tmpreq->src_proc = captr->procid; tmpreq->dest_proc = req->src_proc; tmpreq->memattributes = req->memattributes; tmpreq->vaddr = req->vaddr; tmpreq->paddr = req->paddr; tmpreq->ifetch = 0; tmpreq->parent = req; tmpreq->req_type = req_type; tmpreq->type = COHE; /* This will be changed to COHE_REPLY by L2ProcessDataReq */ return tmpreq;}/*=========================================================================== * Make a cohe-request sent to L1 cache. */static REQ *Cache_make_cohe_to_l1(CACHE *captr, REQ *req, int state){ REQ *tmpreq; /* @@@ fix @@@ */ tmpreq = (REQ *) YS__PoolGetObj(&YS__ReqPool); tmpreq->node = req->node; tmpreq->src_proc = req->src_proc; tmpreq->req_type = (state == SH_CL) ? SHARED : INVALIDATE; tmpreq->type = req->type == WRITEPURGE ? WRITEPURGE : COHE; tmpreq->paddr = req->paddr & block_mask2; tmpreq->vaddr = req->vaddr & block_mask2; tmpreq->ifetch = 0; return tmpreq;}/*=========================================================================== * Try to handle a L2 reply classified as one of the followings: * - write hit in L1 cache, nothing to do; * - not L1-allocated type, do global perform here; * - otherwise, put it into the reply queue of L1 cache. */static int Cache_add_repl_to_l1(CACHE *captr, REQ *req){ if (req->prefetch == 8) { /* * This is an L2 prefetch, has nothing to do with L1 cache. */ if (!req->cohe_count) YS__PoolReturnObj(&YS__ReqPool, req); return 1; } if (req->hit_type == L1DHIT) { /* * This is a write hit in L1 cache. Global perform has been done in * l1 cache. Just release the request here. */ if (!req->cohe_count) YS__PoolReturnObj(&YS__ReqPool, req); return 1; } if (req->l1mshr == 0) { /* * This request hasn't allocated an MSHR in L1 cache, or say * it is not L1-allocate type. We can just release it here. */ Cache_global_perform(captr, req, 1); return 1; } if (req->ifetch) { if (lqueue_full(&(captr->l1i_partner->reply_queue))) return 0; else { lqueue_add(&(captr->l1i_partner->reply_queue), req, captr->nodeid); req->progress = 0; captr->l1i_partner->inq_empty = 0; return 1; } } else { if (lqueue_full(&(captr->l1d_partner->reply_queue))) return 0; else { lqueue_add(&(captr->l1d_partner->reply_queue), req, captr->nodeid); req->progress = 0; captr->l1d_partner->inq_empty = 0; return 1; } }}/*============================================================================= * Start a L1-initiated prefetch. If L1Q is full, drop the prefetch. * Note that prefetch can not cross page boundary and no prefetch for * non-cacheable address. */static void L2Cache_start_prefetch(CACHE *captr, REQ *req){ REQ *newreq; unsigned newpaddr = req->paddr + captr->linesz; if (!SAMEPAGE(req->paddr, newpaddr) || tlb_uncached(req->memattributes)) return; captr->pstats->l2p.total++; if (lqueue_full(&(captr->request_queue))) { captr->pstats->l2p.dropped++; return; } /* * General information */ newreq = (REQ *) YS__PoolGetObj(&YS__ReqPool); newreq->type = REQUEST; newreq->req_type = READ; newreq->prefetch = 8; newreq->node = captr->nodeid; newreq->src_proc = captr->procid; newreq->prcr_req_type = req->prcr_req_type; newreq->paddr = newpaddr; newreq->vaddr = req->vaddr + captr->linesz; newreq->ifetch = req->ifetch; newreq->l1mshr = 0; newreq->l2mshr = 0; newreq->memattributes = req->memattributes; newreq->line_cold = 0; /* * for statistics */ newreq->issue_time = YS__Simtime; newreq->hit_type = UNKHIT; newreq->line_cold = 0; /* * Add it to REQUEST input queue of L1 cache, which must then know that * there is something on its input queue so as to be activated by * cycle-by-cycle simulator. If this access fills up the port, the * L1Q_FULL variable is set so that the processor does not issue any * more memory references until the port clears up. */ lqueue_add(&(captr->request_queue), newreq, captr->nodeid); captr->inq_empty = 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -