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