1/* 2 * Copyright (c) 2017 Jason Lowe-Power 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: Jason Lowe-Power 29 */ 30 31#ifndef __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__ 32#define __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__ 33 34#include <unordered_map> 35 36#include "base/statistics.hh" 37#include "mem/port.hh" 38#include "params/SimpleCache.hh" 39#include "sim/clocked_object.hh" 40 41/** 42 * A very simple cache object. Has a fully-associative data store with random 43 * replacement. 44 * This cache is fully blocking (not non-blocking). Only a single request can 45 * be outstanding at a time. 46 * This cache is a writeback cache. 47 */ 48class SimpleCache : public ClockedObject 49{ 50 private: 51 52 /** 53 * Port on the CPU-side that receives requests. 54 * Mostly just forwards requests to the cache (owner) 55 */ 56 class CPUSidePort : public SlavePort 57 { 58 private: 59 /// Since this is a vector port, need to know what number this one is 60 int id; 61 62 /// The object that owns this object (SimpleCache) 63 SimpleCache *owner; 64 65 /// True if the port needs to send a retry req. 66 bool needRetry; 67 68 /// If we tried to send a packet and it was blocked, store it here 69 PacketPtr blockedPacket; 70 71 public: 72 /** 73 * Constructor. Just calls the superclass constructor. 74 */ 75 CPUSidePort(const std::string& name, int id, SimpleCache *owner) : 76 SlavePort(name, owner), id(id), owner(owner), needRetry(false), 77 blockedPacket(nullptr) 78 { } 79 80 /** 81 * Send a packet across this port. This is called by the owner and 82 * all of the flow control is hanled in this function. 83 * This is a convenience function for the SimpleCache to send pkts. 84 * 85 * @param packet to send. 86 */ 87 void sendPacket(PacketPtr pkt); 88 89 /** 90 * Get a list of the non-overlapping address ranges the owner is 91 * responsible for. All slave ports must override this function 92 * and return a populated list with at least one item. 93 * 94 * @return a list of ranges responded to 95 */ 96 AddrRangeList getAddrRanges() const override; 97 98 /** 99 * Send a retry to the peer port only if it is needed. This is called 100 * from the SimpleCache whenever it is unblocked. 101 */ 102 void trySendRetry(); 103 104 protected: 105 /** 106 * Receive an atomic request packet from the master port. 107 * No need to implement in this simple cache. 108 */ 109 Tick recvAtomic(PacketPtr pkt) override 110 { panic("recvAtomic unimpl."); } 111 112 /** 113 * Receive a functional request packet from the master port. 114 * Performs a "debug" access updating/reading the data in place. 115 * 116 * @param packet the requestor sent. 117 */ 118 void recvFunctional(PacketPtr pkt) override; 119 120 /** 121 * Receive a timing request from the master port. 122 * 123 * @param the packet that the requestor sent 124 * @return whether this object can consume to packet. If false, we 125 * will call sendRetry() when we can try to receive this 126 * request again. 127 */ 128 bool recvTimingReq(PacketPtr pkt) override; 129 130 /** 131 * Called by the master port if sendTimingResp was called on this 132 * slave port (causing recvTimingResp to be called on the master 133 * port) and was unsuccesful. 134 */ 135 void recvRespRetry() override; 136 }; 137 138 /** 139 * Port on the memory-side that receives responses. 140 * Mostly just forwards requests to the cache (owner) 141 */ 142 class MemSidePort : public MasterPort 143 { 144 private: 145 /// The object that owns this object (SimpleCache) 146 SimpleCache *owner; 147 148 /// If we tried to send a packet and it was blocked, store it here 149 PacketPtr blockedPacket; 150 151 public: 152 /** 153 * Constructor. Just calls the superclass constructor. 154 */ 155 MemSidePort(const std::string& name, SimpleCache *owner) : 156 MasterPort(name, owner), owner(owner), blockedPacket(nullptr) 157 { } 158 159 /** 160 * Send a packet across this port. This is called by the owner and 161 * all of the flow control is hanled in this function. 162 * This is a convenience function for the SimpleCache to send pkts. 163 * 164 * @param packet to send. 165 */ 166 void sendPacket(PacketPtr pkt); 167 168 protected: 169 /** 170 * Receive a timing response from the slave port. 171 */ 172 bool recvTimingResp(PacketPtr pkt) override; 173 174 /** 175 * Called by the slave port if sendTimingReq was called on this 176 * master port (causing recvTimingReq to be called on the slave 177 * port) and was unsuccesful. 178 */ 179 void recvReqRetry() override; 180 181 /** 182 * Called to receive an address range change from the peer slave 183 * port. The default implementation ignores the change and does 184 * nothing. Override this function in a derived class if the owner 185 * needs to be aware of the address ranges, e.g. in an 186 * interconnect component like a bus. 187 */ 188 void recvRangeChange() override; 189 }; 190 191 /** 192 * Handle the request from the CPU side. Called from the CPU port 193 * on a timing request. 194 * 195 * @param requesting packet 196 * @param id of the port to send the response 197 * @return true if we can handle the request this cycle, false if the 198 * requestor needs to retry later 199 */ 200 bool handleRequest(PacketPtr pkt, int port_id); 201 202 /** 203 * Handle the respone from the memory side. Called from the memory port 204 * on a timing response. 205 * 206 * @param responding packet 207 * @return true if we can handle the response this cycle, false if the 208 * responder needs to retry later 209 */ 210 bool handleResponse(PacketPtr pkt); 211 212 /** 213 * Send the packet to the CPU side. 214 * This function assumes the pkt is already a response packet and forwards 215 * it to the correct port. This function also unblocks this object and 216 * cleans up the whole request. 217 * 218 * @param the packet to send to the cpu side 219 */ 220 void sendResponse(PacketPtr pkt); 221 222 /** 223 * Handle a packet functionally. Update the data on a write and get the 224 * data on a read. Called from CPU port on a recv functional. 225 * 226 * @param packet to functionally handle 227 */ 228 void handleFunctional(PacketPtr pkt); 229 230 /** 231 * Access the cache for a timing access. This is called after the cache 232 * access latency has already elapsed. 233 */ 234 void accessTiming(PacketPtr pkt); 235 236 /** 237 * This is where we actually update / read from the cache. This function 238 * is executed on both timing and functional accesses. 239 * 240 * @return true if a hit, false otherwise 241 */ 242 bool accessFunctional(PacketPtr pkt); 243 244 /** 245 * Insert a block into the cache. If there is no room left in the cache, 246 * then this function evicts a random entry t make room for the new block. 247 * 248 * @param packet with the data (and address) to insert into the cache 249 */ 250 void insert(PacketPtr pkt); 251 252 /** 253 * Return the address ranges this cache is responsible for. Just use the 254 * same as the next upper level of the hierarchy. 255 * 256 * @return the address ranges this cache is responsible for 257 */ 258 AddrRangeList getAddrRanges() const; 259 260 /** 261 * Tell the CPU side to ask for our memory ranges. 262 */ 263 void sendRangeChange() const; 264 265 /// Latency to check the cache. Number of cycles for both hit and miss 266 const Cycles latency; 267 268 /// The block size for the cache 269 const unsigned blockSize; 270 271 /// Number of blocks in the cache (size of cache / block size) 272 const unsigned capacity; 273 274 /// Instantiation of the CPU-side port 275 std::vector<CPUSidePort> cpuPorts; 276 277 /// Instantiation of the memory-side port 278 MemSidePort memPort; 279 280 /// True if this cache is currently blocked waiting for a response. 281 bool blocked; 282 283 /// Packet that we are currently handling. Used for upgrading to larger 284 /// cache line sizes 285 PacketPtr originalPacket; 286 287 /// The port to send the response when we recieve it back 288 int waitingPortId; 289 290 /// For tracking the miss latency 291 Tick missTime; 292 293 /// An incredibly simple cache storage. Maps block addresses to data 294 std::unordered_map<Addr, uint8_t*> cacheStore; 295 296 /// Cache statistics 297 Stats::Scalar hits; 298 Stats::Scalar misses; 299 Stats::Histogram missLatency; 300 Stats::Formula hitRatio; 301 302 public: 303 304 /** constructor 305 */ 306 SimpleCache(SimpleCacheParams *params); 307 308 /** 309 * Get a port with a given name and index. This is used at 310 * binding time and returns a reference to a protocol-agnostic 311 * port. 312 * 313 * @param if_name Port name 314 * @param idx Index in the case of a VectorPort 315 * 316 * @return A reference to the given port 317 */ 318 Port &getPort(const std::string &if_name, 319 PortID idx=InvalidPortID) override; 320 321 /** 322 * Register the stats 323 */ 324 void regStats() override; 325}; 326 327 328#endif // __LEARNING_GEM5_SIMPLE_CACHE_SIMPLE_CACHE_HH__ 329