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) :
3814252Sgabeblack@google.com    ClockedObject(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
5413784Sgabeblack@google.comPort &
5513784Sgabeblack@google.comSimpleCache::getPort(const std::string &if_name, PortID idx)
5612339Sjason@lowepower.com{
5712339Sjason@lowepower.com    // This is the name from the Python SimObject declaration in SimpleCache.py
5812339Sjason@lowepower.com    if (if_name == "mem_side") {
5913841Sjason@lowepower.com        panic_if(idx != InvalidPortID,
6013841Sjason@lowepower.com                 "Mem side of simple cache not a vector port");
6112339Sjason@lowepower.com        return memPort;
6213784Sgabeblack@google.com    } else if (if_name == "cpu_side" && idx < cpuPorts.size()) {
6312339Sjason@lowepower.com        // We should have already created all of the ports in the constructor
6412339Sjason@lowepower.com        return cpuPorts[idx];
6512339Sjason@lowepower.com    } else {
6612339Sjason@lowepower.com        // pass it along to our super class
6714252Sgabeblack@google.com        return ClockedObject::getPort(if_name, idx);
6812339Sjason@lowepower.com    }
6912339Sjason@lowepower.com}
7012339Sjason@lowepower.com
7112339Sjason@lowepower.comvoid
7212339Sjason@lowepower.comSimpleCache::CPUSidePort::sendPacket(PacketPtr pkt)
7312339Sjason@lowepower.com{
7412339Sjason@lowepower.com    // Note: This flow control is very simple since the cache is blocking.
7512339Sjason@lowepower.com
7612339Sjason@lowepower.com    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
7712339Sjason@lowepower.com
7812339Sjason@lowepower.com    // If we can't send the packet across the port, store it for later.
7912339Sjason@lowepower.com    DPRINTF(SimpleCache, "Sending %s to CPU\n", pkt->print());
8012339Sjason@lowepower.com    if (!sendTimingResp(pkt)) {
8112339Sjason@lowepower.com        DPRINTF(SimpleCache, "failed!\n");
8212339Sjason@lowepower.com        blockedPacket = pkt;
8312339Sjason@lowepower.com    }
8412339Sjason@lowepower.com}
8512339Sjason@lowepower.com
8612339Sjason@lowepower.comAddrRangeList
8712339Sjason@lowepower.comSimpleCache::CPUSidePort::getAddrRanges() const
8812339Sjason@lowepower.com{
8912339Sjason@lowepower.com    return owner->getAddrRanges();
9012339Sjason@lowepower.com}
9112339Sjason@lowepower.com
9212339Sjason@lowepower.comvoid
9312339Sjason@lowepower.comSimpleCache::CPUSidePort::trySendRetry()
9412339Sjason@lowepower.com{
9512339Sjason@lowepower.com    if (needRetry && blockedPacket == nullptr) {
9612339Sjason@lowepower.com        // Only send a retry if the port is now completely free
9712339Sjason@lowepower.com        needRetry = false;
9812339Sjason@lowepower.com        DPRINTF(SimpleCache, "Sending retry req.\n");
9912339Sjason@lowepower.com        sendRetryReq();
10012339Sjason@lowepower.com    }
10112339Sjason@lowepower.com}
10212339Sjason@lowepower.com
10312339Sjason@lowepower.comvoid
10412339Sjason@lowepower.comSimpleCache::CPUSidePort::recvFunctional(PacketPtr pkt)
10512339Sjason@lowepower.com{
10612339Sjason@lowepower.com    // Just forward to the cache.
10712339Sjason@lowepower.com    return owner->handleFunctional(pkt);
10812339Sjason@lowepower.com}
10912339Sjason@lowepower.com
11012339Sjason@lowepower.combool
11112339Sjason@lowepower.comSimpleCache::CPUSidePort::recvTimingReq(PacketPtr pkt)
11212339Sjason@lowepower.com{
11312339Sjason@lowepower.com    DPRINTF(SimpleCache, "Got request %s\n", pkt->print());
11412339Sjason@lowepower.com
11512339Sjason@lowepower.com    if (blockedPacket || needRetry) {
11612339Sjason@lowepower.com        // The cache may not be able to send a reply if this is blocked
11712339Sjason@lowepower.com        DPRINTF(SimpleCache, "Request blocked\n");
11812339Sjason@lowepower.com        needRetry = true;
11912339Sjason@lowepower.com        return false;
12012339Sjason@lowepower.com    }
12112339Sjason@lowepower.com    // Just forward to the cache.
12212339Sjason@lowepower.com    if (!owner->handleRequest(pkt, id)) {
12312339Sjason@lowepower.com        DPRINTF(SimpleCache, "Request failed\n");
12412339Sjason@lowepower.com        // stalling
12512339Sjason@lowepower.com        needRetry = true;
12612339Sjason@lowepower.com        return false;
12712339Sjason@lowepower.com    } else {
12812339Sjason@lowepower.com        DPRINTF(SimpleCache, "Request succeeded\n");
12912339Sjason@lowepower.com        return true;
13012339Sjason@lowepower.com    }
13112339Sjason@lowepower.com}
13212339Sjason@lowepower.com
13312339Sjason@lowepower.comvoid
13412339Sjason@lowepower.comSimpleCache::CPUSidePort::recvRespRetry()
13512339Sjason@lowepower.com{
13612339Sjason@lowepower.com    // We should have a blocked packet if this function is called.
13712339Sjason@lowepower.com    assert(blockedPacket != nullptr);
13812339Sjason@lowepower.com
13912339Sjason@lowepower.com    // Grab the blocked packet.
14012339Sjason@lowepower.com    PacketPtr pkt = blockedPacket;
14112339Sjason@lowepower.com    blockedPacket = nullptr;
14212339Sjason@lowepower.com
14312339Sjason@lowepower.com    DPRINTF(SimpleCache, "Retrying response pkt %s\n", pkt->print());
14412339Sjason@lowepower.com    // Try to resend it. It's possible that it fails again.
14512339Sjason@lowepower.com    sendPacket(pkt);
14612339Sjason@lowepower.com
14712339Sjason@lowepower.com    // We may now be able to accept new packets
14812339Sjason@lowepower.com    trySendRetry();
14912339Sjason@lowepower.com}
15012339Sjason@lowepower.com
15112339Sjason@lowepower.comvoid
15212339Sjason@lowepower.comSimpleCache::MemSidePort::sendPacket(PacketPtr pkt)
15312339Sjason@lowepower.com{
15412339Sjason@lowepower.com    // Note: This flow control is very simple since the cache is blocking.
15512339Sjason@lowepower.com
15612339Sjason@lowepower.com    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
15712339Sjason@lowepower.com
15812339Sjason@lowepower.com    // If we can't send the packet across the port, store it for later.
15912339Sjason@lowepower.com    if (!sendTimingReq(pkt)) {
16012339Sjason@lowepower.com        blockedPacket = pkt;
16112339Sjason@lowepower.com    }
16212339Sjason@lowepower.com}
16312339Sjason@lowepower.com
16412339Sjason@lowepower.combool
16512339Sjason@lowepower.comSimpleCache::MemSidePort::recvTimingResp(PacketPtr pkt)
16612339Sjason@lowepower.com{
16712339Sjason@lowepower.com    // Just forward to the cache.
16812339Sjason@lowepower.com    return owner->handleResponse(pkt);
16912339Sjason@lowepower.com}
17012339Sjason@lowepower.com
17112339Sjason@lowepower.comvoid
17212339Sjason@lowepower.comSimpleCache::MemSidePort::recvReqRetry()
17312339Sjason@lowepower.com{
17412339Sjason@lowepower.com    // We should have a blocked packet if this function is called.
17512339Sjason@lowepower.com    assert(blockedPacket != nullptr);
17612339Sjason@lowepower.com
17712339Sjason@lowepower.com    // Grab the blocked packet.
17812339Sjason@lowepower.com    PacketPtr pkt = blockedPacket;
17912339Sjason@lowepower.com    blockedPacket = nullptr;
18012339Sjason@lowepower.com
18112339Sjason@lowepower.com    // Try to resend it. It's possible that it fails again.
18212339Sjason@lowepower.com    sendPacket(pkt);
18312339Sjason@lowepower.com}
18412339Sjason@lowepower.com
18512339Sjason@lowepower.comvoid
18612339Sjason@lowepower.comSimpleCache::MemSidePort::recvRangeChange()
18712339Sjason@lowepower.com{
18812339Sjason@lowepower.com    owner->sendRangeChange();
18912339Sjason@lowepower.com}
19012339Sjason@lowepower.com
19112339Sjason@lowepower.combool
19212339Sjason@lowepower.comSimpleCache::handleRequest(PacketPtr pkt, int port_id)
19312339Sjason@lowepower.com{
19412339Sjason@lowepower.com    if (blocked) {
19512339Sjason@lowepower.com        // There is currently an outstanding request so we can't respond. Stall
19612339Sjason@lowepower.com        return false;
19712339Sjason@lowepower.com    }
19812339Sjason@lowepower.com
19912339Sjason@lowepower.com    DPRINTF(SimpleCache, "Got request for addr %#x\n", pkt->getAddr());
20012339Sjason@lowepower.com
20112339Sjason@lowepower.com    // This cache is now blocked waiting for the response to this packet.
20212339Sjason@lowepower.com    blocked = true;
20312339Sjason@lowepower.com
20412339Sjason@lowepower.com    // Store the port for when we get the response
20512339Sjason@lowepower.com    assert(waitingPortId == -1);
20612339Sjason@lowepower.com    waitingPortId = port_id;
20712339Sjason@lowepower.com
20812339Sjason@lowepower.com    // Schedule an event after cache access latency to actually access
20912339Sjason@lowepower.com    schedule(new EventFunctionWrapper([this, pkt]{ accessTiming(pkt); },
21012339Sjason@lowepower.com                                      name() + ".accessEvent", true),
21112339Sjason@lowepower.com             clockEdge(latency));
21212339Sjason@lowepower.com
21312339Sjason@lowepower.com    return true;
21412339Sjason@lowepower.com}
21512339Sjason@lowepower.com
21612339Sjason@lowepower.combool
21712339Sjason@lowepower.comSimpleCache::handleResponse(PacketPtr pkt)
21812339Sjason@lowepower.com{
21912339Sjason@lowepower.com    assert(blocked);
22012339Sjason@lowepower.com    DPRINTF(SimpleCache, "Got response for addr %#x\n", pkt->getAddr());
22112339Sjason@lowepower.com
22212339Sjason@lowepower.com    // For now assume that inserts are off of the critical path and don't count
22312339Sjason@lowepower.com    // for any added latency.
22412339Sjason@lowepower.com    insert(pkt);
22512339Sjason@lowepower.com
22612339Sjason@lowepower.com    missLatency.sample(curTick() - missTime);
22712339Sjason@lowepower.com
22812339Sjason@lowepower.com    // If we had to upgrade the request packet to a full cache line, now we
22912339Sjason@lowepower.com    // can use that packet to construct the response.
23012339Sjason@lowepower.com    if (originalPacket != nullptr) {
23112339Sjason@lowepower.com        DPRINTF(SimpleCache, "Copying data from new packet to old\n");
23212339Sjason@lowepower.com        // We had to upgrade a previous packet. We can functionally deal with
23312339Sjason@lowepower.com        // the cache access now. It better be a hit.
23412339Sjason@lowepower.com        bool hit M5_VAR_USED = accessFunctional(originalPacket);
23512339Sjason@lowepower.com        panic_if(!hit, "Should always hit after inserting");
23612339Sjason@lowepower.com        originalPacket->makeResponse();
23712339Sjason@lowepower.com        delete pkt; // We may need to delay this, I'm not sure.
23812339Sjason@lowepower.com        pkt = originalPacket;
23912339Sjason@lowepower.com        originalPacket = nullptr;
24012339Sjason@lowepower.com    } // else, pkt contains the data it needs
24112339Sjason@lowepower.com
24212339Sjason@lowepower.com    sendResponse(pkt);
24312339Sjason@lowepower.com
24412339Sjason@lowepower.com    return true;
24512339Sjason@lowepower.com}
24612339Sjason@lowepower.com
24712339Sjason@lowepower.comvoid SimpleCache::sendResponse(PacketPtr pkt)
24812339Sjason@lowepower.com{
24912339Sjason@lowepower.com    assert(blocked);
25012339Sjason@lowepower.com    DPRINTF(SimpleCache, "Sending resp for addr %#x\n", pkt->getAddr());
25112339Sjason@lowepower.com
25212339Sjason@lowepower.com    int port = waitingPortId;
25312339Sjason@lowepower.com
25412339Sjason@lowepower.com    // The packet is now done. We're about to put it in the port, no need for
25512339Sjason@lowepower.com    // this object to continue to stall.
25612339Sjason@lowepower.com    // We need to free the resource before sending the packet in case the CPU
25712339Sjason@lowepower.com    // tries to send another request immediately (e.g., in the same callchain).
25812339Sjason@lowepower.com    blocked = false;
25912339Sjason@lowepower.com    waitingPortId = -1;
26012339Sjason@lowepower.com
26112339Sjason@lowepower.com    // Simply forward to the memory port
26212339Sjason@lowepower.com    cpuPorts[port].sendPacket(pkt);
26312339Sjason@lowepower.com
26412339Sjason@lowepower.com    // For each of the cpu ports, if it needs to send a retry, it should do it
26512339Sjason@lowepower.com    // now since this memory object may be unblocked now.
26612339Sjason@lowepower.com    for (auto& port : cpuPorts) {
26712339Sjason@lowepower.com        port.trySendRetry();
26812339Sjason@lowepower.com    }
26912339Sjason@lowepower.com}
27012339Sjason@lowepower.com
27112339Sjason@lowepower.comvoid
27212339Sjason@lowepower.comSimpleCache::handleFunctional(PacketPtr pkt)
27312339Sjason@lowepower.com{
27412339Sjason@lowepower.com    if (accessFunctional(pkt)) {
27512339Sjason@lowepower.com        pkt->makeResponse();
27612339Sjason@lowepower.com    } else {
27712339Sjason@lowepower.com        memPort.sendFunctional(pkt);
27812339Sjason@lowepower.com    }
27912339Sjason@lowepower.com}
28012339Sjason@lowepower.com
28112339Sjason@lowepower.comvoid
28212339Sjason@lowepower.comSimpleCache::accessTiming(PacketPtr pkt)
28312339Sjason@lowepower.com{
28412339Sjason@lowepower.com    bool hit = accessFunctional(pkt);
28512339Sjason@lowepower.com
28612339Sjason@lowepower.com    DPRINTF(SimpleCache, "%s for packet: %s\n", hit ? "Hit" : "Miss",
28712339Sjason@lowepower.com            pkt->print());
28812339Sjason@lowepower.com
28912339Sjason@lowepower.com    if (hit) {
29012339Sjason@lowepower.com        // Respond to the CPU side
29112339Sjason@lowepower.com        hits++; // update stats
29212339Sjason@lowepower.com        DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), pkt->getSize());
29312339Sjason@lowepower.com        pkt->makeResponse();
29412339Sjason@lowepower.com        sendResponse(pkt);
29512339Sjason@lowepower.com    } else {
29612339Sjason@lowepower.com        misses++; // update stats
29712339Sjason@lowepower.com        missTime = curTick();
29812339Sjason@lowepower.com        // Forward to the memory side.
29912339Sjason@lowepower.com        // We can't directly forward the packet unless it is exactly the size
30012339Sjason@lowepower.com        // of the cache line, and aligned. Check for that here.
30112339Sjason@lowepower.com        Addr addr = pkt->getAddr();
30212339Sjason@lowepower.com        Addr block_addr = pkt->getBlockAddr(blockSize);
30312339Sjason@lowepower.com        unsigned size = pkt->getSize();
30412339Sjason@lowepower.com        if (addr == block_addr && size == blockSize) {
30512339Sjason@lowepower.com            // Aligned and block size. We can just forward.
30612339Sjason@lowepower.com            DPRINTF(SimpleCache, "forwarding packet\n");
30712339Sjason@lowepower.com            memPort.sendPacket(pkt);
30812339Sjason@lowepower.com        } else {
30912339Sjason@lowepower.com            DPRINTF(SimpleCache, "Upgrading packet to block size\n");
31012339Sjason@lowepower.com            panic_if(addr - block_addr + size > blockSize,
31112339Sjason@lowepower.com                     "Cannot handle accesses that span multiple cache lines");
31212339Sjason@lowepower.com            // Unaligned access to one cache block
31312339Sjason@lowepower.com            assert(pkt->needsResponse());
31412339Sjason@lowepower.com            MemCmd cmd;
31512339Sjason@lowepower.com            if (pkt->isWrite() || pkt->isRead()) {
31612339Sjason@lowepower.com                // Read the data from memory to write into the block.
31712339Sjason@lowepower.com                // We'll write the data in the cache (i.e., a writeback cache)
31812339Sjason@lowepower.com                cmd = MemCmd::ReadReq;
31912339Sjason@lowepower.com            } else {
32012339Sjason@lowepower.com                panic("Unknown packet type in upgrade size");
32112339Sjason@lowepower.com            }
32212339Sjason@lowepower.com
32312339Sjason@lowepower.com            // Create a new packet that is blockSize
32412339Sjason@lowepower.com            PacketPtr new_pkt = new Packet(pkt->req, cmd, blockSize);
32512339Sjason@lowepower.com            new_pkt->allocate();
32612339Sjason@lowepower.com
32712339Sjason@lowepower.com            // Should now be block aligned
32812339Sjason@lowepower.com            assert(new_pkt->getAddr() == new_pkt->getBlockAddr(blockSize));
32912339Sjason@lowepower.com
33012339Sjason@lowepower.com            // Save the old packet
33112339Sjason@lowepower.com            originalPacket = pkt;
33212339Sjason@lowepower.com
33312339Sjason@lowepower.com            DPRINTF(SimpleCache, "forwarding packet\n");
33412339Sjason@lowepower.com            memPort.sendPacket(new_pkt);
33512339Sjason@lowepower.com        }
33612339Sjason@lowepower.com    }
33712339Sjason@lowepower.com}
33812339Sjason@lowepower.com
33912339Sjason@lowepower.combool
34012339Sjason@lowepower.comSimpleCache::accessFunctional(PacketPtr pkt)
34112339Sjason@lowepower.com{
34212339Sjason@lowepower.com    Addr block_addr = pkt->getBlockAddr(blockSize);
34312339Sjason@lowepower.com    auto it = cacheStore.find(block_addr);
34412339Sjason@lowepower.com    if (it != cacheStore.end()) {
34512339Sjason@lowepower.com        if (pkt->isWrite()) {
34612339Sjason@lowepower.com            // Write the data into the block in the cache
34712339Sjason@lowepower.com            pkt->writeDataToBlock(it->second, blockSize);
34812339Sjason@lowepower.com        } else if (pkt->isRead()) {
34912339Sjason@lowepower.com            // Read the data out of the cache block into the packet
35012339Sjason@lowepower.com            pkt->setDataFromBlock(it->second, blockSize);
35112339Sjason@lowepower.com        } else {
35212339Sjason@lowepower.com            panic("Unknown packet type!");
35312339Sjason@lowepower.com        }
35412339Sjason@lowepower.com        return true;
35512339Sjason@lowepower.com    }
35612339Sjason@lowepower.com    return false;
35712339Sjason@lowepower.com}
35812339Sjason@lowepower.com
35912339Sjason@lowepower.comvoid
36012339Sjason@lowepower.comSimpleCache::insert(PacketPtr pkt)
36112339Sjason@lowepower.com{
36212339Sjason@lowepower.com    // The packet should be aligned.
36312339Sjason@lowepower.com    assert(pkt->getAddr() ==  pkt->getBlockAddr(blockSize));
36412339Sjason@lowepower.com    // The address should not be in the cache
36512339Sjason@lowepower.com    assert(cacheStore.find(pkt->getAddr()) == cacheStore.end());
36612339Sjason@lowepower.com    // The pkt should be a response
36712339Sjason@lowepower.com    assert(pkt->isResponse());
36812339Sjason@lowepower.com
36912339Sjason@lowepower.com    if (cacheStore.size() >= capacity) {
37012339Sjason@lowepower.com        // Select random thing to evict. This is a little convoluted since we
37112339Sjason@lowepower.com        // are using a std::unordered_map. See http://bit.ly/2hrnLP2
37212339Sjason@lowepower.com        int bucket, bucket_size;
37312339Sjason@lowepower.com        do {
37412339Sjason@lowepower.com            bucket = random_mt.random(0, (int)cacheStore.bucket_count() - 1);
37512339Sjason@lowepower.com        } while ( (bucket_size = cacheStore.bucket_size(bucket)) == 0 );
37612339Sjason@lowepower.com        auto block = std::next(cacheStore.begin(bucket),
37712339Sjason@lowepower.com                               random_mt.random(0, bucket_size - 1));
37812339Sjason@lowepower.com
37912339Sjason@lowepower.com        DPRINTF(SimpleCache, "Removing addr %#x\n", block->first);
38012339Sjason@lowepower.com
38112339Sjason@lowepower.com        // Write back the data.
38212339Sjason@lowepower.com        // Create a new request-packet pair
38312749Sgiacomo.travaglini@arm.com        RequestPtr req = std::make_shared<Request>(
38412749Sgiacomo.travaglini@arm.com            block->first, blockSize, 0, 0);
38512749Sgiacomo.travaglini@arm.com
38612339Sjason@lowepower.com        PacketPtr new_pkt = new Packet(req, MemCmd::WritebackDirty, blockSize);
38712339Sjason@lowepower.com        new_pkt->dataDynamic(block->second); // This will be deleted later
38812339Sjason@lowepower.com
38912339Sjason@lowepower.com        DPRINTF(SimpleCache, "Writing packet back %s\n", pkt->print());
39012339Sjason@lowepower.com        // Send the write to memory
39112339Sjason@lowepower.com        memPort.sendPacket(new_pkt);
39212339Sjason@lowepower.com
39312339Sjason@lowepower.com        // Delete this entry
39412339Sjason@lowepower.com        cacheStore.erase(block->first);
39512339Sjason@lowepower.com    }
39612339Sjason@lowepower.com
39712339Sjason@lowepower.com    DPRINTF(SimpleCache, "Inserting %s\n", pkt->print());
39812339Sjason@lowepower.com    DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), blockSize);
39912339Sjason@lowepower.com
40012339Sjason@lowepower.com    // Allocate space for the cache block data
40112339Sjason@lowepower.com    uint8_t *data = new uint8_t[blockSize];
40212339Sjason@lowepower.com
40312339Sjason@lowepower.com    // Insert the data and address into the cache store
40412339Sjason@lowepower.com    cacheStore[pkt->getAddr()] = data;
40512339Sjason@lowepower.com
40612339Sjason@lowepower.com    // Write the data into the cache
40712339Sjason@lowepower.com    pkt->writeDataToBlock(data, blockSize);
40812339Sjason@lowepower.com}
40912339Sjason@lowepower.com
41012339Sjason@lowepower.comAddrRangeList
41112339Sjason@lowepower.comSimpleCache::getAddrRanges() const
41212339Sjason@lowepower.com{
41312339Sjason@lowepower.com    DPRINTF(SimpleCache, "Sending new ranges\n");
41412339Sjason@lowepower.com    // Just use the same ranges as whatever is on the memory side.
41512339Sjason@lowepower.com    return memPort.getAddrRanges();
41612339Sjason@lowepower.com}
41712339Sjason@lowepower.com
41812339Sjason@lowepower.comvoid
41912339Sjason@lowepower.comSimpleCache::sendRangeChange() const
42012339Sjason@lowepower.com{
42112339Sjason@lowepower.com    for (auto& port : cpuPorts) {
42212339Sjason@lowepower.com        port.sendRangeChange();
42312339Sjason@lowepower.com    }
42412339Sjason@lowepower.com}
42512339Sjason@lowepower.com
42612339Sjason@lowepower.comvoid
42712339Sjason@lowepower.comSimpleCache::regStats()
42812339Sjason@lowepower.com{
42912339Sjason@lowepower.com    // If you don't do this you get errors about uninitialized stats.
43014252Sgabeblack@google.com    ClockedObject::regStats();
43112339Sjason@lowepower.com
43212339Sjason@lowepower.com    hits.name(name() + ".hits")
43312339Sjason@lowepower.com        .desc("Number of hits")
43412339Sjason@lowepower.com        ;
43512339Sjason@lowepower.com
43612339Sjason@lowepower.com    misses.name(name() + ".misses")
43712339Sjason@lowepower.com        .desc("Number of misses")
43812339Sjason@lowepower.com        ;
43912339Sjason@lowepower.com
44012339Sjason@lowepower.com    missLatency.name(name() + ".missLatency")
44112339Sjason@lowepower.com        .desc("Ticks for misses to the cache")
44212339Sjason@lowepower.com        .init(16) // number of buckets
44312339Sjason@lowepower.com        ;
44412339Sjason@lowepower.com
44512339Sjason@lowepower.com    hitRatio.name(name() + ".hitRatio")
44612339Sjason@lowepower.com        .desc("The ratio of hits to the total accesses to the cache")
44712339Sjason@lowepower.com        ;
44812339Sjason@lowepower.com
44912339Sjason@lowepower.com    hitRatio = hits / (hits + misses);
45012339Sjason@lowepower.com
45112339Sjason@lowepower.com}
45212339Sjason@lowepower.com
45312339Sjason@lowepower.com
45412339Sjason@lowepower.comSimpleCache*
45512339Sjason@lowepower.comSimpleCacheParams::create()
45612339Sjason@lowepower.com{
45712339Sjason@lowepower.com    return new SimpleCache(this);
45812339Sjason@lowepower.com}
459