noncoherent_cache.cc revision 13564:9bbd53a77887
1/* 2 * Copyright (c) 2010-2018 ARM Limited 3 * All rights reserved. 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2002-2005 The Regents of The University of Michigan 15 * Copyright (c) 2010,2015 Advanced Micro Devices, Inc. 16 * All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions are 20 * met: redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer; 22 * redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution; 25 * neither the name of the copyright holders nor the names of its 26 * contributors may be used to endorse or promote products derived from 27 * this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Authors: Erik Hallnor 42 * Dave Greene 43 * Nathan Binkert 44 * Steve Reinhardt 45 * Ron Dreslinski 46 * Andreas Sandberg 47 * Nikos Nikoleris 48 */ 49 50/** 51 * @file 52 * Cache definitions. 53 */ 54 55#include "mem/cache/noncoherent_cache.hh" 56 57#include <cassert> 58 59#include "base/logging.hh" 60#include "base/trace.hh" 61#include "base/types.hh" 62#include "debug/Cache.hh" 63#include "mem/cache/cache_blk.hh" 64#include "mem/cache/mshr.hh" 65#include "params/NoncoherentCache.hh" 66 67NoncoherentCache::NoncoherentCache(const NoncoherentCacheParams *p) 68 : BaseCache(p, p->system->cacheLineSize()) 69{ 70} 71 72void 73NoncoherentCache::satisfyRequest(PacketPtr pkt, CacheBlk *blk, bool, bool) 74{ 75 // As this a non-coherent cache located below the point of 76 // coherency, we do not expect requests that are typically used to 77 // keep caches coherent (e.g., InvalidateReq or UpdateReq). 78 assert(pkt->isRead() || pkt->isWrite()); 79 BaseCache::satisfyRequest(pkt, blk); 80} 81 82bool 83NoncoherentCache::access(PacketPtr pkt, CacheBlk *&blk, Cycles &lat, 84 PacketList &writebacks) 85{ 86 bool success = BaseCache::access(pkt, blk, lat, writebacks); 87 88 if (pkt->isWriteback() || pkt->cmd == MemCmd::WriteClean) { 89 assert(blk && blk->isValid()); 90 // Writeback and WriteClean can allocate and fill even if the 91 // referenced block was not present or it was invalid. If that 92 // is the case, make sure that the new block is marked as 93 // writable 94 blk->status |= BlkWritable; 95 } 96 97 return success; 98} 99 100void 101NoncoherentCache::doWritebacks(PacketList& writebacks, Tick forward_time) 102{ 103 while (!writebacks.empty()) { 104 PacketPtr wb_pkt = writebacks.front(); 105 allocateWriteBuffer(wb_pkt, forward_time); 106 writebacks.pop_front(); 107 } 108} 109 110void 111NoncoherentCache::doWritebacksAtomic(PacketList& writebacks) 112{ 113 while (!writebacks.empty()) { 114 PacketPtr wb_pkt = writebacks.front(); 115 memSidePort.sendAtomic(wb_pkt); 116 writebacks.pop_front(); 117 delete wb_pkt; 118 } 119} 120 121void 122NoncoherentCache::handleTimingReqMiss(PacketPtr pkt, CacheBlk *blk, 123 Tick forward_time, Tick request_time) 124{ 125 // miss 126 Addr blk_addr = pkt->getBlockAddr(blkSize); 127 MSHR *mshr = mshrQueue.findMatch(blk_addr, pkt->isSecure(), false); 128 129 // We can always write to a non coherent cache if the block is 130 // present and therefore if we have reached this point then the 131 // block should not be in the cache. 132 assert(mshr || !blk || !blk->isValid()); 133 134 BaseCache::handleTimingReqMiss(pkt, mshr, blk, forward_time, request_time); 135} 136 137void 138NoncoherentCache::recvTimingReq(PacketPtr pkt) 139{ 140 panic_if(pkt->cacheResponding(), "Should not see packets where cache " 141 "is responding"); 142 143 panic_if(!(pkt->isRead() || pkt->isWrite()), 144 "Should only see read and writes at non-coherent cache\n"); 145 146 BaseCache::recvTimingReq(pkt); 147} 148 149PacketPtr 150NoncoherentCache::createMissPacket(PacketPtr cpu_pkt, CacheBlk *blk, 151 bool needs_writable, 152 bool is_whole_line_write) const 153{ 154 // We also fill for writebacks from the coherent caches above us, 155 // and they do not need responses 156 assert(cpu_pkt->needsResponse()); 157 158 // A miss can happen only due to missing block 159 assert(!blk || !blk->isValid()); 160 161 PacketPtr pkt = new Packet(cpu_pkt->req, MemCmd::ReadReq, blkSize); 162 163 // the packet should be block aligned 164 assert(pkt->getAddr() == pkt->getBlockAddr(blkSize)); 165 166 pkt->allocate(); 167 DPRINTF(Cache, "%s created %s from %s\n", __func__, pkt->print(), 168 cpu_pkt->print()); 169 return pkt; 170} 171 172 173Cycles 174NoncoherentCache::handleAtomicReqMiss(PacketPtr pkt, CacheBlk *&blk, 175 PacketList &writebacks) 176{ 177 PacketPtr bus_pkt = createMissPacket(pkt, blk, true, 178 pkt->isWholeLineWrite(blkSize)); 179 DPRINTF(Cache, "Sending an atomic %s\n", bus_pkt->print()); 180 181 Cycles latency = ticksToCycles(memSidePort.sendAtomic(bus_pkt)); 182 183 assert(bus_pkt->isResponse()); 184 // At the moment the only supported downstream requests we issue 185 // are ReadReq and therefore here we should only see the 186 // corresponding responses 187 assert(bus_pkt->isRead()); 188 assert(pkt->cmd != MemCmd::UpgradeResp); 189 assert(!bus_pkt->isInvalidate()); 190 assert(!bus_pkt->hasSharers()); 191 192 // We are now dealing with the response handling 193 DPRINTF(Cache, "Receive response: %s\n", bus_pkt->print()); 194 195 if (!bus_pkt->isError()) { 196 // Any reponse that does not have an error should be filling, 197 // afterall it is a read response 198 DPRINTF(Cache, "Block for addr %#llx being updated in Cache\n", 199 bus_pkt->getAddr()); 200 blk = handleFill(bus_pkt, blk, writebacks, allocOnFill(bus_pkt->cmd)); 201 assert(blk); 202 } 203 satisfyRequest(pkt, blk); 204 205 maintainClusivity(true, blk); 206 207 // Use the separate bus_pkt to generate response to pkt and 208 // then delete it. 209 if (!pkt->isWriteback() && pkt->cmd != MemCmd::WriteClean) { 210 assert(pkt->needsResponse()); 211 pkt->makeAtomicResponse(); 212 if (bus_pkt->isError()) { 213 pkt->copyError(bus_pkt); 214 } 215 } 216 217 delete bus_pkt; 218 219 return latency; 220} 221 222Tick 223NoncoherentCache::recvAtomic(PacketPtr pkt) 224{ 225 panic_if(pkt->cacheResponding(), "Should not see packets where cache " 226 "is responding"); 227 228 panic_if(!(pkt->isRead() || pkt->isWrite()), 229 "Should only see read and writes at non-coherent cache\n"); 230 231 return BaseCache::recvAtomic(pkt); 232} 233 234 235void 236NoncoherentCache::functionalAccess(PacketPtr pkt, bool from_cpu_side) 237{ 238 panic_if(!from_cpu_side, "Non-coherent cache received functional snoop" 239 " request\n"); 240 241 BaseCache::functionalAccess(pkt, from_cpu_side); 242} 243 244void 245NoncoherentCache::serviceMSHRTargets(MSHR *mshr, const PacketPtr pkt, 246 CacheBlk *blk) 247{ 248 MSHR::Target *initial_tgt = mshr->getTarget(); 249 // First offset for critical word first calculations 250 const int initial_offset = initial_tgt->pkt->getOffset(blkSize); 251 252 MSHR::TargetList targets = mshr->extractServiceableTargets(pkt); 253 for (auto &target: targets) { 254 Packet *tgt_pkt = target.pkt; 255 256 switch (target.source) { 257 case MSHR::Target::FromCPU: 258 // handle deferred requests comming from a cache or core 259 // above 260 261 Tick completion_time; 262 // Here we charge on completion_time the delay of the xbar if the 263 // packet comes from it, charged on headerDelay. 264 completion_time = pkt->headerDelay; 265 266 satisfyRequest(tgt_pkt, blk); 267 268 // How many bytes past the first request is this one 269 int transfer_offset; 270 transfer_offset = tgt_pkt->getOffset(blkSize) - initial_offset; 271 if (transfer_offset < 0) { 272 transfer_offset += blkSize; 273 } 274 // If not critical word (offset) return payloadDelay. 275 // responseLatency is the latency of the return path 276 // from lower level caches/memory to an upper level cache or 277 // the core. 278 completion_time += clockEdge(responseLatency) + 279 (transfer_offset ? pkt->payloadDelay : 0); 280 281 assert(tgt_pkt->req->masterId() < system->maxMasters()); 282 missLatency[tgt_pkt->cmdToIndex()][tgt_pkt->req->masterId()] += 283 completion_time - target.recvTime; 284 285 tgt_pkt->makeTimingResponse(); 286 if (pkt->isError()) 287 tgt_pkt->copyError(pkt); 288 289 // Reset the bus additional time as it is now accounted for 290 tgt_pkt->headerDelay = tgt_pkt->payloadDelay = 0; 291 cpuSidePort.schedTimingResp(tgt_pkt, completion_time); 292 break; 293 294 case MSHR::Target::FromPrefetcher: 295 // handle deferred requests comming from a prefetcher 296 // attached to this cache 297 assert(tgt_pkt->cmd == MemCmd::HardPFReq); 298 299 if (blk) 300 blk->status |= BlkHWPrefetched; 301 302 // We have filled the block and the prefetcher does not 303 // require responses. 304 delete tgt_pkt; 305 break; 306 307 default: 308 // we should never see FromSnoop Targets as this is a 309 // non-coherent cache 310 panic("Illegal target->source enum %d\n", target.source); 311 } 312 } 313 314 // Reponses are filling and bring in writable blocks, therefore 315 // there should be no deferred targets and all the non-deferred 316 // targets are now serviced. 317 assert(mshr->getNumTargets() == 0); 318} 319 320void 321NoncoherentCache::recvTimingResp(PacketPtr pkt) 322{ 323 assert(pkt->isResponse()); 324 // At the moment the only supported downstream requests we issue 325 // are ReadReq and therefore here we should only see the 326 // corresponding responses 327 assert(pkt->isRead()); 328 assert(pkt->cmd != MemCmd::UpgradeResp); 329 assert(!pkt->isInvalidate()); 330 // This cache is non-coherent and any memories below are 331 // non-coherent too (non-coherent caches or the main memory), 332 // therefore the fetched block can be marked as writable. 333 assert(!pkt->hasSharers()); 334 335 BaseCache::recvTimingResp(pkt); 336} 337 338PacketPtr 339NoncoherentCache::evictBlock(CacheBlk *blk) 340{ 341 // A dirty block is always written back. 342 343 // A clean block can we written back, if we turned on writebacks 344 // for clean blocks. This could be useful if there is a cache 345 // below and we want to make sure the block is cached but if the 346 // memory below is the main memory WritebackCleans are 347 // unnecessary. 348 349 // If we clean writebacks are not enabled, we do not take any 350 // further action for evictions of clean blocks (i.e., CleanEvicts 351 // are unnecessary). 352 PacketPtr pkt = (blk->isDirty() || writebackClean) ? 353 writebackBlk(blk) : nullptr; 354 355 invalidateBlock(blk); 356 357 return pkt; 358} 359 360NoncoherentCache* 361NoncoherentCacheParams::create() 362{ 363 assert(tags); 364 assert(replacement_policy); 365 366 return new NoncoherentCache(this); 367} 368