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