base.hh revision 2858
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 public: 102 void setBlocked(); 103 104 void clearBlocked(); 105 106 bool blocked; 107 108 bool isCpuSide; 109 }; 110 111 struct CacheEvent : public Event 112 { 113 CachePort *cachePort; 114 Packet *pkt; 115 116 CacheEvent(CachePort *_cachePort); 117 CacheEvent(CachePort *_cachePort, Packet *_pkt); 118 void process(); 119 const char *description(); 120 }; 121 122 protected: 123 CachePort *cpuSidePort; 124 CachePort *memSidePort; 125 126 public: 127 virtual Port *getPort(const std::string &if_name, int idx = -1); 128 129 private: 130 //To be defined in cache_impl.hh not in base class 131 virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide) 132 { 133 fatal("No implementation"); 134 } 135 136 virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide) 137 { 138 fatal("No implementation"); 139 } 140 141 virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide) 142 { 143 fatal("No implementation"); 144 } 145 146 void recvStatusChange(Port::Status status, bool isCpuSide) 147 { 148 if (status == Port::RangeChange) 149 { 150 if (!isCpuSide) 151 { 152 cpuSidePort->sendStatusChange(Port::RangeChange); 153 } 154 else 155 { 156 memSidePort->sendStatusChange(Port::RangeChange); 157 } 158 } 159 } 160 161 virtual Packet *getPacket() 162 { 163 fatal("No implementation"); 164 } 165 166 virtual Packet *getCoherencePacket() 167 { 168 fatal("No implementation"); 169 } 170 171 virtual void sendResult(Packet* &pkt, bool success) 172 { 173 174 fatal("No implementation"); 175 } 176 177 /** 178 * Bit vector of the blocking reasons for the access path. 179 * @sa #BlockedCause 180 */ 181 uint8_t blocked; 182 183 /** 184 * Bit vector for the blocking reasons for the snoop path. 185 * @sa #BlockedCause 186 */ 187 uint8_t blockedSnoop; 188 189 /** 190 * Bit vector for the outstanding requests for the master interface. 191 */ 192 uint8_t masterRequests; 193 194 /** 195 * Bit vector for the outstanding requests for the slave interface. 196 */ 197 uint8_t slaveRequests; 198 199 protected: 200 201 /** True if this cache is connected to the CPU. */ 202 bool topLevelCache; 203 204 /** Stores time the cache blocked for statistics. */ 205 Tick blockedCycle; 206 207 /** Block size of this cache */ 208 const int blkSize; 209 210 /** The number of misses to trigger an exit event. */ 211 Counter missCount; 212 213 public: 214 // Statistics 215 /** 216 * @addtogroup CacheStatistics 217 * @{ 218 */ 219 220 /** Number of hits per thread for each type of command. @sa Packet::Command */ 221 Stats::Vector<> hits[NUM_MEM_CMDS]; 222 /** Number of hits for demand accesses. */ 223 Stats::Formula demandHits; 224 /** Number of hit for all accesses. */ 225 Stats::Formula overallHits; 226 227 /** Number of misses per thread for each type of command. @sa Packet::Command */ 228 Stats::Vector<> misses[NUM_MEM_CMDS]; 229 /** Number of misses for demand accesses. */ 230 Stats::Formula demandMisses; 231 /** Number of misses for all accesses. */ 232 Stats::Formula overallMisses; 233 234 /** 235 * Total number of cycles per thread/command spent waiting for a miss. 236 * Used to calculate the average miss latency. 237 */ 238 Stats::Vector<> missLatency[NUM_MEM_CMDS]; 239 /** Total number of cycles spent waiting for demand misses. */ 240 Stats::Formula demandMissLatency; 241 /** Total number of cycles spent waiting for all misses. */ 242 Stats::Formula overallMissLatency; 243 244 /** The number of accesses per command and thread. */ 245 Stats::Formula accesses[NUM_MEM_CMDS]; 246 /** The number of demand accesses. */ 247 Stats::Formula demandAccesses; 248 /** The number of overall accesses. */ 249 Stats::Formula overallAccesses; 250 251 /** The miss rate per command and thread. */ 252 Stats::Formula missRate[NUM_MEM_CMDS]; 253 /** The miss rate of all demand accesses. */ 254 Stats::Formula demandMissRate; 255 /** The miss rate for all accesses. */ 256 Stats::Formula overallMissRate; 257 258 /** The average miss latency per command and thread. */ 259 Stats::Formula avgMissLatency[NUM_MEM_CMDS]; 260 /** The average miss latency for demand misses. */ 261 Stats::Formula demandAvgMissLatency; 262 /** The average miss latency for all misses. */ 263 Stats::Formula overallAvgMissLatency; 264 265 /** The total number of cycles blocked for each blocked cause. */ 266 Stats::Vector<> blocked_cycles; 267 /** The number of times this cache blocked for each blocked cause. */ 268 Stats::Vector<> blocked_causes; 269 270 /** The average number of cycles blocked for each blocked cause. */ 271 Stats::Formula avg_blocked; 272 273 /** The number of fast writes (WH64) performed. */ 274 Stats::Scalar<> fastWrites; 275 276 /** The number of cache copies performed. */ 277 Stats::Scalar<> cacheCopies; 278 279 /** 280 * @} 281 */ 282 283 /** 284 * Register stats for this object. 285 */ 286 virtual void regStats(); 287 288 public: 289 290 class Params 291 { 292 public: 293 /** List of address ranges of this cache. */ 294 std::vector<Range<Addr> > addrRange; 295 /** The hit latency for this cache. */ 296 int hitLatency; 297 /** The block size of this cache. */ 298 int blkSize; 299 /** 300 * The maximum number of misses this cache should handle before 301 * ending the simulation. 302 */ 303 Counter maxMisses; 304 305 /** 306 * Construct an instance of this parameter class. 307 */ 308 Params(std::vector<Range<Addr> > addr_range, 309 int hit_latency, int _blkSize, Counter max_misses) 310 : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize), 311 maxMisses(max_misses) 312 { 313 } 314 }; 315 316 /** 317 * Create and initialize a basic cache object. 318 * @param name The name of this cache. 319 * @param hier_params Pointer to the HierParams object for this hierarchy 320 * of this cache. 321 * @param params The parameter object for this BaseCache. 322 */ 323 BaseCache(const std::string &name, Params ¶ms) 324 : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0), 325 slaveRequests(0), topLevelCache(false), blkSize(params.blkSize), 326 missCount(params.maxMisses) 327 { 328 //Start ports at null if more than one is created we should panic 329 cpuSidePort = NULL; 330 memSidePort = NULL; 331 } 332 333 virtual void init(); 334 335 /** 336 * Query block size of a cache. 337 * @return The block size 338 */ 339 int getBlockSize() const 340 { 341 return blkSize; 342 } 343 344 /** 345 * Returns true if this cache is connect to the CPU. 346 * @return True if this is a L1 cache. 347 */ 348 bool isTopLevel() 349 { 350 return topLevelCache; 351 } 352 353 /** 354 * Returns true if the cache is blocked for accesses. 355 */ 356 bool isBlocked() 357 { 358 return blocked != 0; 359 } 360 361 /** 362 * Returns true if the cache is blocked for snoops. 363 */ 364 bool isBlockedForSnoop() 365 { 366 return blockedSnoop != 0; 367 } 368 369 /** 370 * Marks the access path of the cache as blocked for the given cause. This 371 * also sets the blocked flag in the slave interface. 372 * @param cause The reason for the cache blocking. 373 */ 374 void setBlocked(BlockedCause cause) 375 { 376 uint8_t flag = 1 << cause; 377 if (blocked == 0) { 378 blocked_causes[cause]++; 379 blockedCycle = curTick; 380 } 381 blocked |= flag; 382 DPRINTF(Cache,"Blocking for cause %s\n", cause); 383 cpuSidePort->setBlocked(); 384 } 385 386 /** 387 * Marks the snoop path of the cache as blocked for the given cause. This 388 * also sets the blocked flag in the master interface. 389 * @param cause The reason to block the snoop path. 390 */ 391 void setBlockedForSnoop(BlockedCause cause) 392 { 393 uint8_t flag = 1 << cause; 394 blockedSnoop |= flag; 395 memSidePort->setBlocked(); 396 } 397 398 /** 399 * Marks the cache as unblocked for the given cause. This also clears the 400 * blocked flags in the appropriate interfaces. 401 * @param cause The newly unblocked cause. 402 * @warning Calling this function can cause a blocked request on the bus to 403 * access the cache. The cache must be in a state to handle that request. 404 */ 405 void clearBlocked(BlockedCause cause) 406 { 407 uint8_t flag = 1 << cause; 408 blocked &= ~flag; 409 blockedSnoop &= ~flag; 410 DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n", 411 cause, blocked); 412 if (!isBlocked()) { 413 blocked_cycles[cause] += curTick - blockedCycle; 414 DPRINTF(Cache,"Unblocking from all causes\n"); 415 cpuSidePort->clearBlocked(); 416 } 417 if (!isBlockedForSnoop()) { 418 memSidePort->clearBlocked(); 419 } 420 } 421 422 /** 423 * True if the master bus should be requested. 424 * @return True if there are outstanding requests for the master bus. 425 */ 426 bool doMasterRequest() 427 { 428 return masterRequests != 0; 429 } 430 431 /** 432 * Request the master bus for the given cause and time. 433 * @param cause The reason for the request. 434 * @param time The time to make the request. 435 */ 436 void setMasterRequest(RequestCause cause, Tick time) 437 { 438 if (!doMasterRequest()) 439 { 440 BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort); 441 reqCpu->schedule(time); 442 } 443 uint8_t flag = 1<<cause; 444 masterRequests |= flag; 445 } 446 447 /** 448 * Clear the master bus request for the given cause. 449 * @param cause The request reason to clear. 450 */ 451 void clearMasterRequest(RequestCause cause) 452 { 453 uint8_t flag = 1<<cause; 454 masterRequests &= ~flag; 455 } 456 457 /** 458 * Return true if the slave bus should be requested. 459 * @return True if there are outstanding requests for the slave bus. 460 */ 461 bool doSlaveRequest() 462 { 463 return slaveRequests != 0; 464 } 465 466 /** 467 * Request the slave bus for the given reason and time. 468 * @param cause The reason for the request. 469 * @param time The time to make the request. 470 */ 471 void setSlaveRequest(RequestCause cause, Tick time) 472 { 473 uint8_t flag = 1<<cause; 474 slaveRequests |= flag; 475 assert("Implement\n" && 0); 476// si->pktuest(time); 477 } 478 479 /** 480 * Clear the slave bus request for the given reason. 481 * @param cause The request reason to clear. 482 */ 483 void clearSlaveRequest(RequestCause cause) 484 { 485 uint8_t flag = 1<<cause; 486 slaveRequests &= ~flag; 487 } 488 489 /** 490 * Send a response to the slave interface. 491 * @param req The request being responded to. 492 * @param time The time the response is ready. 493 */ 494 void respond(Packet *pkt, Tick time) 495 { 496 pkt->makeTimingResponse(); 497 pkt->result = Packet::Success; 498 CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); 499 reqCpu->schedule(time); 500 } 501 502 /** 503 * Send a reponse to the slave interface and calculate miss latency. 504 * @param req The request to respond to. 505 * @param time The time the response is ready. 506 */ 507 void respondToMiss(Packet *pkt, Tick time) 508 { 509 if (!pkt->req->isUncacheable()) { 510 missLatency[pkt->cmdToIndex()][pkt->req->getThreadNum()] += time - pkt->time; 511 } 512 pkt->makeTimingResponse(); 513 pkt->result = Packet::Success; 514 CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt); 515 reqCpu->schedule(time); 516 } 517 518 /** 519 * Suppliess the data if cache to cache transfers are enabled. 520 * @param req The bus transaction to fulfill. 521 */ 522 void respondToSnoop(Packet *pkt) 523 { 524 assert("Implement\n" && 0); 525// mi->respond(pkt,curTick + hitLatency); 526 } 527 528 /** 529 * Notification from master interface that a address range changed. Nothing 530 * to do for a cache. 531 */ 532 void rangeChange() {} 533 534 void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide) 535 { 536 if (isCpuSide) 537 { 538 AddrRangeList dummy; 539 memSidePort->getPeerAddressRanges(resp, dummy); 540 } 541 else 542 { 543 //This is where snoops get updated 544 return; 545 } 546 } 547}; 548 549#endif //__BASE_CACHE_HH__ 550