⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l2cache.c

📁 ml-rsim 多处理器模拟器 支持类bsd操作系统
💻 C
📖 第 1 页 / 共 4 页
字号:
  /*   * 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 + -