simple_cache.cc revision 12749
112339Sjason@lowepower.com/* 212339Sjason@lowepower.com * Copyright (c) 2017 Jason Lowe-Power 312339Sjason@lowepower.com * All rights reserved. 412339Sjason@lowepower.com * 512339Sjason@lowepower.com * Redistribution and use in source and binary forms, with or without 612339Sjason@lowepower.com * modification, are permitted provided that the following conditions are 712339Sjason@lowepower.com * met: redistributions of source code must retain the above copyright 812339Sjason@lowepower.com * notice, this list of conditions and the following disclaimer; 912339Sjason@lowepower.com * redistributions in binary form must reproduce the above copyright 1012339Sjason@lowepower.com * notice, this list of conditions and the following disclaimer in the 1112339Sjason@lowepower.com * documentation and/or other materials provided with the distribution; 1212339Sjason@lowepower.com * neither the name of the copyright holders nor the names of its 1312339Sjason@lowepower.com * contributors may be used to endorse or promote products derived from 1412339Sjason@lowepower.com * this software without specific prior written permission. 1512339Sjason@lowepower.com * 1612339Sjason@lowepower.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1712339Sjason@lowepower.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1812339Sjason@lowepower.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1912339Sjason@lowepower.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2012339Sjason@lowepower.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2112339Sjason@lowepower.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2212339Sjason@lowepower.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2312339Sjason@lowepower.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2412339Sjason@lowepower.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2512339Sjason@lowepower.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2612339Sjason@lowepower.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2712339Sjason@lowepower.com * 2812339Sjason@lowepower.com * Authors: Jason Lowe-Power 2912339Sjason@lowepower.com */ 3012339Sjason@lowepower.com 3112339Sjason@lowepower.com#include "learning_gem5/part2/simple_cache.hh" 3212339Sjason@lowepower.com 3312339Sjason@lowepower.com#include "base/random.hh" 3412339Sjason@lowepower.com#include "debug/SimpleCache.hh" 3512339Sjason@lowepower.com#include "sim/system.hh" 3612339Sjason@lowepower.com 3712339Sjason@lowepower.comSimpleCache::SimpleCache(SimpleCacheParams *params) : 3812339Sjason@lowepower.com MemObject(params), 3912339Sjason@lowepower.com latency(params->latency), 4012339Sjason@lowepower.com blockSize(params->system->cacheLineSize()), 4112339Sjason@lowepower.com capacity(params->size / blockSize), 4212339Sjason@lowepower.com memPort(params->name + ".mem_side", this), 4312339Sjason@lowepower.com blocked(false), originalPacket(nullptr), waitingPortId(-1) 4412339Sjason@lowepower.com{ 4512339Sjason@lowepower.com // Since the CPU side ports are a vector of ports, create an instance of 4612339Sjason@lowepower.com // the CPUSidePort for each connection. This member of params is 4712339Sjason@lowepower.com // automatically created depending on the name of the vector port and 4812339Sjason@lowepower.com // holds the number of connections to this port name 4912339Sjason@lowepower.com for (int i = 0; i < params->port_cpu_side_connection_count; ++i) { 5012339Sjason@lowepower.com cpuPorts.emplace_back(name() + csprintf(".cpu_side[%d]", i), i, this); 5112339Sjason@lowepower.com } 5212339Sjason@lowepower.com} 5312339Sjason@lowepower.com 5412339Sjason@lowepower.comBaseMasterPort& 5512339Sjason@lowepower.comSimpleCache::getMasterPort(const std::string& if_name, PortID idx) 5612339Sjason@lowepower.com{ 5712339Sjason@lowepower.com panic_if(idx != InvalidPortID, "This object doesn't support vector ports"); 5812339Sjason@lowepower.com 5912339Sjason@lowepower.com // This is the name from the Python SimObject declaration in SimpleCache.py 6012339Sjason@lowepower.com if (if_name == "mem_side") { 6112339Sjason@lowepower.com return memPort; 6212339Sjason@lowepower.com } else { 6312339Sjason@lowepower.com // pass it along to our super class 6412339Sjason@lowepower.com return MemObject::getMasterPort(if_name, idx); 6512339Sjason@lowepower.com } 6612339Sjason@lowepower.com} 6712339Sjason@lowepower.com 6812339Sjason@lowepower.comBaseSlavePort& 6912339Sjason@lowepower.comSimpleCache::getSlavePort(const std::string& if_name, PortID idx) 7012339Sjason@lowepower.com{ 7112339Sjason@lowepower.com // This is the name from the Python SimObject declaration (SimpleMemobj.py) 7212339Sjason@lowepower.com if (if_name == "cpu_side" && idx < cpuPorts.size()) { 7312339Sjason@lowepower.com // We should have already created all of the ports in the constructor 7412339Sjason@lowepower.com return cpuPorts[idx]; 7512339Sjason@lowepower.com } else { 7612339Sjason@lowepower.com // pass it along to our super class 7712339Sjason@lowepower.com return MemObject::getSlavePort(if_name, idx); 7812339Sjason@lowepower.com } 7912339Sjason@lowepower.com} 8012339Sjason@lowepower.com 8112339Sjason@lowepower.comvoid 8212339Sjason@lowepower.comSimpleCache::CPUSidePort::sendPacket(PacketPtr pkt) 8312339Sjason@lowepower.com{ 8412339Sjason@lowepower.com // Note: This flow control is very simple since the cache is blocking. 8512339Sjason@lowepower.com 8612339Sjason@lowepower.com panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 8712339Sjason@lowepower.com 8812339Sjason@lowepower.com // If we can't send the packet across the port, store it for later. 8912339Sjason@lowepower.com DPRINTF(SimpleCache, "Sending %s to CPU\n", pkt->print()); 9012339Sjason@lowepower.com if (!sendTimingResp(pkt)) { 9112339Sjason@lowepower.com DPRINTF(SimpleCache, "failed!\n"); 9212339Sjason@lowepower.com blockedPacket = pkt; 9312339Sjason@lowepower.com } 9412339Sjason@lowepower.com} 9512339Sjason@lowepower.com 9612339Sjason@lowepower.comAddrRangeList 9712339Sjason@lowepower.comSimpleCache::CPUSidePort::getAddrRanges() const 9812339Sjason@lowepower.com{ 9912339Sjason@lowepower.com return owner->getAddrRanges(); 10012339Sjason@lowepower.com} 10112339Sjason@lowepower.com 10212339Sjason@lowepower.comvoid 10312339Sjason@lowepower.comSimpleCache::CPUSidePort::trySendRetry() 10412339Sjason@lowepower.com{ 10512339Sjason@lowepower.com if (needRetry && blockedPacket == nullptr) { 10612339Sjason@lowepower.com // Only send a retry if the port is now completely free 10712339Sjason@lowepower.com needRetry = false; 10812339Sjason@lowepower.com DPRINTF(SimpleCache, "Sending retry req.\n"); 10912339Sjason@lowepower.com sendRetryReq(); 11012339Sjason@lowepower.com } 11112339Sjason@lowepower.com} 11212339Sjason@lowepower.com 11312339Sjason@lowepower.comvoid 11412339Sjason@lowepower.comSimpleCache::CPUSidePort::recvFunctional(PacketPtr pkt) 11512339Sjason@lowepower.com{ 11612339Sjason@lowepower.com // Just forward to the cache. 11712339Sjason@lowepower.com return owner->handleFunctional(pkt); 11812339Sjason@lowepower.com} 11912339Sjason@lowepower.com 12012339Sjason@lowepower.combool 12112339Sjason@lowepower.comSimpleCache::CPUSidePort::recvTimingReq(PacketPtr pkt) 12212339Sjason@lowepower.com{ 12312339Sjason@lowepower.com DPRINTF(SimpleCache, "Got request %s\n", pkt->print()); 12412339Sjason@lowepower.com 12512339Sjason@lowepower.com if (blockedPacket || needRetry) { 12612339Sjason@lowepower.com // The cache may not be able to send a reply if this is blocked 12712339Sjason@lowepower.com DPRINTF(SimpleCache, "Request blocked\n"); 12812339Sjason@lowepower.com needRetry = true; 12912339Sjason@lowepower.com return false; 13012339Sjason@lowepower.com } 13112339Sjason@lowepower.com // Just forward to the cache. 13212339Sjason@lowepower.com if (!owner->handleRequest(pkt, id)) { 13312339Sjason@lowepower.com DPRINTF(SimpleCache, "Request failed\n"); 13412339Sjason@lowepower.com // stalling 13512339Sjason@lowepower.com needRetry = true; 13612339Sjason@lowepower.com return false; 13712339Sjason@lowepower.com } else { 13812339Sjason@lowepower.com DPRINTF(SimpleCache, "Request succeeded\n"); 13912339Sjason@lowepower.com return true; 14012339Sjason@lowepower.com } 14112339Sjason@lowepower.com} 14212339Sjason@lowepower.com 14312339Sjason@lowepower.comvoid 14412339Sjason@lowepower.comSimpleCache::CPUSidePort::recvRespRetry() 14512339Sjason@lowepower.com{ 14612339Sjason@lowepower.com // We should have a blocked packet if this function is called. 14712339Sjason@lowepower.com assert(blockedPacket != nullptr); 14812339Sjason@lowepower.com 14912339Sjason@lowepower.com // Grab the blocked packet. 15012339Sjason@lowepower.com PacketPtr pkt = blockedPacket; 15112339Sjason@lowepower.com blockedPacket = nullptr; 15212339Sjason@lowepower.com 15312339Sjason@lowepower.com DPRINTF(SimpleCache, "Retrying response pkt %s\n", pkt->print()); 15412339Sjason@lowepower.com // Try to resend it. It's possible that it fails again. 15512339Sjason@lowepower.com sendPacket(pkt); 15612339Sjason@lowepower.com 15712339Sjason@lowepower.com // We may now be able to accept new packets 15812339Sjason@lowepower.com trySendRetry(); 15912339Sjason@lowepower.com} 16012339Sjason@lowepower.com 16112339Sjason@lowepower.comvoid 16212339Sjason@lowepower.comSimpleCache::MemSidePort::sendPacket(PacketPtr pkt) 16312339Sjason@lowepower.com{ 16412339Sjason@lowepower.com // Note: This flow control is very simple since the cache is blocking. 16512339Sjason@lowepower.com 16612339Sjason@lowepower.com panic_if(blockedPacket != nullptr, "Should never try to send if blocked!"); 16712339Sjason@lowepower.com 16812339Sjason@lowepower.com // If we can't send the packet across the port, store it for later. 16912339Sjason@lowepower.com if (!sendTimingReq(pkt)) { 17012339Sjason@lowepower.com blockedPacket = pkt; 17112339Sjason@lowepower.com } 17212339Sjason@lowepower.com} 17312339Sjason@lowepower.com 17412339Sjason@lowepower.combool 17512339Sjason@lowepower.comSimpleCache::MemSidePort::recvTimingResp(PacketPtr pkt) 17612339Sjason@lowepower.com{ 17712339Sjason@lowepower.com // Just forward to the cache. 17812339Sjason@lowepower.com return owner->handleResponse(pkt); 17912339Sjason@lowepower.com} 18012339Sjason@lowepower.com 18112339Sjason@lowepower.comvoid 18212339Sjason@lowepower.comSimpleCache::MemSidePort::recvReqRetry() 18312339Sjason@lowepower.com{ 18412339Sjason@lowepower.com // We should have a blocked packet if this function is called. 18512339Sjason@lowepower.com assert(blockedPacket != nullptr); 18612339Sjason@lowepower.com 18712339Sjason@lowepower.com // Grab the blocked packet. 18812339Sjason@lowepower.com PacketPtr pkt = blockedPacket; 18912339Sjason@lowepower.com blockedPacket = nullptr; 19012339Sjason@lowepower.com 19112339Sjason@lowepower.com // Try to resend it. It's possible that it fails again. 19212339Sjason@lowepower.com sendPacket(pkt); 19312339Sjason@lowepower.com} 19412339Sjason@lowepower.com 19512339Sjason@lowepower.comvoid 19612339Sjason@lowepower.comSimpleCache::MemSidePort::recvRangeChange() 19712339Sjason@lowepower.com{ 19812339Sjason@lowepower.com owner->sendRangeChange(); 19912339Sjason@lowepower.com} 20012339Sjason@lowepower.com 20112339Sjason@lowepower.combool 20212339Sjason@lowepower.comSimpleCache::handleRequest(PacketPtr pkt, int port_id) 20312339Sjason@lowepower.com{ 20412339Sjason@lowepower.com if (blocked) { 20512339Sjason@lowepower.com // There is currently an outstanding request so we can't respond. Stall 20612339Sjason@lowepower.com return false; 20712339Sjason@lowepower.com } 20812339Sjason@lowepower.com 20912339Sjason@lowepower.com DPRINTF(SimpleCache, "Got request for addr %#x\n", pkt->getAddr()); 21012339Sjason@lowepower.com 21112339Sjason@lowepower.com // This cache is now blocked waiting for the response to this packet. 21212339Sjason@lowepower.com blocked = true; 21312339Sjason@lowepower.com 21412339Sjason@lowepower.com // Store the port for when we get the response 21512339Sjason@lowepower.com assert(waitingPortId == -1); 21612339Sjason@lowepower.com waitingPortId = port_id; 21712339Sjason@lowepower.com 21812339Sjason@lowepower.com // Schedule an event after cache access latency to actually access 21912339Sjason@lowepower.com schedule(new EventFunctionWrapper([this, pkt]{ accessTiming(pkt); }, 22012339Sjason@lowepower.com name() + ".accessEvent", true), 22112339Sjason@lowepower.com clockEdge(latency)); 22212339Sjason@lowepower.com 22312339Sjason@lowepower.com return true; 22412339Sjason@lowepower.com} 22512339Sjason@lowepower.com 22612339Sjason@lowepower.combool 22712339Sjason@lowepower.comSimpleCache::handleResponse(PacketPtr pkt) 22812339Sjason@lowepower.com{ 22912339Sjason@lowepower.com assert(blocked); 23012339Sjason@lowepower.com DPRINTF(SimpleCache, "Got response for addr %#x\n", pkt->getAddr()); 23112339Sjason@lowepower.com 23212339Sjason@lowepower.com // For now assume that inserts are off of the critical path and don't count 23312339Sjason@lowepower.com // for any added latency. 23412339Sjason@lowepower.com insert(pkt); 23512339Sjason@lowepower.com 23612339Sjason@lowepower.com missLatency.sample(curTick() - missTime); 23712339Sjason@lowepower.com 23812339Sjason@lowepower.com // If we had to upgrade the request packet to a full cache line, now we 23912339Sjason@lowepower.com // can use that packet to construct the response. 24012339Sjason@lowepower.com if (originalPacket != nullptr) { 24112339Sjason@lowepower.com DPRINTF(SimpleCache, "Copying data from new packet to old\n"); 24212339Sjason@lowepower.com // We had to upgrade a previous packet. We can functionally deal with 24312339Sjason@lowepower.com // the cache access now. It better be a hit. 24412339Sjason@lowepower.com bool hit M5_VAR_USED = accessFunctional(originalPacket); 24512339Sjason@lowepower.com panic_if(!hit, "Should always hit after inserting"); 24612339Sjason@lowepower.com originalPacket->makeResponse(); 24712339Sjason@lowepower.com delete pkt; // We may need to delay this, I'm not sure. 24812339Sjason@lowepower.com pkt = originalPacket; 24912339Sjason@lowepower.com originalPacket = nullptr; 25012339Sjason@lowepower.com } // else, pkt contains the data it needs 25112339Sjason@lowepower.com 25212339Sjason@lowepower.com sendResponse(pkt); 25312339Sjason@lowepower.com 25412339Sjason@lowepower.com return true; 25512339Sjason@lowepower.com} 25612339Sjason@lowepower.com 25712339Sjason@lowepower.comvoid SimpleCache::sendResponse(PacketPtr pkt) 25812339Sjason@lowepower.com{ 25912339Sjason@lowepower.com assert(blocked); 26012339Sjason@lowepower.com DPRINTF(SimpleCache, "Sending resp for addr %#x\n", pkt->getAddr()); 26112339Sjason@lowepower.com 26212339Sjason@lowepower.com int port = waitingPortId; 26312339Sjason@lowepower.com 26412339Sjason@lowepower.com // The packet is now done. We're about to put it in the port, no need for 26512339Sjason@lowepower.com // this object to continue to stall. 26612339Sjason@lowepower.com // We need to free the resource before sending the packet in case the CPU 26712339Sjason@lowepower.com // tries to send another request immediately (e.g., in the same callchain). 26812339Sjason@lowepower.com blocked = false; 26912339Sjason@lowepower.com waitingPortId = -1; 27012339Sjason@lowepower.com 27112339Sjason@lowepower.com // Simply forward to the memory port 27212339Sjason@lowepower.com cpuPorts[port].sendPacket(pkt); 27312339Sjason@lowepower.com 27412339Sjason@lowepower.com // For each of the cpu ports, if it needs to send a retry, it should do it 27512339Sjason@lowepower.com // now since this memory object may be unblocked now. 27612339Sjason@lowepower.com for (auto& port : cpuPorts) { 27712339Sjason@lowepower.com port.trySendRetry(); 27812339Sjason@lowepower.com } 27912339Sjason@lowepower.com} 28012339Sjason@lowepower.com 28112339Sjason@lowepower.comvoid 28212339Sjason@lowepower.comSimpleCache::handleFunctional(PacketPtr pkt) 28312339Sjason@lowepower.com{ 28412339Sjason@lowepower.com if (accessFunctional(pkt)) { 28512339Sjason@lowepower.com pkt->makeResponse(); 28612339Sjason@lowepower.com } else { 28712339Sjason@lowepower.com memPort.sendFunctional(pkt); 28812339Sjason@lowepower.com } 28912339Sjason@lowepower.com} 29012339Sjason@lowepower.com 29112339Sjason@lowepower.comvoid 29212339Sjason@lowepower.comSimpleCache::accessTiming(PacketPtr pkt) 29312339Sjason@lowepower.com{ 29412339Sjason@lowepower.com bool hit = accessFunctional(pkt); 29512339Sjason@lowepower.com 29612339Sjason@lowepower.com DPRINTF(SimpleCache, "%s for packet: %s\n", hit ? "Hit" : "Miss", 29712339Sjason@lowepower.com pkt->print()); 29812339Sjason@lowepower.com 29912339Sjason@lowepower.com if (hit) { 30012339Sjason@lowepower.com // Respond to the CPU side 30112339Sjason@lowepower.com hits++; // update stats 30212339Sjason@lowepower.com DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), pkt->getSize()); 30312339Sjason@lowepower.com pkt->makeResponse(); 30412339Sjason@lowepower.com sendResponse(pkt); 30512339Sjason@lowepower.com } else { 30612339Sjason@lowepower.com misses++; // update stats 30712339Sjason@lowepower.com missTime = curTick(); 30812339Sjason@lowepower.com // Forward to the memory side. 30912339Sjason@lowepower.com // We can't directly forward the packet unless it is exactly the size 31012339Sjason@lowepower.com // of the cache line, and aligned. Check for that here. 31112339Sjason@lowepower.com Addr addr = pkt->getAddr(); 31212339Sjason@lowepower.com Addr block_addr = pkt->getBlockAddr(blockSize); 31312339Sjason@lowepower.com unsigned size = pkt->getSize(); 31412339Sjason@lowepower.com if (addr == block_addr && size == blockSize) { 31512339Sjason@lowepower.com // Aligned and block size. We can just forward. 31612339Sjason@lowepower.com DPRINTF(SimpleCache, "forwarding packet\n"); 31712339Sjason@lowepower.com memPort.sendPacket(pkt); 31812339Sjason@lowepower.com } else { 31912339Sjason@lowepower.com DPRINTF(SimpleCache, "Upgrading packet to block size\n"); 32012339Sjason@lowepower.com panic_if(addr - block_addr + size > blockSize, 32112339Sjason@lowepower.com "Cannot handle accesses that span multiple cache lines"); 32212339Sjason@lowepower.com // Unaligned access to one cache block 32312339Sjason@lowepower.com assert(pkt->needsResponse()); 32412339Sjason@lowepower.com MemCmd cmd; 32512339Sjason@lowepower.com if (pkt->isWrite() || pkt->isRead()) { 32612339Sjason@lowepower.com // Read the data from memory to write into the block. 32712339Sjason@lowepower.com // We'll write the data in the cache (i.e., a writeback cache) 32812339Sjason@lowepower.com cmd = MemCmd::ReadReq; 32912339Sjason@lowepower.com } else { 33012339Sjason@lowepower.com panic("Unknown packet type in upgrade size"); 33112339Sjason@lowepower.com } 33212339Sjason@lowepower.com 33312339Sjason@lowepower.com // Create a new packet that is blockSize 33412339Sjason@lowepower.com PacketPtr new_pkt = new Packet(pkt->req, cmd, blockSize); 33512339Sjason@lowepower.com new_pkt->allocate(); 33612339Sjason@lowepower.com 33712339Sjason@lowepower.com // Should now be block aligned 33812339Sjason@lowepower.com assert(new_pkt->getAddr() == new_pkt->getBlockAddr(blockSize)); 33912339Sjason@lowepower.com 34012339Sjason@lowepower.com // Save the old packet 34112339Sjason@lowepower.com originalPacket = pkt; 34212339Sjason@lowepower.com 34312339Sjason@lowepower.com DPRINTF(SimpleCache, "forwarding packet\n"); 34412339Sjason@lowepower.com memPort.sendPacket(new_pkt); 34512339Sjason@lowepower.com } 34612339Sjason@lowepower.com } 34712339Sjason@lowepower.com} 34812339Sjason@lowepower.com 34912339Sjason@lowepower.combool 35012339Sjason@lowepower.comSimpleCache::accessFunctional(PacketPtr pkt) 35112339Sjason@lowepower.com{ 35212339Sjason@lowepower.com Addr block_addr = pkt->getBlockAddr(blockSize); 35312339Sjason@lowepower.com auto it = cacheStore.find(block_addr); 35412339Sjason@lowepower.com if (it != cacheStore.end()) { 35512339Sjason@lowepower.com if (pkt->isWrite()) { 35612339Sjason@lowepower.com // Write the data into the block in the cache 35712339Sjason@lowepower.com pkt->writeDataToBlock(it->second, blockSize); 35812339Sjason@lowepower.com } else if (pkt->isRead()) { 35912339Sjason@lowepower.com // Read the data out of the cache block into the packet 36012339Sjason@lowepower.com pkt->setDataFromBlock(it->second, blockSize); 36112339Sjason@lowepower.com } else { 36212339Sjason@lowepower.com panic("Unknown packet type!"); 36312339Sjason@lowepower.com } 36412339Sjason@lowepower.com return true; 36512339Sjason@lowepower.com } 36612339Sjason@lowepower.com return false; 36712339Sjason@lowepower.com} 36812339Sjason@lowepower.com 36912339Sjason@lowepower.comvoid 37012339Sjason@lowepower.comSimpleCache::insert(PacketPtr pkt) 37112339Sjason@lowepower.com{ 37212339Sjason@lowepower.com // The packet should be aligned. 37312339Sjason@lowepower.com assert(pkt->getAddr() == pkt->getBlockAddr(blockSize)); 37412339Sjason@lowepower.com // The address should not be in the cache 37512339Sjason@lowepower.com assert(cacheStore.find(pkt->getAddr()) == cacheStore.end()); 37612339Sjason@lowepower.com // The pkt should be a response 37712339Sjason@lowepower.com assert(pkt->isResponse()); 37812339Sjason@lowepower.com 37912339Sjason@lowepower.com if (cacheStore.size() >= capacity) { 38012339Sjason@lowepower.com // Select random thing to evict. This is a little convoluted since we 38112339Sjason@lowepower.com // are using a std::unordered_map. See http://bit.ly/2hrnLP2 38212339Sjason@lowepower.com int bucket, bucket_size; 38312339Sjason@lowepower.com do { 38412339Sjason@lowepower.com bucket = random_mt.random(0, (int)cacheStore.bucket_count() - 1); 38512339Sjason@lowepower.com } while ( (bucket_size = cacheStore.bucket_size(bucket)) == 0 ); 38612339Sjason@lowepower.com auto block = std::next(cacheStore.begin(bucket), 38712339Sjason@lowepower.com random_mt.random(0, bucket_size - 1)); 38812339Sjason@lowepower.com 38912339Sjason@lowepower.com DPRINTF(SimpleCache, "Removing addr %#x\n", block->first); 39012339Sjason@lowepower.com 39112339Sjason@lowepower.com // Write back the data. 39212339Sjason@lowepower.com // Create a new request-packet pair 39312749Sgiacomo.travaglini@arm.com RequestPtr req = std::make_shared<Request>( 39412749Sgiacomo.travaglini@arm.com block->first, blockSize, 0, 0); 39512749Sgiacomo.travaglini@arm.com 39612339Sjason@lowepower.com PacketPtr new_pkt = new Packet(req, MemCmd::WritebackDirty, blockSize); 39712339Sjason@lowepower.com new_pkt->dataDynamic(block->second); // This will be deleted later 39812339Sjason@lowepower.com 39912339Sjason@lowepower.com DPRINTF(SimpleCache, "Writing packet back %s\n", pkt->print()); 40012339Sjason@lowepower.com // Send the write to memory 40112339Sjason@lowepower.com memPort.sendPacket(new_pkt); 40212339Sjason@lowepower.com 40312339Sjason@lowepower.com // Delete this entry 40412339Sjason@lowepower.com cacheStore.erase(block->first); 40512339Sjason@lowepower.com } 40612339Sjason@lowepower.com 40712339Sjason@lowepower.com DPRINTF(SimpleCache, "Inserting %s\n", pkt->print()); 40812339Sjason@lowepower.com DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), blockSize); 40912339Sjason@lowepower.com 41012339Sjason@lowepower.com // Allocate space for the cache block data 41112339Sjason@lowepower.com uint8_t *data = new uint8_t[blockSize]; 41212339Sjason@lowepower.com 41312339Sjason@lowepower.com // Insert the data and address into the cache store 41412339Sjason@lowepower.com cacheStore[pkt->getAddr()] = data; 41512339Sjason@lowepower.com 41612339Sjason@lowepower.com // Write the data into the cache 41712339Sjason@lowepower.com pkt->writeDataToBlock(data, blockSize); 41812339Sjason@lowepower.com} 41912339Sjason@lowepower.com 42012339Sjason@lowepower.comAddrRangeList 42112339Sjason@lowepower.comSimpleCache::getAddrRanges() const 42212339Sjason@lowepower.com{ 42312339Sjason@lowepower.com DPRINTF(SimpleCache, "Sending new ranges\n"); 42412339Sjason@lowepower.com // Just use the same ranges as whatever is on the memory side. 42512339Sjason@lowepower.com return memPort.getAddrRanges(); 42612339Sjason@lowepower.com} 42712339Sjason@lowepower.com 42812339Sjason@lowepower.comvoid 42912339Sjason@lowepower.comSimpleCache::sendRangeChange() const 43012339Sjason@lowepower.com{ 43112339Sjason@lowepower.com for (auto& port : cpuPorts) { 43212339Sjason@lowepower.com port.sendRangeChange(); 43312339Sjason@lowepower.com } 43412339Sjason@lowepower.com} 43512339Sjason@lowepower.com 43612339Sjason@lowepower.comvoid 43712339Sjason@lowepower.comSimpleCache::regStats() 43812339Sjason@lowepower.com{ 43912339Sjason@lowepower.com // If you don't do this you get errors about uninitialized stats. 44012339Sjason@lowepower.com MemObject::regStats(); 44112339Sjason@lowepower.com 44212339Sjason@lowepower.com hits.name(name() + ".hits") 44312339Sjason@lowepower.com .desc("Number of hits") 44412339Sjason@lowepower.com ; 44512339Sjason@lowepower.com 44612339Sjason@lowepower.com misses.name(name() + ".misses") 44712339Sjason@lowepower.com .desc("Number of misses") 44812339Sjason@lowepower.com ; 44912339Sjason@lowepower.com 45012339Sjason@lowepower.com missLatency.name(name() + ".missLatency") 45112339Sjason@lowepower.com .desc("Ticks for misses to the cache") 45212339Sjason@lowepower.com .init(16) // number of buckets 45312339Sjason@lowepower.com ; 45412339Sjason@lowepower.com 45512339Sjason@lowepower.com hitRatio.name(name() + ".hitRatio") 45612339Sjason@lowepower.com .desc("The ratio of hits to the total accesses to the cache") 45712339Sjason@lowepower.com ; 45812339Sjason@lowepower.com 45912339Sjason@lowepower.com hitRatio = hits / (hits + misses); 46012339Sjason@lowepower.com 46112339Sjason@lowepower.com} 46212339Sjason@lowepower.com 46312339Sjason@lowepower.com 46412339Sjason@lowepower.comSimpleCache* 46512339Sjason@lowepower.comSimpleCacheParams::create() 46612339Sjason@lowepower.com{ 46712339Sjason@lowepower.com return new SimpleCache(this); 46812339Sjason@lowepower.com} 469