noncoherent_cache.cc revision 13859
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 // First offset for critical word first calculations 249 const int initial_offset = mshr->getTarget()->pkt->getOffset(blkSize); 250 251 MSHR::TargetList targets = mshr->extractServiceableTargets(pkt); 252 for (auto &target: targets) { 253 Packet *tgt_pkt = target.pkt; 254 255 switch (target.source) { 256 case MSHR::Target::FromCPU: 257 // handle deferred requests comming from a cache or core 258 // above 259 260 Tick completion_time; 261 // Here we charge on completion_time the delay of the xbar if the 262 // packet comes from it, charged on headerDelay. 263 completion_time = pkt->headerDelay; 264 265 satisfyRequest(tgt_pkt, blk); 266 267 // How many bytes past the first request is this one 268 int transfer_offset; 269 transfer_offset = tgt_pkt->getOffset(blkSize) - initial_offset; 270 if (transfer_offset < 0) { 271 transfer_offset += blkSize; 272 } 273 // If not critical word (offset) return payloadDelay. 274 // responseLatency is the latency of the return path 275 // from lower level caches/memory to an upper level cache or 276 // the core. 277 completion_time += clockEdge(responseLatency) + 278 (transfer_offset ? pkt->payloadDelay : 0); 279 280 assert(tgt_pkt->req->masterId() < system->maxMasters()); 281 missLatency[tgt_pkt->cmdToIndex()][tgt_pkt->req->masterId()] += 282 completion_time - target.recvTime; 283 284 tgt_pkt->makeTimingResponse(); 285 if (pkt->isError()) 286 tgt_pkt->copyError(pkt); 287 288 // Reset the bus additional time as it is now accounted for 289 tgt_pkt->headerDelay = tgt_pkt->payloadDelay = 0; 290 cpuSidePort.schedTimingResp(tgt_pkt, completion_time); 291 break; 292 293 case MSHR::Target::FromPrefetcher: 294 // handle deferred requests comming from a prefetcher 295 // attached to this cache 296 assert(tgt_pkt->cmd == MemCmd::HardPFReq); 297 298 if (blk) 299 blk->status |= BlkHWPrefetched; 300 301 // We have filled the block and the prefetcher does not 302 // require responses. 303 delete tgt_pkt; 304 break; 305 306 default: 307 // we should never see FromSnoop Targets as this is a 308 // non-coherent cache 309 panic("Illegal target->source enum %d\n", target.source); 310 } 311 } 312 313 // Reponses are filling and bring in writable blocks, therefore 314 // there should be no deferred targets and all the non-deferred 315 // targets are now serviced. 316 assert(mshr->getNumTargets() == 0); 317} 318 319void 320NoncoherentCache::recvTimingResp(PacketPtr pkt) 321{ 322 assert(pkt->isResponse()); 323 // At the moment the only supported downstream requests we issue 324 // are ReadReq and therefore here we should only see the 325 // corresponding responses 326 assert(pkt->isRead()); 327 assert(pkt->cmd != MemCmd::UpgradeResp); 328 assert(!pkt->isInvalidate()); 329 // This cache is non-coherent and any memories below are 330 // non-coherent too (non-coherent caches or the main memory), 331 // therefore the fetched block can be marked as writable. 332 assert(!pkt->hasSharers()); 333 334 BaseCache::recvTimingResp(pkt); 335} 336 337PacketPtr 338NoncoherentCache::evictBlock(CacheBlk *blk) 339{ 340 // A dirty block is always written back. 341 342 // A clean block can we written back, if we turned on writebacks 343 // for clean blocks. This could be useful if there is a cache 344 // below and we want to make sure the block is cached but if the 345 // memory below is the main memory WritebackCleans are 346 // unnecessary. 347 348 // If we clean writebacks are not enabled, we do not take any 349 // further action for evictions of clean blocks (i.e., CleanEvicts 350 // are unnecessary). 351 PacketPtr pkt = (blk->isDirty() || writebackClean) ? 352 writebackBlk(blk) : nullptr; 353 354 invalidateBlock(blk); 355 356 return pkt; 357} 358 359NoncoherentCache* 360NoncoherentCacheParams::create() 361{ 362 assert(tags); 363 assert(replacement_policy); 364 365 return new NoncoherentCache(this); 366} 367