📄 l2cache.c
字号:
/* * Copyright (c) 2002 The Board of Trustees of the University of Illinois and * William Marsh Rice University * Copyright (c) 2002 The University of Utah * Copyright (c) 2002 The University of Notre Dame du Lac * * All rights reserved. * * Based on RSIM 1.0, developed by: * Professor Sarita Adve's RSIM research group * University of Illinois at Urbana-Champaign and William Marsh Rice University * http://www.cs.uiuc.edu/rsim and http://www.ece.rice.edu/~rsim/dist.html * ML-RSIM/URSIM extensions by: * The Impulse Research Group, University of Utah * http://www.cs.utah.edu/impulse * Lambert Schaelicke, University of Utah and University of Notre Dame du Lac * http://www.cse.nd.edu/~lambert * Mike Parker, University of Utah * http://www.cs.utah.edu/~map * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal with the Software without restriction, including without * limitation the rights to use, copy, modify, merge, publish, distribute, * sublicense, and/or sell copies of the Software, and to permit persons to * whom the Software is furnished to do so, subject to the following * conditions: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimers. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimers in the * documentation and/or other materials provided with the distribution. * 3. Neither the names of Professor Sarita Adve's RSIM research group, * the University of Illinois at Urbana-Champaign, William Marsh Rice * University, nor the names of its contributors may be used to endorse * or promote products derived from this Software without specific prior * written permission. * 4. Neither the names of the ML-RSIM project, the URSIM project, the * Impulse research group, the University of Utah, the University of * Notre Dame du Lac, nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS WITH THE SOFTWARE. */#include <stdio.h>#include <malloc.h>#include "Processor/capconf.h"#include "Processor/simio.h"#include "Processor/memunit.h"#include "Processor/tlb.h"#include "sim_main/simsys.h"#include "Caches/system.h"#include "Caches/req.h"#include "Caches/pipeline.h"#include "Caches/cache.h"#include "Caches/ubuf.h"#include "Caches/syscontrol.h"#include "IO/addr_map.h"#include "Bus/bus.h"/* * Macros which specify which pipeline each type of access belongs to. * * A separate COHE tag pipe is added to avoid deadlock. Such a port may be * considered excessive in a real system; thus, it may be advisable to * reserve a certain number of MSHR-like buffers for incoming COHE messages * and simply withhold processing of additional COHEs until space opens up * in one of these buffers. */#define L2ReqDATAPIPE 0#define L2ReplyTAGPIPE 0#define L2CoheTAGPIPE 1#define L2RequestTAGPIPE 2/* * Functions to process request */static int L2ProcessDataReq (CACHE*, REQ*);static int L2ProcessTagRequest (CACHE*, REQ*);static int L2ProcessTagReply (CACHE*, REQ*);static int L2ProcessTagCohe (CACHE*, REQ*);static int L2ProcessTagCoheReply (CACHE*, REQ*);static int L2ProcessFlushPurge (CACHE*, REQ*);static REQ *Cache_make_wb_req (CACHE*, REQ*, ReqType);static REQ *Cache_make_cohe_to_l1 (CACHE*, REQ*, int state);static int Cache_add_repl_to_l1 (CACHE*, REQ*);static MSHR_Response L2Cache_check_mshr (CACHE*, REQ*);static void L2Cache_start_prefetch (CACHE*, REQ*);static int L2Cache_uncoalesce_mshr (CACHE*, MSHR*);/*=========================================================================== * L2CacheInSim: function that brings new transactions from the ports into * the pipelines associated with the various cache parts. An operation can * be removed from its port as soon as pipeline space opens up for it. * Called whenever there may be something on an input port. */void L2CacheInSim(int gid){ CACHE *captr = L2Caches[gid]; REQ *req; int nothing_on_ports = 1; /* First check if there is a pending cache-to-cache copy ================*/ if (captr->data_cohe_pending) if (AddToPipe(captr->data_pipe[L2ReqDATAPIPE], captr->data_cohe_pending)) { captr->data_cohe_pending = 0; captr->num_in_pipes++; } /* Coherence queue first because somebody else is waiting for you =======*/ while (req = lqueue_head(&captr->cohe_queue)) { if (AddToPipe(captr->tag_pipe[L2CoheTAGPIPE], req)) { req->progress = 0; lqueue_remove(&(captr->cohe_queue)); captr->num_in_pipes++; } else { nothing_on_ports = 0; break; } } req = lqueue_head(&captr->noncohe_queue); if (req != NULL) { if ((IsSysControl_external(req, gid % ARCH_cpus)) || (IsSysControl_local(req))) { if (SysControl_external_request(gid, req)) { lqueue_remove(&(captr->noncohe_queue)); } else nothing_on_ports = 0; } else YS__errmsg(captr->nodeid, "Unknown request type in noncoherent queue\n"); } /* Reply queue is always handled before request queue ===================*/ while (req = lqueue_head(&captr->reply_queue)) { if (AddToPipe(captr->tag_pipe[L2ReplyTAGPIPE], req)) { req->progress = 0; lqueue_remove(&(captr->reply_queue)); captr->num_in_pipes++; } else { nothing_on_ports = 0; break; } } /* Request queue ========================================================*/ while (req = lqueue_head(&captr->request_queue)) { if (AddToPipe(captr->tag_pipe[L2RequestTAGPIPE], req)) { req->progress = 0; lqueue_remove(&(captr->request_queue)); captr->num_in_pipes++; } else { nothing_on_ports = 0; break; } } if (nothing_on_ports) captr->inq_empty = 1;}/*=========================================================================== * L2CacheOutSim: initiates actual processing of various REQ types * Called each cycle that there is something in pipes to be processed */void L2CacheOutSim(int gid){ CACHE *captr = L2Caches[gid]; Pipeline *pipe; REQ *req; int pipenum, ctr, index, result; /* * NOTE: L2 is not a monolithic piece of SRAM like the L1. The L2 is split * into a "tag SRAM" array and a "data SRAM" array. So, this function needs * to look at both tag pipes and data pipes. It looks at data pipes first, * as tag pipes might push something into data pipes, but never the other * way around. */ for (pipenum = 0; pipenum < L2_DATA_PIPES; pipenum++) { pipe = captr->data_pipe[pipenum]; for (ctr = 0; ctr < pipe->ports; ctr++) { GetPipeElt(req, pipe); if (req == 0) break; result = L2ProcessDataReq(captr, req); if (result == 1) { ClearPipeElt(pipe); captr->num_in_pipes--; } else if (result == -1) { SetPipeElt(req->invl_req, pipe); req->invl_req = 0; } } } /*------------------------------------------------------------------------- * Process tag pipelines. First, process reply queue; then, process * coherence request queue; Finally, it's request queue's turn. */ if (!captr->stall_reply) { pipe = captr->tag_pipe[L2ReplyTAGPIPE]; for (ctr = 0; ctr < pipe->ports; ctr++) { GetPipeElt(req, pipe); if (req == 0) break; result = L2ProcessTagReply(captr, req); if (result == 1) { ClearPipeElt(pipe); captr->num_in_pipes--; } else if (result == -1) { SetPipeElt(req->invl_req, pipe); req->invl_req = 0; } } } if (!captr->stall_cohe && !captr->cohe_reply) { pipe = captr->tag_pipe[L2CoheTAGPIPE]; for (ctr = 0; ctr < pipe->ports; ctr++) { GetPipeElt(req, pipe); if (req == 0) break; if (L2ProcessTagCohe(captr, req)) { ClearPipeElt(pipe); captr->num_in_pipes--; captr->pstats->snoop_requests++; } } } /*-----------------------------------------------------------------------*/ if (!captr->stall_request) { pipe = captr->tag_pipe[L2RequestTAGPIPE]; for (ctr = 0; ctr < pipe->ports; ctr++) { GetPipeElt(req, pipe); if (req == 0) break; result = L2ProcessTagRequest(captr, req); if (result == 0) /* ?? */ break; if (result == 1) { ClearPipeElt(pipe); captr->num_in_pipes--; } else if (result == -1) { SetPipeElt(req->invl_req, pipe); req->invl_req = 0; } } }}/*=========================================================================== * L2ProcessDataReq: simulates accesses to the L2 data SRAM array, * Returns 0 on failure; 1 on success. No equivalent function in L1. */int L2ProcessDataReq(CACHE *captr, REQ * req){ switch (req->type) { case REQUEST: /* * A cache hit that gets sent back to the L1. Change it to REPLY. */ if (req->req_type == WBACK) { YS__PoolReturnObj(&YS__ReqPool, req); return 1; } if (req->progress == 0) { req->progress = 1; req->type = REPLY; } /* * Try to send it up to L1 cache. Cache_add_repl_to_l1 returns 1 on * success, and 0 on failure. This request will be awoken in REPLY case, * which just seeks to send up access also. */ return Cache_add_repl_to_l1(captr, req); case REPLY: if (req->l2mshr == 0) { /* * It's a stalled L2 hit (came from REQUEST). */ return Cache_add_repl_to_l1(captr, req); } else { MSHR *pmshr = req->l2mshr; REQ *tmpreq; /* * It was an L2 miss. We have to release all the coalesced requests * one by one; and the flush/purge request if exists. */ if (Cache_add_repl_to_l1(captr, req) == 0) return 0; pmshr->next_move++; for (; pmshr->next_move < pmshr->counter; pmshr->next_move++) { tmpreq = pmshr->coal_req[pmshr->next_move]; if (Cache_add_repl_to_l1(captr, tmpreq) == 0) { tmpreq->l2mshr = pmshr; req->invl_req = tmpreq; return -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++; } } /* * All coalesced requests either have been sent back to L1 cache, or * have performed GlobalPerform. Release the MSHR now. */ Cache_free_mshr(captr, pmshr); if (tmpreq) { if (!lqueue_full(&(captr->outbuffer)) || !captr->pending_writeback) { Cache_start_send_to_bus(captr, tmpreq); return 1; } else { req->invl_req = tmpreq; return -1; } } } return 1; case COHE: /* * This is a cache-to-cache copy. Only one cache-to-cache copy * is allowed at one time. */ if (captr->cohe_reply) return 0; else { req->type = COHE_REPLY; Cache_start_send_to_bus(captr, req); return 1; } case WRITEBACK: /*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -