simple_cache.cc revision 13841
12623SN/A/*
22623SN/A * Copyright (c) 2017 Jason Lowe-Power
32623SN/A * All rights reserved.
42623SN/A *
52623SN/A * Redistribution and use in source and binary forms, with or without
62623SN/A * modification, are permitted provided that the following conditions are
72623SN/A * met: redistributions of source code must retain the above copyright
82623SN/A * notice, this list of conditions and the following disclaimer;
92623SN/A * redistributions in binary form must reproduce the above copyright
102623SN/A * notice, this list of conditions and the following disclaimer in the
112623SN/A * documentation and/or other materials provided with the distribution;
122623SN/A * neither the name of the copyright holders nor the names of its
132623SN/A * contributors may be used to endorse or promote products derived from
142623SN/A * this software without specific prior written permission.
152623SN/A *
162623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Jason Lowe-Power
292623SN/A */
302623SN/A
312623SN/A#include "learning_gem5/part2/simple_cache.hh"
322623SN/A
332623SN/A#include "base/random.hh"
342623SN/A#include "debug/SimpleCache.hh"
356973Stjones1@inf.ed.ac.uk#include "sim/system.hh"
365529Snate@binkert.org
375529Snate@binkert.orgSimpleCache::SimpleCache(SimpleCacheParams *params) :
382623SN/A    MemObject(params),
392623SN/A    latency(params->latency),
402623SN/A    blockSize(params->system->cacheLineSize()),
412623SN/A    capacity(params->size / blockSize),
425529Snate@binkert.org    memPort(params->name + ".mem_side", this),
432623SN/A    blocked(false), originalPacket(nullptr), waitingPortId(-1)
442623SN/A{
452623SN/A    // Since the CPU side ports are a vector of ports, create an instance of
462623SN/A    // the CPUSidePort for each connection. This member of params is
472623SN/A    // automatically created depending on the name of the vector port and
482839Sktlim@umich.edu    // holds the number of connections to this port name
492798Sktlim@umich.edu    for (int i = 0; i < params->port_cpu_side_connection_count; ++i) {
502623SN/A        cpuPorts.emplace_back(name() + csprintf(".cpu_side[%d]", i), i, this);
512623SN/A    }
525728Sgblack@eecs.umich.edu}
535728Sgblack@eecs.umich.edu
545728Sgblack@eecs.umich.eduPort &
555728Sgblack@eecs.umich.eduSimpleCache::getPort(const std::string &if_name, PortID idx)
565728Sgblack@eecs.umich.edu{
575728Sgblack@eecs.umich.edu    // This is the name from the Python SimObject declaration in SimpleCache.py
585728Sgblack@eecs.umich.edu    if (if_name == "mem_side") {
595728Sgblack@eecs.umich.edu        panic_if(idx != InvalidPortID,
605728Sgblack@eecs.umich.edu                 "Mem side of simple cache not a vector port");
615728Sgblack@eecs.umich.edu        return memPort;
625728Sgblack@eecs.umich.edu    } else if (if_name == "cpu_side" && idx < cpuPorts.size()) {
635728Sgblack@eecs.umich.edu        // We should have already created all of the ports in the constructor
645728Sgblack@eecs.umich.edu        return cpuPorts[idx];
655728Sgblack@eecs.umich.edu    } else {
665728Sgblack@eecs.umich.edu        // pass it along to our super class
675728Sgblack@eecs.umich.edu        return MemObject::getPort(if_name, idx);
685728Sgblack@eecs.umich.edu    }
695728Sgblack@eecs.umich.edu}
705728Sgblack@eecs.umich.edu
715728Sgblack@eecs.umich.eduvoid
725728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::sendPacket(PacketPtr pkt)
735728Sgblack@eecs.umich.edu{
745728Sgblack@eecs.umich.edu    // Note: This flow control is very simple since the cache is blocking.
755728Sgblack@eecs.umich.edu
765728Sgblack@eecs.umich.edu    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
775728Sgblack@eecs.umich.edu
785728Sgblack@eecs.umich.edu    // If we can't send the packet across the port, store it for later.
795728Sgblack@eecs.umich.edu    DPRINTF(SimpleCache, "Sending %s to CPU\n", pkt->print());
805728Sgblack@eecs.umich.edu    if (!sendTimingResp(pkt)) {
815728Sgblack@eecs.umich.edu        DPRINTF(SimpleCache, "failed!\n");
825728Sgblack@eecs.umich.edu        blockedPacket = pkt;
835728Sgblack@eecs.umich.edu    }
845728Sgblack@eecs.umich.edu}
855728Sgblack@eecs.umich.edu
865728Sgblack@eecs.umich.eduAddrRangeList
875728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::getAddrRanges() const
885728Sgblack@eecs.umich.edu{
895728Sgblack@eecs.umich.edu    return owner->getAddrRanges();
905728Sgblack@eecs.umich.edu}
915728Sgblack@eecs.umich.edu
925728Sgblack@eecs.umich.eduvoid
935728Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::trySendRetry()
945728Sgblack@eecs.umich.edu{
955728Sgblack@eecs.umich.edu    if (needRetry && blockedPacket == nullptr) {
965728Sgblack@eecs.umich.edu        // Only send a retry if the port is now completely free
975728Sgblack@eecs.umich.edu        needRetry = false;
985728Sgblack@eecs.umich.edu        DPRINTF(SimpleCache, "Sending retry req.\n");
995894Sgblack@eecs.umich.edu        sendRetryReq();
1005894Sgblack@eecs.umich.edu    }
1015894Sgblack@eecs.umich.edu}
1025894Sgblack@eecs.umich.edu
1035894Sgblack@eecs.umich.eduvoid
1045894Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::recvFunctional(PacketPtr pkt)
1056023Snate@binkert.org{
1066023Snate@binkert.org    // Just forward to the cache.
1075894Sgblack@eecs.umich.edu    return owner->handleFunctional(pkt);
1085894Sgblack@eecs.umich.edu}
1096023Snate@binkert.org
1107944SGiacomo.Gabrielli@arm.combool
1117945SAli.Saidi@ARM.comSimpleCache::CPUSidePort::recvTimingReq(PacketPtr pkt)
1127945SAli.Saidi@ARM.com{
1137945SAli.Saidi@ARM.com    DPRINTF(SimpleCache, "Got request %s\n", pkt->print());
1147945SAli.Saidi@ARM.com
1157944SGiacomo.Gabrielli@arm.com    if (blockedPacket || needRetry) {
1167944SGiacomo.Gabrielli@arm.com        // The cache may not be able to send a reply if this is blocked
1176023Snate@binkert.org        DPRINTF(SimpleCache, "Request blocked\n");
1186023Snate@binkert.org        needRetry = true;
1195894Sgblack@eecs.umich.edu        return false;
1205894Sgblack@eecs.umich.edu    }
1215894Sgblack@eecs.umich.edu    // Just forward to the cache.
1225894Sgblack@eecs.umich.edu    if (!owner->handleRequest(pkt, id)) {
1235894Sgblack@eecs.umich.edu        DPRINTF(SimpleCache, "Request failed\n");
1245894Sgblack@eecs.umich.edu        // stalling
1256973Stjones1@inf.ed.ac.uk        needRetry = true;
1266973Stjones1@inf.ed.ac.uk        return false;
1276973Stjones1@inf.ed.ac.uk    } else {
1285894Sgblack@eecs.umich.edu        DPRINTF(SimpleCache, "Request succeeded\n");
1295894Sgblack@eecs.umich.edu        return true;
1305894Sgblack@eecs.umich.edu    }
1315894Sgblack@eecs.umich.edu}
1325894Sgblack@eecs.umich.edu
1335894Sgblack@eecs.umich.eduvoid
1345894Sgblack@eecs.umich.eduSimpleCache::CPUSidePort::recvRespRetry()
1355744Sgblack@eecs.umich.edu{
1365728Sgblack@eecs.umich.edu    // We should have a blocked packet if this function is called.
1375728Sgblack@eecs.umich.edu    assert(blockedPacket != nullptr);
1385728Sgblack@eecs.umich.edu
1395728Sgblack@eecs.umich.edu    // Grab the blocked packet.
1408707Sandreas.hansson@arm.com    PacketPtr pkt = blockedPacket;
1418707Sandreas.hansson@arm.com    blockedPacket = nullptr;
1428707Sandreas.hansson@arm.com
1438707Sandreas.hansson@arm.com    DPRINTF(SimpleCache, "Retrying response pkt %s\n", pkt->print());
1448707Sandreas.hansson@arm.com    // Try to resend it. It's possible that it fails again.
1458707Sandreas.hansson@arm.com    sendPacket(pkt);
1468707Sandreas.hansson@arm.com
1472623SN/A    // We may now be able to accept new packets
1482623SN/A    trySendRetry();
1492623SN/A}
1508707Sandreas.hansson@arm.com
1518707Sandreas.hansson@arm.comvoid
1522623SN/ASimpleCache::MemSidePort::sendPacket(PacketPtr pkt)
1532623SN/A{
1542623SN/A    // Note: This flow control is very simple since the cache is blocking.
1552623SN/A
1568948Sandreas.hansson@arm.com    panic_if(blockedPacket != nullptr, "Should never try to send if blocked!");
1578948Sandreas.hansson@arm.com
1588948Sandreas.hansson@arm.com    // If we can't send the packet across the port, store it for later.
1598948Sandreas.hansson@arm.com    if (!sendTimingReq(pkt)) {
1608948Sandreas.hansson@arm.com        blockedPacket = pkt;
1618707Sandreas.hansson@arm.com    }
1622948Ssaidi@eecs.umich.edu}
1632948Ssaidi@eecs.umich.edu
1642948Ssaidi@eecs.umich.edubool
1653349Sbinkertn@umich.eduSimpleCache::MemSidePort::recvTimingResp(PacketPtr pkt)
1662948Ssaidi@eecs.umich.edu{
1677745SAli.Saidi@ARM.com    // Just forward to the cache.
1682948Ssaidi@eecs.umich.edu    return owner->handleResponse(pkt);
1698707Sandreas.hansson@arm.com}
1705336Shines@cs.fsu.edu
1713349Sbinkertn@umich.eduvoid
1722948Ssaidi@eecs.umich.eduSimpleCache::MemSidePort::recvReqRetry()
1732948Ssaidi@eecs.umich.edu{
1747745SAli.Saidi@ARM.com    // We should have a blocked packet if this function is called.
1752623SN/A    assert(blockedPacket != nullptr);
1762623SN/A
1778707Sandreas.hansson@arm.com    // Grab the blocked packet.
1782623SN/A    PacketPtr pkt = blockedPacket;
1792623SN/A    blockedPacket = nullptr;
1802623SN/A
1818707Sandreas.hansson@arm.com    // Try to resend it. It's possible that it fails again.
1828707Sandreas.hansson@arm.com    sendPacket(pkt);
1838707Sandreas.hansson@arm.com}
1842623SN/A
1852623SN/Avoid
1862623SN/ASimpleCache::MemSidePort::recvRangeChange()
1872623SN/A{
1883349Sbinkertn@umich.edu    owner->sendRangeChange();
1892623SN/A}
1902657Ssaidi@eecs.umich.edu
1912948Ssaidi@eecs.umich.edubool
1922948Ssaidi@eecs.umich.eduSimpleCache::handleRequest(PacketPtr pkt, int port_id)
1932948Ssaidi@eecs.umich.edu{
1942948Ssaidi@eecs.umich.edu    if (blocked) {
1952948Ssaidi@eecs.umich.edu        // There is currently an outstanding request so we can't respond. Stall
1962948Ssaidi@eecs.umich.edu        return false;
1972948Ssaidi@eecs.umich.edu    }
1985336Shines@cs.fsu.edu
1992948Ssaidi@eecs.umich.edu    DPRINTF(SimpleCache, "Got request for addr %#x\n", pkt->getAddr());
2002948Ssaidi@eecs.umich.edu
2012948Ssaidi@eecs.umich.edu    // This cache is now blocked waiting for the response to this packet.
2022948Ssaidi@eecs.umich.edu    blocked = true;
2032623SN/A
2042623SN/A    // Store the port for when we get the response
2058707Sandreas.hansson@arm.com    assert(waitingPortId == -1);
2062623SN/A    waitingPortId = port_id;
2072623SN/A
2082623SN/A    // Schedule an event after cache access latency to actually access
2098707Sandreas.hansson@arm.com    schedule(new EventFunctionWrapper([this, pkt]{ accessTiming(pkt); },
2108707Sandreas.hansson@arm.com                                      name() + ".accessEvent", true),
2112623SN/A             clockEdge(latency));
2122623SN/A
2132623SN/A    return true;
2142623SN/A}
2153349Sbinkertn@umich.edu
2162623SN/Abool
2172657Ssaidi@eecs.umich.eduSimpleCache::handleResponse(PacketPtr pkt)
2182948Ssaidi@eecs.umich.edu{
2192948Ssaidi@eecs.umich.edu    assert(blocked);
2202948Ssaidi@eecs.umich.edu    DPRINTF(SimpleCache, "Got response for addr %#x\n", pkt->getAddr());
2212948Ssaidi@eecs.umich.edu
2222948Ssaidi@eecs.umich.edu    // For now assume that inserts are off of the critical path and don't count
2232948Ssaidi@eecs.umich.edu    // for any added latency.
2245336Shines@cs.fsu.edu    insert(pkt);
2252948Ssaidi@eecs.umich.edu
2262948Ssaidi@eecs.umich.edu    missLatency.sample(curTick() - missTime);
2272948Ssaidi@eecs.umich.edu
2282948Ssaidi@eecs.umich.edu    // If we had to upgrade the request packet to a full cache line, now we
2292623SN/A    // can use that packet to construct the response.
2302623SN/A    if (originalPacket != nullptr) {
2312623SN/A        DPRINTF(SimpleCache, "Copying data from new packet to old\n");
2322623SN/A        // We had to upgrade a previous packet. We can functionally deal with
2332623SN/A        // the cache access now. It better be a hit.
2343349Sbinkertn@umich.edu        bool hit M5_VAR_USED = accessFunctional(originalPacket);
2353349Sbinkertn@umich.edu        panic_if(!hit, "Should always hit after inserting");
2362623SN/A        originalPacket->makeResponse();
2373222Sktlim@umich.edu        delete pkt; // We may need to delay this, I'm not sure.
2383170Sstever@eecs.umich.edu        pkt = originalPacket;
2398850Sandreas.hansson@arm.com        originalPacket = nullptr;
2408850Sandreas.hansson@arm.com    } // else, pkt contains the data it needs
2418850Sandreas.hansson@arm.com
2428850Sandreas.hansson@arm.com    sendResponse(pkt);
2438850Sandreas.hansson@arm.com
2448850Sandreas.hansson@arm.com    return true;
2458850Sandreas.hansson@arm.com}
2468850Sandreas.hansson@arm.com
2472623SN/Avoid SimpleCache::sendResponse(PacketPtr pkt)
2482623SN/A{
2492623SN/A    assert(blocked);
2502623SN/A    DPRINTF(SimpleCache, "Sending resp for addr %#x\n", pkt->getAddr());
2512623SN/A
2522901Ssaidi@eecs.umich.edu    int port = waitingPortId;
2532798Sktlim@umich.edu
2542798Sktlim@umich.edu    // The packet is now done. We're about to put it in the port, no need for
2552798Sktlim@umich.edu    // this object to continue to stall.
2562623SN/A    // We need to free the resource before sending the packet in case the CPU
2572623SN/A    // tries to send another request immediately (e.g., in the same callchain).
2588737Skoansin.tan@gmail.com    blocked = false;
2598737Skoansin.tan@gmail.com    waitingPortId = -1;
2602623SN/A
2618444Sgblack@eecs.umich.edu    // Simply forward to the memory port
2627520Sgblack@eecs.umich.edu    cpuPorts[port].sendPacket(pkt);
2638444Sgblack@eecs.umich.edu
2648444Sgblack@eecs.umich.edu    // For each of the cpu ports, if it needs to send a retry, it should do it
2657520Sgblack@eecs.umich.edu    // now since this memory object may be unblocked now.
2662623SN/A    for (auto& port : cpuPorts) {
2675894Sgblack@eecs.umich.edu        port.trySendRetry();
2683349Sbinkertn@umich.edu    }
2695894Sgblack@eecs.umich.edu}
2702644Sstever@eecs.umich.edu
2714471Sstever@eecs.umich.eduvoid
2725315Sstever@gmail.comSimpleCache::handleFunctional(PacketPtr pkt)
2735315Sstever@gmail.com{
2745315Sstever@gmail.com    if (accessFunctional(pkt)) {
2755315Sstever@gmail.com        pkt->makeResponse();
2765315Sstever@gmail.com    } else {
2775315Sstever@gmail.com        memPort.sendFunctional(pkt);
2786973Stjones1@inf.ed.ac.uk    }
2796973Stjones1@inf.ed.ac.uk}
2806973Stjones1@inf.ed.ac.uk
2816973Stjones1@inf.ed.ac.ukvoid
2826973Stjones1@inf.ed.ac.ukSimpleCache::accessTiming(PacketPtr pkt)
2836973Stjones1@inf.ed.ac.uk{
2842798Sktlim@umich.edu    bool hit = accessFunctional(pkt);
2854471Sstever@eecs.umich.edu
2864471Sstever@eecs.umich.edu    DPRINTF(SimpleCache, "%s for packet: %s\n", hit ? "Hit" : "Miss",
2875710Scws3k@cs.virginia.edu            pkt->print());
2884471Sstever@eecs.umich.edu
2895103Ssaidi@eecs.umich.edu    if (hit) {
2905103Ssaidi@eecs.umich.edu        // Respond to the CPU side
2915103Ssaidi@eecs.umich.edu        hits++; // update stats
2925103Ssaidi@eecs.umich.edu        DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), pkt->getSize());
2935103Ssaidi@eecs.umich.edu        pkt->makeResponse();
2945336Shines@cs.fsu.edu        sendResponse(pkt);
2955103Ssaidi@eecs.umich.edu    } else {
2965103Ssaidi@eecs.umich.edu        misses++; // update stats
2972839Sktlim@umich.edu        missTime = curTick();
2982623SN/A        // Forward to the memory side.
2992623SN/A        // We can't directly forward the packet unless it is exactly the size
3002623SN/A        // of the cache line, and aligned. Check for that here.
301        Addr addr = pkt->getAddr();
302        Addr block_addr = pkt->getBlockAddr(blockSize);
303        unsigned size = pkt->getSize();
304        if (addr == block_addr && size == blockSize) {
305            // Aligned and block size. We can just forward.
306            DPRINTF(SimpleCache, "forwarding packet\n");
307            memPort.sendPacket(pkt);
308        } else {
309            DPRINTF(SimpleCache, "Upgrading packet to block size\n");
310            panic_if(addr - block_addr + size > blockSize,
311                     "Cannot handle accesses that span multiple cache lines");
312            // Unaligned access to one cache block
313            assert(pkt->needsResponse());
314            MemCmd cmd;
315            if (pkt->isWrite() || pkt->isRead()) {
316                // Read the data from memory to write into the block.
317                // We'll write the data in the cache (i.e., a writeback cache)
318                cmd = MemCmd::ReadReq;
319            } else {
320                panic("Unknown packet type in upgrade size");
321            }
322
323            // Create a new packet that is blockSize
324            PacketPtr new_pkt = new Packet(pkt->req, cmd, blockSize);
325            new_pkt->allocate();
326
327            // Should now be block aligned
328            assert(new_pkt->getAddr() == new_pkt->getBlockAddr(blockSize));
329
330            // Save the old packet
331            originalPacket = pkt;
332
333            DPRINTF(SimpleCache, "forwarding packet\n");
334            memPort.sendPacket(new_pkt);
335        }
336    }
337}
338
339bool
340SimpleCache::accessFunctional(PacketPtr pkt)
341{
342    Addr block_addr = pkt->getBlockAddr(blockSize);
343    auto it = cacheStore.find(block_addr);
344    if (it != cacheStore.end()) {
345        if (pkt->isWrite()) {
346            // Write the data into the block in the cache
347            pkt->writeDataToBlock(it->second, blockSize);
348        } else if (pkt->isRead()) {
349            // Read the data out of the cache block into the packet
350            pkt->setDataFromBlock(it->second, blockSize);
351        } else {
352            panic("Unknown packet type!");
353        }
354        return true;
355    }
356    return false;
357}
358
359void
360SimpleCache::insert(PacketPtr pkt)
361{
362    // The packet should be aligned.
363    assert(pkt->getAddr() ==  pkt->getBlockAddr(blockSize));
364    // The address should not be in the cache
365    assert(cacheStore.find(pkt->getAddr()) == cacheStore.end());
366    // The pkt should be a response
367    assert(pkt->isResponse());
368
369    if (cacheStore.size() >= capacity) {
370        // Select random thing to evict. This is a little convoluted since we
371        // are using a std::unordered_map. See http://bit.ly/2hrnLP2
372        int bucket, bucket_size;
373        do {
374            bucket = random_mt.random(0, (int)cacheStore.bucket_count() - 1);
375        } while ( (bucket_size = cacheStore.bucket_size(bucket)) == 0 );
376        auto block = std::next(cacheStore.begin(bucket),
377                               random_mt.random(0, bucket_size - 1));
378
379        DPRINTF(SimpleCache, "Removing addr %#x\n", block->first);
380
381        // Write back the data.
382        // Create a new request-packet pair
383        RequestPtr req = std::make_shared<Request>(
384            block->first, blockSize, 0, 0);
385
386        PacketPtr new_pkt = new Packet(req, MemCmd::WritebackDirty, blockSize);
387        new_pkt->dataDynamic(block->second); // This will be deleted later
388
389        DPRINTF(SimpleCache, "Writing packet back %s\n", pkt->print());
390        // Send the write to memory
391        memPort.sendPacket(new_pkt);
392
393        // Delete this entry
394        cacheStore.erase(block->first);
395    }
396
397    DPRINTF(SimpleCache, "Inserting %s\n", pkt->print());
398    DDUMP(SimpleCache, pkt->getConstPtr<uint8_t>(), blockSize);
399
400    // Allocate space for the cache block data
401    uint8_t *data = new uint8_t[blockSize];
402
403    // Insert the data and address into the cache store
404    cacheStore[pkt->getAddr()] = data;
405
406    // Write the data into the cache
407    pkt->writeDataToBlock(data, blockSize);
408}
409
410AddrRangeList
411SimpleCache::getAddrRanges() const
412{
413    DPRINTF(SimpleCache, "Sending new ranges\n");
414    // Just use the same ranges as whatever is on the memory side.
415    return memPort.getAddrRanges();
416}
417
418void
419SimpleCache::sendRangeChange() const
420{
421    for (auto& port : cpuPorts) {
422        port.sendRangeChange();
423    }
424}
425
426void
427SimpleCache::regStats()
428{
429    // If you don't do this you get errors about uninitialized stats.
430    MemObject::regStats();
431
432    hits.name(name() + ".hits")
433        .desc("Number of hits")
434        ;
435
436    misses.name(name() + ".misses")
437        .desc("Number of misses")
438        ;
439
440    missLatency.name(name() + ".missLatency")
441        .desc("Ticks for misses to the cache")
442        .init(16) // number of buckets
443        ;
444
445    hitRatio.name(name() + ".hitRatio")
446        .desc("The ratio of hits to the total accesses to the cache")
447        ;
448
449    hitRatio = hits / (hits + misses);
450
451}
452
453
454SimpleCache*
455SimpleCacheParams::create()
456{
457    return new SimpleCache(this);
458}
459