base.hh revision 3170
1/* 2 * Copyright (c) 2003-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * Authors: Erik Hallnor 29 */ 30 31/** 32 * @file 33 * Declares a basic cache interface BaseCache. 34 */ 35 36#ifndef __BASE_CACHE_HH__ 37#define __BASE_CACHE_HH__ 38 39#include <vector> 40#include <string> 41#include <list> 42#include <inttypes.h> 43 44#include "base/misc.hh" 45#include "base/statistics.hh" 46#include "base/trace.hh" 47#include "mem/mem_object.hh" 48#include "mem/packet.hh" 49#include "mem/port.hh" 50#include "mem/request.hh" 51#include "sim/eventq.hh" 52 53/** 54 * Reasons for Caches to be Blocked. 55 */ 56enum BlockedCause{ 57 Blocked_NoMSHRs, 58 Blocked_NoTargets, 59 Blocked_NoWBBuffers, 60 Blocked_Coherence, 61 Blocked_Copy, 62 NUM_BLOCKED_CAUSES 63}; 64 65/** 66 * Reasons for cache to request a bus. 67 */ 68enum RequestCause{ 69 Request_MSHR, 70 Request_WB, 71 Request_Coherence, 72 Request_PF 73}; 74 75/** 76 * A basic cache interface. Implements some common functions for speed. 77 */ 78class BaseCache : public MemObject 79{ 80 class CachePort : public Port 81 { 82 public: 83 BaseCache *cache; 84 85 CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide); 86 87 protected: 88 virtual bool recvTiming(Packet *pkt); 89 90 virtual Tick recvAtomic(Packet *pkt); 91 92 virtual void recvFunctional(Packet *pkt); 93 94 virtual void recvStatusChange(Status status); 95 96 virtual void getDeviceAddressRanges(AddrRangeList &resp, 97 AddrRangeList &snoop); 98 99 virtual int deviceBlockSize(); 100 101 virtual void recvRetry(); 102 103 public: 104 void setBlocked(); 105 106 void clearBlocked(); 107 108 bool blocked; 109 110 bool mustSendRetry; 111 112 bool isCpuSide; 113 114 std::list<Packet *> drainList; 115 }; 116 117 struct CacheEvent : public Event 118 { 119 CachePort *cachePort; 120 Packet *pkt; 121 122 CacheEvent(CachePort *_cachePort); 123 CacheEvent(CachePort *_cachePort, Packet *_pkt); 124 void process(); 125 const char *description(); 126 }; 127 128 protected: 129 CachePort *cpuSidePort; 130 CachePort *memSidePort; 131 132 bool snoopRangesSent; 133 134 public: 135 virtual Port *getPort(const std::string &if_name, int idx = -1); 136 137 private: 138 //To be defined in cache_impl.hh not in base class 139 virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide) 140 { 141 fatal("No implementation"); 142 } 143 144 virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide) 145 { 146 fatal("No implementation"); 147 } 148 149 virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide) 150 { 151 fatal("No implementation"); 152 } 153 154 void recvStatusChange(Port::Status status, bool isCpuSide) 155 { 156 if (status == Port::RangeChange){ 157 if (!isCpuSide) { 158 cpuSidePort->sendStatusChange(Port::RangeChange); 159 if (topLevelCache && !snoopRangesSent) { 160 snoopRangesSent = true; 161 memSidePort->sendStatusChange(Port::RangeChange); 162 } 163 } 164 else { 165 memSidePort->sendStatusChange(Port::RangeChange); 166 } 167 } 168 else if (status == Port::SnoopSquash) { 169 assert(snoopPhase2); 170 snoopPhase2 = false; 171 } 172 } 173 174 virtual Packet *getPacket() 175 { 176 fatal("No implementation"); 177 } 178 179 virtual Packet *getCoherencePacket() 180 { 181 fatal("No implementation"); 182 } 183 184 virtual void sendResult(Packet* &pkt, bool success) 185 { 186 187 fatal("No implementation"); 188 } 189 190 /** 191 * Bit vector of the blocking reasons for the access path. 192 * @sa #BlockedCause 193 */ 194 uint8_t blocked; 195 196 /** 197 * Bit vector for the blocking reasons for the snoop path. 198 * @sa #BlockedCause 199 */ 200 uint8_t blockedSnoop; 201 202 /** 203 * Bit vector for the outstanding requests for the master interface. 204 */ 205 uint8_t masterRequests; 206 207 /** 208 * Bit vector for the outstanding requests for the slave interface. 209 */ 210 uint8_t slaveRequests; 211 212 protected: 213 214 /** True if this cache is connected to the CPU. */ 215 bool topLevelCache; 216 217 218 /** True if we are now in phase 2 of the snoop process. */ 219 bool snoopPhase2; 220 221 /** Stores time the cache blocked for statistics. */ 222 Tick blockedCycle; 223 224 /** Block size of this cache */ 225 const int blkSize; 226 227 /** The number of misses to trigger an exit event. */ 228 Counter missCount; 229 230 public: 231 // Statistics 232 /** 233 * @addtogroup CacheStatistics 234 * @{ 235 */ 236 237 /** Number of hits per thread for each type of command. @sa Packet::Command */ 238 Stats::Vector<> hits[NUM_MEM_CMDS]; 239 /** Number of hits for demand accesses. */ 240 Stats::Formula demandHits; 241 /** Number of hit for all accesses. */ 242 Stats::Formula overallHits; 243 244 /** Number of misses per thread for each type of command. @sa Packet::Command */ 245 Stats::Vector<> misses[NUM_MEM_CMDS]; 246 /** Number of misses for demand accesses. */ 247 Stats::Formula demandMisses; 248 /** Number of misses for all accesses. */ 249 Stats::Formula overallMisses; 250 251 /** 252 * Total number of cycles per thread/command spent waiting for a miss. 253 * Used to calculate the average miss latency. 254 */ 255 Stats::Vector<> missLatency[NUM_MEM_CMDS]; 256 /** Total number of cycles spent waiting for demand misses. */ 257 Stats::Formula demandMissLatency; 258 /** Total number of cycles spent waiting for all misses. */ 259 Stats::Formula overallMissLatency; 260 261 /** The number of accesses per command and thread. */ 262 Stats::Formula accesses[NUM_MEM_CMDS]; 263 /** The number of demand accesses. */ 264 Stats::Formula demandAccesses; 265 /** The number of overall accesses. */ 266 Stats::Formula overallAccesses; 267 268 /** The miss rate per command and thread. */ 269 Stats::Formula missRate[NUM_MEM_CMDS]; 270 /** The miss rate of all demand accesses. */ 271 Stats::Formula demandMissRate; 272 /** The miss rate for all accesses. */ 273 Stats::Formula overallMissRate; 274 275 /** The average miss latency per command and thread. */ 276 Stats::Formula avgMissLatency[NUM_MEM_CMDS]; 277 /** The average miss latency for demand misses. */ 278 Stats::Formula demandAvgMissLatency; 279 /** The average miss latency for all misses. */ 280 Stats::Formula overallAvgMissLatency; 281 282 /** The total number of cycles blocked for each blocked cause. */ 283 Stats::Vector<> blocked_cycles; 284 /** The number of times this cache blocked for each blocked cause. */ 285 Stats::Vector<> blocked_causes; 286 287 /** The average number of cycles blocked for each blocked cause. */ 288 Stats::Formula avg_blocked; 289 290 /** The number of fast writes (WH64) performed. */ 291 Stats::Scalar<> fastWrites; 292 293 /** The number of cache copies performed. */ 294 Stats::Scalar<> cacheCopies; 295 296 /** 297 * @} 298 */ 299 300 /** 301 * Register stats for this object. 302 */ 303 virtual void regStats(); 304 305 public: 306 307 class Params 308 { 309 public: 310 /** List of address ranges of this cache. */ 311 std::vector<Range<Addr> > addrRange; 312 /** The hit latency for this cache. */ 313 int hitLatency; 314 /** The block size of this cache. */ 315 int blkSize; 316 /** 317 * The maximum number of misses this cache should handle before 318 * ending the simulation. 319 */ 320 Counter maxMisses; 321 322 /** 323 * Construct an instance of this parameter class. 324 */ 325 Params(std::vector<Range<Addr> > addr_range, 326 int hit_latency, int _blkSize, Counter max_misses) 327 : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize), 328 maxMisses(max_misses) 329 { 330 } 331 }; 332 333 /** 334 * Create and initialize a basic cache object. 335 * @param name The name of this cache. 336 * @param hier_params Pointer to the HierParams object for this hierarchy 337 * of this cache. 338 * @param params The parameter object for this BaseCache. 339 */ 340 BaseCache(const std::string &name, Params ¶ms) 341 : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0), 342 slaveRequests(0), topLevelCache(false), blkSize(params.blkSize), 343 missCount(params.maxMisses) 344 { 345 //Start ports at null if more than one is created we should panic 346 cpuSidePort = NULL; 347 memSidePort = NULL; 348 snoopRangesSent = false; 349 } 350 351 virtual void init(); 352 353 /** 354 * Query block size of a cache. 355 * @return The block size 356 */ 357 int getBlockSize() const 358 { 359 return blkSize; 360 } 361 362 /** 363 * Returns true if this cache is connect to the CPU. 364 * @return True if this is a L1 cache. 365 */ 366 bool isTopLevel() 367 { 368 return topLevelCache; 369 } 370 371 /** 372 * Returns true if the cache is blocked for accesses. 373 */ 374 bool isBlocked() 375 { 376 return blocked != 0; 377 } 378 379 /** 380 * Returns true if the cache is blocked for snoops. 381 */ 382 bool isBlockedForSnoop() 383 { 384 return blockedSnoop != 0; 385 } 386 387 /** 388 * Marks the access path of the cache as blocked for the given cause. This 389 * also sets the blocked flag in the slave interface. 390 * @param cause The reason for the cache blocking. 391 */ 392 void setBlocked(BlockedCause cause) 393 { 394 uint8_t flag = 1 << cause; 395 if (blocked == 0) { 396 blocked_causes[cause]++; 397 blockedCycle = curTick; 398 } 399 if (!(blocked & flag)) { 400 //Wasn't already blocked for this cause 401 blocked |= flag; 402 DPRINTF(Cache,"Blocking for cause %s\n", cause); 403 cpuSidePort->setBlocked(); 404 } 405 } 406 407 /** 408 * Marks the snoop path of the cache as blocked for the given cause. This 409 * also sets the blocked flag in the master interface. 410 * @param cause The reason to block the snoop path. 411 */ 412 void setBlockedForSnoop(BlockedCause cause) 413 { 414 uint8_t flag = 1 << cause; 415 if (!(blocked & flag)) { 416 //Wasn't already blocked for this cause 417 blockedSnoop |= flag; 418 memSidePort->setBlocked(); 419 } 420 } 421 422 /** 423 * Marks the cache as unblocked for the given cause. This also clears the 424 * blocked flags in the appropriate interfaces. 425 * @param cause The newly unblocked cause. 426 * @warning Calling this function can cause a blocked request on the bus to 427 * access the cache. The cache must be in a state to handle that request. 428 */ 429 void clearBlocked(BlockedCause cause) 430 { 431 uint8_t flag = 1 << cause; 432 DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n", 433 cause, blocked); 434 if (blocked & flag) 435 { 436 blocked &= ~flag; 437 if (!isBlocked()) { 438 blocked_cycles[cause] += curTick - blockedCycle; 439 DPRINTF(Cache,"Unblocking from all causes\n"); 440 cpuSidePort->clearBlocked(); 441 } 442 } 443 if (blockedSnoop & flag) 444 { 445 blockedSnoop &= ~flag; 446 if (!isBlockedForSnoop()) { 447 memSidePort->clearBlocked(); 448 } 449 } 450 } 451 452 /** 453 * True if the master bus should be requested. 454 * @return True if there are outstanding requests for the master bus. 455 */ 456 bool doMasterRequest() 457 { 458 return masterRequests != 0; 459 } 460 461 /** 462 * Request the master bus for the given cause and time. 463 * @param cause The reason for the request. 464 * @param time The time to make the request. 465 */ 466 void setMasterRequest(RequestCause cause, Tick time) 467 { 468 if (!doMasterRequest()) 469 { 470 BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort); 471 reqCpu->schedule(time); 472 } 473 uint8_t flag = 1<<cause; 474 masterRequests |= flag; 475 } 476 477 /** 478 * Clear the master bus request for the given cause. 479 * @param cause The request reason to clear. 480 */ 481 void clearMasterRequest(RequestCause cause) 482 { 483 uint8_t flag = 1<<cause; 484 masterRequests &= ~flag; 485 } 486 487 /** 488 * Return true if the slave bus should be requested. 489 * @return True if there are outstanding requests for the slave bus. 490 */ 491 bool doSlaveRequest() 492 { 493 return slaveRequests != 0; 494 } 495 496 /** 497 * Request the slave bus for the given reason and time. 498 * @param cause The reason for the request. 499 * @param time The time to make the request. 500 */ 501 void setSlaveRequest(RequestCause cause, Tick time) 502 { 503 uint8_t flag = 1<<cause; 504 slaveRequests |= flag; 505 assert("Implement\n" && 0); 506// si->pktuest(time); 507 } 508 509 /** 510 * Clear the slave bus request for the given reason. 511 * @param cause The request reason to clear. 512 */ 513 void clearSlaveRequest(RequestCause cause) 514 { 515 uint8_t flag = 1<<cause; 516 slaveRequests &= ~flag; 517 } 518 519 /** 520 * Send a response to the slave interface. 521 * @param pkt The request being responded to. 522 * @param time The time the response is ready. 523 */ 524 void respond(Packet *pkt, Tick time) 525 { 526 CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); 527 reqCpu->schedule(time); 528 } 529 530 /** 531 * Send a reponse to the slave interface and calculate miss latency. 532 * @param pkt The request to respond to. 533 * @param time The time the response is ready. 534 */ 535 void respondToMiss(Packet *pkt, Tick time) 536 { 537 if (!pkt->req->isUncacheable()) { 538 missLatency[pkt->cmdToIndex()][0/*pkt->req->getThreadNum()*/] += time - pkt->time; 539 } 540 CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); 541 reqCpu->schedule(time); 542 } 543 544 /** 545 * Suppliess the data if cache to cache transfers are enabled. 546 * @param pkt The bus transaction to fulfill. 547 */ 548 void respondToSnoop(Packet *pkt, Tick time) 549 { 550// assert("Implement\n" && 0); 551// mi->respond(pkt,curTick + hitLatency); 552 CacheEvent *reqMem = new CacheEvent(memSidePort, pkt); 553 reqMem->schedule(time); 554 } 555 556 /** 557 * Notification from master interface that a address range changed. Nothing 558 * to do for a cache. 559 */ 560 void rangeChange() {} 561 562 void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide) 563 { 564 if (isCpuSide) 565 { 566 AddrRangeList dummy; 567 memSidePort->getPeerAddressRanges(resp, dummy); 568 } 569 else 570 { 571 //This is where snoops get updated 572 AddrRangeList dummy; 573 if (!topLevelCache) 574 { 575 cpuSidePort->getPeerAddressRanges(dummy, snoop); 576 } 577 else 578 { 579 snoop.push_back(RangeSize(0,-1)); 580 } 581 582 return; 583 } 584 } 585}; 586 587#endif //__BASE_CACHE_HH__ 588