summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/bridge.cc262
-rw-r--r--src/mem/bridge.hh188
-rw-r--r--src/mem/bus.cc395
-rw-r--r--src/mem/bus.hh207
-rw-r--r--src/mem/cache/base_cache.cc466
-rw-r--r--src/mem/cache/base_cache.hh559
-rw-r--r--src/mem/cache/cache.cc146
-rw-r--r--src/mem/cache/cache.hh268
-rw-r--r--src/mem/cache/cache_blk.hh200
-rw-r--r--src/mem/cache/cache_builder.cc480
-rw-r--r--src/mem/cache/cache_impl.hh672
-rw-r--r--src/mem/cache/coherence/coherence_protocol.cc567
-rw-r--r--src/mem/cache/coherence/coherence_protocol.hh263
-rw-r--r--src/mem/cache/coherence/simple_coherence.hh161
-rw-r--r--src/mem/cache/coherence/uni_coherence.cc86
-rw-r--r--src/mem/cache/coherence/uni_coherence.hh136
-rw-r--r--src/mem/cache/miss/blocking_buffer.cc243
-rw-r--r--src/mem/cache/miss/blocking_buffer.hh256
-rw-r--r--src/mem/cache/miss/miss_queue.cc757
-rw-r--r--src/mem/cache/miss/miss_queue.hh349
-rw-r--r--src/mem/cache/miss/mshr.cc181
-rw-r--r--src/mem/cache/miss/mshr.hh179
-rw-r--r--src/mem/cache/miss/mshr_queue.cc269
-rw-r--r--src/mem/cache/miss/mshr_queue.hh239
-rw-r--r--src/mem/cache/prefetch/base_prefetcher.cc249
-rw-r--r--src/mem/cache/prefetch/base_prefetcher.hh117
-rw-r--r--src/mem/cache/prefetch/ghb_prefetcher.cc54
-rw-r--r--src/mem/cache/prefetch/ghb_prefetcher.hh114
-rw-r--r--src/mem/cache/prefetch/stride_prefetcher.cc54
-rw-r--r--src/mem/cache/prefetch/stride_prefetcher.hh149
-rw-r--r--src/mem/cache/prefetch/tagged_prefetcher.hh71
-rw-r--r--src/mem/cache/prefetch/tagged_prefetcher_impl.hh76
-rw-r--r--src/mem/cache/tags/base_tags.cc91
-rw-r--r--src/mem/cache/tags/base_tags.hh143
-rw-r--r--src/mem/cache/tags/fa_lru.cc334
-rw-r--r--src/mem/cache/tags/fa_lru.hh346
-rw-r--r--src/mem/cache/tags/iic.cc877
-rw-r--r--src/mem/cache/tags/iic.hh574
-rw-r--r--src/mem/cache/tags/lru.cc307
-rw-r--r--src/mem/cache/tags/lru.hh327
-rw-r--r--src/mem/cache/tags/repl/gen.cc277
-rw-r--r--src/mem/cache/tags/repl/gen.hh247
-rw-r--r--src/mem/cache/tags/repl/repl.cc43
-rw-r--r--src/mem/cache/tags/repl/repl.hh129
-rw-r--r--src/mem/cache/tags/split.cc478
-rw-r--r--src/mem/cache/tags/split.hh335
-rw-r--r--src/mem/cache/tags/split_blk.hh68
-rw-r--r--src/mem/cache/tags/split_lifo.cc404
-rw-r--r--src/mem/cache/tags/split_lifo.hh350
-rw-r--r--src/mem/cache/tags/split_lru.cc329
-rw-r--r--src/mem/cache/tags/split_lru.hh333
-rw-r--r--src/mem/config/cache.hh42
-rw-r--r--src/mem/config/prefetch.hh41
-rw-r--r--src/mem/dram.cc2746
-rw-r--r--src/mem/dram.hh172
-rw-r--r--src/mem/mem_object.cc39
-rw-r--r--src/mem/mem_object.hh56
-rw-r--r--src/mem/packet.cc120
-rw-r--r--src/mem/packet.hh375
-rw-r--r--src/mem/page_table.cc161
-rw-r--r--src/mem/page_table.hh100
-rw-r--r--src/mem/physical.cc354
-rw-r--r--src/mem/physical.hh123
-rw-r--r--src/mem/port.cc86
-rw-r--r--src/mem/port.hh285
-rw-r--r--src/mem/port_impl.hh51
-rw-r--r--src/mem/request.hh242
-rw-r--r--src/mem/tport.cc97
-rw-r--r--src/mem/tport.hh143
-rw-r--r--src/mem/translating_port.cc190
-rw-r--r--src/mem/translating_port.hh64
-rw-r--r--src/mem/vport.cc72
-rw-r--r--src/mem/vport.hh79
73 files changed, 20043 insertions, 0 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
new file mode 100644
index 000000000..9c14e7ee2
--- /dev/null
+++ b/src/mem/bridge.cc
@@ -0,0 +1,262 @@
+
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Definition of a simple bus bridge without buffering.
+ */
+
+#include <algorithm>
+
+#include "base/trace.hh"
+#include "mem/bridge.hh"
+#include "sim/builder.hh"
+
+Bridge::BridgePort::BridgePort(const std::string &_name,
+ Bridge *_bridge, BridgePort *_otherPort,
+ int _delay, int _queueLimit)
+ : Port(_name), bridge(_bridge), otherPort(_otherPort),
+ delay(_delay), outstandingResponses(0),
+ queueLimit(_queueLimit), sendEvent(this)
+{
+}
+
+Bridge::Bridge(const std::string &n, int qsa, int qsb,
+ Tick _delay, int write_ack)
+ : MemObject(n),
+ portA(n + "-portA", this, &portB, _delay, qsa),
+ portB(n + "-portB", this, &portA, _delay, qsa),
+ ackWrites(write_ack)
+{
+}
+
+Port *
+Bridge::getPort(const std::string &if_name, int idx)
+{
+ BridgePort *port;
+
+ if (if_name == "side_a")
+ port = &portA;
+ else if (if_name == "side_b")
+ port = &portB;
+ else
+ return NULL;
+
+ if (port->getPeer() != NULL)
+ panic("bridge side %s already connected to.", if_name);
+ return port;
+}
+
+
+void
+Bridge::init()
+{
+ // Make sure that both sides are connected to.
+ if (portA.getPeer() == NULL || portB.getPeer() == NULL)
+ panic("Both ports of bus bridge are not connected to a bus.\n");
+}
+
+
+/** Function called by the port when the bus is receiving a Timing
+ * transaction.*/
+bool
+Bridge::BridgePort::recvTiming(Packet *pkt)
+{
+ DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+
+ return otherPort->queueForSendTiming(pkt);
+}
+
+
+bool
+Bridge::BridgePort::queueForSendTiming(Packet *pkt)
+{
+ if (queueFull())
+ return false;
+
+ if (pkt->isResponse()) {
+ // This is a response for a request we forwarded earlier. The
+ // corresponding PacketBuffer should be stored in the packet's
+ // senderState field.
+ PacketBuffer *buf = dynamic_cast<PacketBuffer*>(pkt->senderState);
+ assert(buf != NULL);
+ // set up new packet dest & senderState based on values saved
+ // from original request
+ buf->fixResponse(pkt);
+ DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n",
+ pkt->senderState, buf);
+ DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest());
+ delete buf;
+ }
+
+ Tick readyTime = curTick + delay;
+ PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+ DPRINTF(BusBridge, "old sender state: %#X, new sender state: %#X\n",
+ buf->origSenderState, buf);
+
+ // If we're about to put this packet at the head of the queue, we
+ // need to schedule an event to do the transmit. Otherwise there
+ // should already be an event scheduled for sending the head
+ // packet.
+ if (sendQueue.empty()) {
+ sendEvent.schedule(readyTime);
+ }
+
+ sendQueue.push_back(buf);
+
+ return true;
+}
+
+void
+Bridge::BridgePort::trySend()
+{
+ assert(!sendQueue.empty());
+
+ bool was_full = queueFull();
+
+ PacketBuffer *buf = sendQueue.front();
+
+ assert(buf->ready <= curTick);
+
+ Packet *pkt = buf->pkt;
+
+ DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
+ buf->origSrc, pkt->getDest(), pkt->getAddr());
+
+ if (sendTiming(pkt)) {
+ // send successful
+ sendQueue.pop_front();
+ buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it
+
+ if (buf->expectResponse) {
+ // Must wait for response. We just need to count outstanding
+ // responses (in case we want to cap them); PacketBuffer
+ // pointer will be recovered on response.
+ ++outstandingResponses;
+ DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
+ outstandingResponses);
+ } else {
+ // no response expected... deallocate packet buffer now.
+ DPRINTF(BusBridge, " successful: no response expected\n");
+ delete buf;
+ }
+
+ // If there are more packets to send, schedule event to try again.
+ if (!sendQueue.empty()) {
+ buf = sendQueue.front();
+ sendEvent.schedule(std::max(buf->ready, curTick + 1));
+ }
+ // Let things start sending again
+ if (was_full) {
+ DPRINTF(BusBridge, "Queue was full, sending retry\n");
+ otherPort->sendRetry();
+ }
+
+ } else {
+ DPRINTF(BusBridge, " unsuccessful\n");
+ }
+}
+
+
+void
+Bridge::BridgePort::recvRetry()
+{
+ trySend();
+}
+
+/** Function called by the port when the bus is receiving a Atomic
+ * transaction.*/
+Tick
+Bridge::BridgePort::recvAtomic(Packet *pkt)
+{
+ return otherPort->sendAtomic(pkt) + delay;
+}
+
+/** Function called by the port when the bus is receiving a Functional
+ * transaction.*/
+void
+Bridge::BridgePort::recvFunctional(Packet *pkt)
+{
+ std::list<PacketBuffer*>::iterator i;
+ bool pktContinue = true;
+
+ for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
+ if (pkt->intersect((*i)->pkt)) {
+ pktContinue &= fixPacket(pkt, (*i)->pkt);
+ }
+ }
+
+ if (pktContinue) {
+ otherPort->sendFunctional(pkt);
+ }
+}
+
+/** Function called by the port when the bus is receiving a status change.*/
+void
+Bridge::BridgePort::recvStatusChange(Port::Status status)
+{
+ otherPort->sendStatusChange(status);
+}
+
+void
+Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+{
+ otherPort->getPeerAddressRanges(resp, snoop);
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge)
+
+ Param<int> queue_size_a;
+ Param<int> queue_size_b;
+ Param<Tick> delay;
+ Param<bool> write_ack;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Bridge)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge)
+
+ INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"),
+ INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"),
+ INIT_PARAM(delay, "The miminum delay to cross this bridge"),
+ INIT_PARAM(write_ack, "Acknowledge any writes that are received.")
+
+END_INIT_SIM_OBJECT_PARAMS(Bridge)
+
+CREATE_SIM_OBJECT(Bridge)
+{
+ return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay,
+ write_ack);
+}
+
+REGISTER_SIM_OBJECT("Bridge", Bridge)
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
new file mode 100644
index 000000000..2ab9799c7
--- /dev/null
+++ b/src/mem/bridge.hh
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Declaration of a simple bus bridge object with no buffering
+ */
+
+#ifndef __MEM_BRIDGE_HH__
+#define __MEM_BRIDGE_HH__
+
+#include <string>
+#include <list>
+#include <inttypes.h>
+#include <queue>
+
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "sim/eventq.hh"
+
+class Bridge : public MemObject
+{
+ protected:
+ /** Declaration of the buses port type, one will be instantiated for each
+ of the interfaces connecting to the bus. */
+ class BridgePort : public Port
+ {
+ /** A pointer to the bridge to which this port belongs. */
+ Bridge *bridge;
+
+ /**
+ * Pointer to the port on the other side of the bridge
+ * (connected to the other bus).
+ */
+ BridgePort *otherPort;
+
+ /** Minimum delay though this bridge. */
+ Tick delay;
+
+ class PacketBuffer : public Packet::SenderState {
+
+ public:
+ Tick ready;
+ Packet *pkt;
+ Packet::SenderState *origSenderState;
+ short origSrc;
+ bool expectResponse;
+
+ PacketBuffer(Packet *_pkt, Tick t)
+ : ready(t), pkt(_pkt),
+ origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()),
+ expectResponse(_pkt->needsResponse())
+ {
+ if (!pkt->isResponse())
+ pkt->senderState = this;
+ }
+
+ void fixResponse(Packet *pkt)
+ {
+ assert(pkt->senderState == this);
+ pkt->setDest(origSrc);
+ pkt->senderState = origSenderState;
+ }
+ };
+
+ /**
+ * Outbound packet queue. Packets are held in this queue for a
+ * specified delay to model the processing delay of the
+ * bridge.
+ */
+ std::list<PacketBuffer*> sendQueue;
+
+ int outstandingResponses;
+
+ /** Max queue size for outbound packets */
+ int queueLimit;
+
+ /**
+ * Is this side blocked from accepting outbound packets?
+ */
+ bool queueFull() { return (sendQueue.size() == queueLimit); }
+
+ bool queueForSendTiming(Packet *pkt);
+
+ void finishSend(PacketBuffer *buf);
+
+ /**
+ * Handle send event, scheduled when the packet at the head of
+ * the outbound queue is ready to transmit (for timing
+ * accesses only).
+ */
+ void trySend();
+
+ class SendEvent : public Event
+ {
+ BridgePort *port;
+
+ public:
+ SendEvent(BridgePort *p)
+ : Event(&mainEventQueue), port(p) {}
+
+ virtual void process() { port->trySend(); }
+
+ virtual const char *description() { return "bridge send event"; }
+ };
+
+ SendEvent sendEvent;
+
+ public:
+
+ /** Constructor for the BusPort.*/
+ BridgePort(const std::string &_name,
+ Bridge *_bridge, BridgePort *_otherPort,
+ int _delay, int _queueLimit);
+
+ protected:
+
+ /** When receiving a timing request from the peer port,
+ pass it to the bridge. */
+ virtual bool recvTiming(Packet *pkt);
+
+ /** When receiving a retry request from the peer port,
+ pass it to the bridge. */
+ virtual void recvRetry();
+
+ /** When receiving a Atomic requestfrom the peer port,
+ pass it to the bridge. */
+ virtual Tick recvAtomic(Packet *pkt);
+
+ /** When receiving a Functional request from the peer port,
+ pass it to the bridge. */
+ virtual void recvFunctional(Packet *pkt);
+
+ /** When receiving a status changefrom the peer port,
+ pass it to the bridge. */
+ virtual void recvStatusChange(Status status);
+
+ /** When receiving a address range request the peer port,
+ pass it to the bridge. */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop);
+ };
+
+ BridgePort portA, portB;
+
+ /** If this bridge should acknowledge writes. */
+ bool ackWrites;
+
+ public:
+
+ /** A function used to return the port associated with this bus object. */
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ virtual void init();
+
+ Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack);
+};
+
+#endif //__MEM_BUS_HH__
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
new file mode 100644
index 000000000..cf9e54e62
--- /dev/null
+++ b/src/mem/bus.cc
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/**
+ * @file
+ * Definition of a bus object.
+ */
+
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "mem/bus.hh"
+#include "sim/builder.hh"
+
+Port *
+Bus::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "default")
+ if (defaultPort == NULL) {
+ defaultPort = new BusPort(csprintf("%s-default",name()), this,
+ defaultId);
+ return defaultPort;
+ } else
+ fatal("Default port already set\n");
+
+ // if_name ignored? forced to be empty?
+ int id = interfaces.size();
+ BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
+ interfaces.push_back(bp);
+ return bp;
+}
+
+/** Get the ranges of anyone other buses that we are connected to. */
+void
+Bus::init()
+{
+ std::vector<Port*>::iterator intIter;
+
+ for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
+ (*intIter)->sendStatusChange(Port::RangeChange);
+}
+
+
+/** Function called by the port when the bus is receiving a Timing
+ * transaction.*/
+bool
+Bus::recvTiming(Packet *pkt)
+{
+ Port *port;
+ DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+
+ short dest = pkt->getDest();
+ if (dest == Packet::Broadcast) {
+ if ( timingSnoopPhase1(pkt) )
+ {
+ timingSnoopPhase2(pkt);
+ port = findPort(pkt->getAddr(), pkt->getSrc());
+ }
+ else
+ {
+ //Snoop didn't succeed
+ retryList.push_back(interfaces[pkt->getSrc()]);
+ return false;
+ }
+ } else {
+ assert(dest >= 0 && dest < interfaces.size());
+ assert(dest != pkt->getSrc()); // catch infinite loops
+ port = interfaces[dest];
+ }
+ if (port->sendTiming(pkt)) {
+ // packet was successfully sent, just return true.
+ return true;
+ }
+
+ // packet not successfully sent
+ retryList.push_back(interfaces[pkt->getSrc()]);
+ return false;
+}
+
+void
+Bus::recvRetry(int id)
+{
+ // Go through all the elements on the list calling sendRetry on each
+ // This is not very efficient at all but it works. Ultimately we should end
+ // up with something that is more intelligent.
+ int initialSize = retryList.size();
+ int i;
+ Port *p;
+
+ for (i = 0; i < initialSize; i++) {
+ assert(retryList.size() > 0);
+ p = retryList.front();
+ retryList.pop_front();
+ p->sendRetry();
+ }
+}
+
+
+Port *
+Bus::findPort(Addr addr, int id)
+{
+ /* An interval tree would be a better way to do this. --ali. */
+ int dest_id = -1;
+ int i = 0;
+ bool found = false;
+ AddrRangeIter iter;
+
+ while (i < portList.size() && !found)
+ {
+ if (portList[i].range == addr) {
+ dest_id = portList[i].portId;
+ found = true;
+ DPRINTF(Bus, " found addr %#llx on device %d\n", addr, dest_id);
+ }
+ i++;
+ }
+
+ // Check if this matches the default range
+ if (dest_id == -1) {
+ for (iter = defaultRange.begin(); iter != defaultRange.end(); iter++) {
+ if (*iter == addr) {
+ DPRINTF(Bus, " found addr %#llx on default\n", addr);
+ return defaultPort;
+ }
+ }
+ panic("Unable to find destination for addr: %#llx", addr);
+ }
+
+
+ // we shouldn't be sending this back to where it came from
+ assert(dest_id != id);
+
+ return interfaces[dest_id];
+}
+
+std::vector<int>
+Bus::findSnoopPorts(Addr addr, int id)
+{
+ int i = 0;
+ AddrRangeIter iter;
+ std::vector<int> ports;
+
+ while (i < portSnoopList.size())
+ {
+ if (portSnoopList[i].range == addr && portSnoopList[i].portId != id) {
+ //Careful to not overlap ranges
+ //or snoop will be called more than once on the port
+ ports.push_back(portSnoopList[i].portId);
+ DPRINTF(Bus, " found snoop addr %#llx on device%d\n", addr,
+ portSnoopList[i].portId);
+ }
+ i++;
+ }
+ return ports;
+}
+
+void
+Bus::atomicSnoop(Packet *pkt)
+{
+ std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
+
+ while (!ports.empty())
+ {
+ interfaces[ports.back()]->sendAtomic(pkt);
+ ports.pop_back();
+ }
+}
+
+bool
+Bus::timingSnoopPhase1(Packet *pkt)
+{
+ std::vector<int> ports = findSnoopPorts(pkt->getAddr(), pkt->getSrc());
+ bool success = true;
+
+ while (!ports.empty() && success)
+ {
+ snoopCallbacks.push_back(ports.back());
+ success = interfaces[ports.back()]->sendTiming(pkt);
+ ports.pop_back();
+ }
+ if (!success)
+ {
+ while (!snoopCallbacks.empty())
+ {
+ interfaces[snoopCallbacks.back()]->sendStatusChange(Port::SnoopSquash);
+ snoopCallbacks.pop_back();
+ }
+ return false;
+ }
+ return true;
+}
+
+void
+Bus::timingSnoopPhase2(Packet *pkt)
+{
+ bool success;
+ pkt->flags |= SNOOP_COMMIT;
+ while (!snoopCallbacks.empty())
+ {
+ success = interfaces[snoopCallbacks.back()]->sendTiming(pkt);
+ //We should not fail on snoop callbacks
+ assert(success);
+ snoopCallbacks.pop_back();
+ }
+}
+
+/** Function called by the port when the bus is receiving a Atomic
+ * transaction.*/
+Tick
+Bus::recvAtomic(Packet *pkt)
+{
+ DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ assert(pkt->getDest() == Packet::Broadcast);
+ atomicSnoop(pkt);
+ return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt);
+}
+
+/** Function called by the port when the bus is receiving a Functional
+ * transaction.*/
+void
+Bus::recvFunctional(Packet *pkt)
+{
+ DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString());
+ assert(pkt->getDest() == Packet::Broadcast);
+ findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt);
+}
+
+/** Function called by the port when the bus is receiving a status change.*/
+void
+Bus::recvStatusChange(Port::Status status, int id)
+{
+ AddrRangeList ranges;
+ AddrRangeList snoops;
+ int x;
+ AddrRangeIter iter;
+
+ assert(status == Port::RangeChange &&
+ "The other statuses need to be implemented.");
+
+ DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
+
+ if (id == defaultId) {
+ defaultRange.clear();
+ defaultPort->getPeerAddressRanges(ranges, snoops);
+ assert(snoops.size() == 0);
+ for(iter = ranges.begin(); iter != ranges.end(); iter++) {
+ defaultRange.push_back(*iter);
+ DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
+ iter->start, iter->end);
+ }
+ } else {
+
+ assert((id < interfaces.size() && id >= 0) || id == -1);
+ Port *port = interfaces[id];
+ std::vector<DevMap>::iterator portIter;
+ std::vector<DevMap>::iterator snoopIter;
+
+ // Clean out any previously existent ids
+ for (portIter = portList.begin(); portIter != portList.end(); ) {
+ if (portIter->portId == id)
+ portIter = portList.erase(portIter);
+ else
+ portIter++;
+ }
+
+ for (snoopIter = portSnoopList.begin(); snoopIter != portSnoopList.end(); ) {
+ if (snoopIter->portId == id)
+ snoopIter = portSnoopList.erase(snoopIter);
+ else
+ snoopIter++;
+ }
+
+ port->getPeerAddressRanges(ranges, snoops);
+
+ for(iter = snoops.begin(); iter != snoops.end(); iter++) {
+ DevMap dm;
+ dm.portId = id;
+ dm.range = *iter;
+
+ DPRINTF(BusAddrRanges, "Adding snoop range %#llx - %#llx for id %d\n",
+ dm.range.start, dm.range.end, id);
+ portSnoopList.push_back(dm);
+ }
+
+ for(iter = ranges.begin(); iter != ranges.end(); iter++) {
+ DevMap dm;
+ dm.portId = id;
+ dm.range = *iter;
+
+ DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
+ dm.range.start, dm.range.end, id);
+ portList.push_back(dm);
+ }
+ }
+ DPRINTF(MMU, "port list has %d entries\n", portList.size());
+
+ // tell all our peers that our address range has changed.
+ // Don't tell the device that caused this change, it already knows
+ for (x = 0; x < interfaces.size(); x++)
+ if (x != id)
+ interfaces[x]->sendStatusChange(Port::RangeChange);
+
+ if (id != defaultId && defaultPort)
+ defaultPort->sendStatusChange(Port::RangeChange);
+}
+
+void
+Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id)
+{
+ std::vector<DevMap>::iterator portIter;
+ AddrRangeIter dflt_iter;
+ bool subset;
+
+ resp.clear();
+ snoop.clear();
+
+ DPRINTF(BusAddrRanges, "received address range request, returning:\n");
+
+ for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
+ dflt_iter++) {
+ resp.push_back(*dflt_iter);
+ DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",dflt_iter->start,
+ dflt_iter->end);
+ }
+ for (portIter = portList.begin(); portIter != portList.end(); portIter++) {
+ subset = false;
+ for (dflt_iter = defaultRange.begin(); dflt_iter != defaultRange.end();
+ dflt_iter++) {
+ if ((portIter->range.start < dflt_iter->start &&
+ portIter->range.end >= dflt_iter->start) ||
+ (portIter->range.start < dflt_iter->end &&
+ portIter->range.end >= dflt_iter->end))
+ fatal("Devices can not set ranges that itersect the default set\
+ but are not a subset of the default set.\n");
+ if (portIter->range.start >= dflt_iter->start &&
+ portIter->range.end <= dflt_iter->end) {
+ subset = true;
+ DPRINTF(BusAddrRanges, " -- %#llx : %#llx is a SUBSET\n",
+ portIter->range.start, portIter->range.end);
+ }
+ }
+ if (portIter->portId != id && !subset) {
+ resp.push_back(portIter->range);
+ DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
+ portIter->range.start, portIter->range.end);
+ }
+ }
+}
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus)
+
+ Param<int> bus_id;
+
+END_DECLARE_SIM_OBJECT_PARAMS(Bus)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(Bus)
+ INIT_PARAM(bus_id, "a globally unique bus id")
+END_INIT_SIM_OBJECT_PARAMS(Bus)
+
+CREATE_SIM_OBJECT(Bus)
+{
+ return new Bus(getInstanceName(), bus_id);
+}
+
+REGISTER_SIM_OBJECT("Bus", Bus)
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
new file mode 100644
index 000000000..941389296
--- /dev/null
+++ b/src/mem/bus.hh
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ */
+
+/**
+ * @file
+ * Declaration of a bus object.
+ */
+
+#ifndef __MEM_BUS_HH__
+#define __MEM_BUS_HH__
+
+#include <string>
+#include <list>
+#include <inttypes.h>
+
+#include "base/range.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+
+class Bus : public MemObject
+{
+ /** a globally unique id for this bus. */
+ int busId;
+
+ static const int defaultId = -1;
+
+ struct DevMap {
+ int portId;
+ Range<Addr> range;
+ };
+ std::vector<DevMap> portList;
+ AddrRangeList defaultRange;
+ std::vector<DevMap> portSnoopList;
+
+ std::vector<int> snoopCallbacks;
+
+
+ /** Function called by the port when the bus is recieving a Timing
+ transaction.*/
+ bool recvTiming(Packet *pkt);
+
+ /** Function called by the port when the bus is recieving a Atomic
+ transaction.*/
+ Tick recvAtomic(Packet *pkt);
+
+ /** Function called by the port when the bus is recieving a Functional
+ transaction.*/
+ void recvFunctional(Packet *pkt);
+
+ /** Timing function called by port when it is once again able to process
+ * requests. */
+ void recvRetry(int id);
+
+ /** Function called by the port when the bus is recieving a status change.*/
+ void recvStatusChange(Port::Status status, int id);
+
+ /** Find which port connected to this bus (if any) should be given a packet
+ * with this address.
+ * @param addr Address to find port for.
+ * @param id Id of the port this packet was received from (to prevent
+ * loops)
+ * @return pointer to port that the packet should be sent out of.
+ */
+ Port *findPort(Addr addr, int id);
+
+ /** Find all ports with a matching snoop range, except src port. Keep in mind
+ * that the ranges shouldn't overlap or you will get a double snoop to the same
+ * interface.and the cache will assert out.
+ * @param addr Address to find snoop prts for.
+ * @param id Id of the src port of the request to avoid calling snoop on src
+ * @return vector of IDs to snoop on
+ */
+ std::vector<int> findSnoopPorts(Addr addr, int id);
+
+ /** Snoop all relevant ports atomicly. */
+ void atomicSnoop(Packet *pkt);
+
+ /** Snoop for NACK and Blocked in phase 1
+ * @return True if succeds.
+ */
+ bool timingSnoopPhase1(Packet *pkt);
+
+ /** @todo Don't need to commit all snoops just those that need it
+ *(register somehow). */
+ /** Commit all snoops now that we know if any of them would have blocked.
+ */
+ void timingSnoopPhase2(Packet *pkt);
+
+ /** Process address range request.
+ * @param resp addresses that we can respond to
+ * @param snoop addresses that we would like to snoop
+ * @param id ide of the busport that made the request.
+ */
+ void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id);
+
+
+ /** Declaration of the buses port type, one will be instantiated for each
+ of the interfaces connecting to the bus. */
+ class BusPort : public Port
+ {
+ /** A pointer to the bus to which this port belongs. */
+ Bus *bus;
+
+ /** A id to keep track of the intercafe ID this port is connected to. */
+ int id;
+
+ public:
+
+ /** Constructor for the BusPort.*/
+ BusPort(const std::string &_name, Bus *_bus, int _id)
+ : Port(_name), bus(_bus), id(_id)
+ { }
+
+ protected:
+
+ /** When reciving a timing request from the peer port (at id),
+ pass it to the bus. */
+ virtual bool recvTiming(Packet *pkt)
+ { pkt->setSrc(id); return bus->recvTiming(pkt); }
+
+ /** When reciving a Atomic requestfrom the peer port (at id),
+ pass it to the bus. */
+ virtual Tick recvAtomic(Packet *pkt)
+ { pkt->setSrc(id); return bus->recvAtomic(pkt); }
+
+ /** When reciving a Functional requestfrom the peer port (at id),
+ pass it to the bus. */
+ virtual void recvFunctional(Packet *pkt)
+ { pkt->setSrc(id); bus->recvFunctional(pkt); }
+
+ /** When reciving a status changefrom the peer port (at id),
+ pass it to the bus. */
+ virtual void recvStatusChange(Status status)
+ { bus->recvStatusChange(status, id); }
+
+ /** When reciving a retry from the peer port (at id),
+ pass it to the bus. */
+ virtual void recvRetry()
+ { bus->recvRetry(id); }
+
+ // This should return all the 'owned' addresses that are
+ // downstream from this bus, yes? That is, the union of all
+ // the 'owned' address ranges of all the other interfaces on
+ // this bus...
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { bus->addressRanges(resp, snoop, id); }
+
+ // Hack to make translating port work without changes
+ virtual int deviceBlockSize() { return 32; }
+
+ };
+
+ /** An array of pointers to the peer port interfaces
+ connected to this bus.*/
+ std::vector<Port*> interfaces;
+
+ /** An array of pointers to ports that retry should be called on because the
+ * original send failed for whatever reason.*/
+ std::list<Port*> retryList;
+
+ /** Port that handles requests that don't match any of the interfaces.*/
+ Port *defaultPort;
+
+ public:
+
+ /** A function used to return the port associated with this bus object. */
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ virtual void init();
+
+ Bus(const std::string &n, int bus_id)
+ : MemObject(n), busId(bus_id), defaultPort(NULL) {}
+
+};
+
+#endif //__MEM_BUS_HH__
diff --git a/src/mem/cache/base_cache.cc b/src/mem/cache/base_cache.cc
new file mode 100644
index 000000000..a172847df
--- /dev/null
+++ b/src/mem/cache/base_cache.cc
@@ -0,0 +1,466 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definition of BaseCache functions.
+ */
+
+#include "mem/cache/base_cache.hh"
+#include "cpu/smt.hh"
+#include "cpu/base.hh"
+
+using namespace std;
+
+BaseCache::CachePort::CachePort(const std::string &_name, BaseCache *_cache,
+ bool _isCpuSide)
+ : Port(_name), cache(_cache), isCpuSide(_isCpuSide)
+{
+ blocked = false;
+ //Start ports at null if more than one is created we should panic
+ //cpuSidePort = NULL;
+ //memSidePort = NULL;
+}
+
+void
+BaseCache::CachePort::recvStatusChange(Port::Status status)
+{
+ cache->recvStatusChange(status, isCpuSide);
+}
+
+void
+BaseCache::CachePort::getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+{
+ cache->getAddressRanges(resp, snoop, isCpuSide);
+}
+
+int
+BaseCache::CachePort::deviceBlockSize()
+{
+ return cache->getBlockSize();
+}
+
+bool
+BaseCache::CachePort::recvTiming(Packet *pkt)
+{
+ if (blocked)
+ {
+ DPRINTF(Cache,"Scheduling a retry while blocked\n");
+ mustSendRetry = true;
+ return false;
+ }
+ return cache->doTimingAccess(pkt, this, isCpuSide);
+}
+
+Tick
+BaseCache::CachePort::recvAtomic(Packet *pkt)
+{
+ return cache->doAtomicAccess(pkt, isCpuSide);
+}
+
+void
+BaseCache::CachePort::recvFunctional(Packet *pkt)
+{
+ cache->doFunctionalAccess(pkt, isCpuSide);
+}
+
+void
+BaseCache::CachePort::recvRetry()
+{
+ Packet *pkt;
+
+ if (!isCpuSide)
+ {
+ pkt = cache->getPacket();
+ bool success = sendTiming(pkt);
+ DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
+ pkt->getAddr(), success ? "succesful" : "unsuccesful");
+ cache->sendResult(pkt, success);
+ if (success && cache->doMasterRequest())
+ {
+ //Still more to issue, rerequest in 1 cycle
+ pkt = NULL;
+ BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
+ reqCpu->schedule(curTick + 1);
+ }
+ }
+ else
+ {
+ pkt = cache->getCoherencePacket();
+ bool success = sendTiming(pkt);
+ if (success && cache->doSlaveRequest())
+ {
+ //Still more to issue, rerequest in 1 cycle
+ pkt = NULL;
+ BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(this);
+ reqCpu->schedule(curTick + 1);
+ }
+
+ }
+ return;
+}
+void
+BaseCache::CachePort::setBlocked()
+{
+ assert(!blocked);
+ DPRINTF(Cache, "Cache Blocking\n");
+ blocked = true;
+ //Clear the retry flag
+ mustSendRetry = false;
+}
+
+void
+BaseCache::CachePort::clearBlocked()
+{
+ assert(blocked);
+ DPRINTF(Cache, "Cache Unblocking\n");
+ blocked = false;
+ if (mustSendRetry)
+ {
+ DPRINTF(Cache, "Cache Sending Retry\n");
+ mustSendRetry = false;
+ sendRetry();
+ }
+}
+
+BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort)
+{
+ this->setFlags(AutoDelete);
+ pkt = NULL;
+}
+
+BaseCache::CacheEvent::CacheEvent(CachePort *_cachePort, Packet *_pkt)
+ : Event(&mainEventQueue, CPU_Tick_Pri), cachePort(_cachePort), pkt(_pkt)
+{
+ this->setFlags(AutoDelete);
+}
+
+void
+BaseCache::CacheEvent::process()
+{
+ if (!pkt)
+ {
+ if (!cachePort->isCpuSide)
+ {
+ //MSHR
+ pkt = cachePort->cache->getPacket();
+ bool success = cachePort->sendTiming(pkt);
+ DPRINTF(Cache, "Address %x was %s in sending the timing request\n",
+ pkt->getAddr(), success ? "succesful" : "unsuccesful");
+ cachePort->cache->sendResult(pkt, success);
+ if (success && cachePort->cache->doMasterRequest())
+ {
+ //Still more to issue, rerequest in 1 cycle
+ pkt = NULL;
+ this->schedule(curTick+1);
+ }
+ }
+ else
+ {
+ //CSHR
+ pkt = cachePort->cache->getCoherencePacket();
+ bool success = cachePort->sendTiming(pkt);
+ if (success && cachePort->cache->doSlaveRequest())
+ {
+ //Still more to issue, rerequest in 1 cycle
+ pkt = NULL;
+ this->schedule(curTick+1);
+ }
+ }
+ return;
+ }
+ //Response
+ //Know the packet to send, no need to mark in service (must succed)
+ assert(cachePort->sendTiming(pkt));
+}
+
+const char *
+BaseCache::CacheEvent::description()
+{
+ return "timing event\n";
+}
+
+Port*
+BaseCache::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "")
+ {
+ if(cpuSidePort == NULL)
+ cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
+ return cpuSidePort;
+ }
+ else if (if_name == "functional")
+ {
+ if(cpuSidePort == NULL)
+ cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
+ return cpuSidePort;
+ }
+ else if (if_name == "cpu_side")
+ {
+ if(cpuSidePort == NULL)
+ cpuSidePort = new CachePort(name() + "-cpu_side_port", this, true);
+ return cpuSidePort;
+ }
+ else if (if_name == "mem_side")
+ {
+ if (memSidePort != NULL)
+ panic("Already have a mem side for this cache\n");
+ memSidePort = new CachePort(name() + "-mem_side_port", this, false);
+ return memSidePort;
+ }
+ else panic("Port name %s unrecognized\n", if_name);
+}
+
+void
+BaseCache::init()
+{
+ if (!cpuSidePort || !memSidePort)
+ panic("Cache not hooked up on both sides\n");
+ cpuSidePort->sendStatusChange(Port::RangeChange);
+}
+
+void
+BaseCache::regStats()
+{
+ Request temp_req((Addr) NULL, 4, 0);
+ Packet::Command temp_cmd = Packet::ReadReq;
+ Packet temp_pkt(&temp_req, temp_cmd, 0); //@todo FIx command strings so this isn't neccessary
+ temp_pkt.allocate(); //Temp allocate, all need data
+
+ using namespace Stats;
+
+ // Hit statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ hits[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_hits")
+ .desc("number of " + cstr + " hits")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandHits
+ .name(name() + ".demand_hits")
+ .desc("number of demand (read+write) hits")
+ .flags(total)
+ ;
+ demandHits = hits[Packet::ReadReq] + hits[Packet::WriteReq];
+
+ overallHits
+ .name(name() + ".overall_hits")
+ .desc("number of overall hits")
+ .flags(total)
+ ;
+ overallHits = demandHits + hits[Packet::SoftPFReq] + hits[Packet::HardPFReq]
+ + hits[Packet::Writeback];
+
+ // Miss statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ misses[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_misses")
+ .desc("number of " + cstr + " misses")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMisses
+ .name(name() + ".demand_misses")
+ .desc("number of demand (read+write) misses")
+ .flags(total)
+ ;
+ demandMisses = misses[Packet::ReadReq] + misses[Packet::WriteReq];
+
+ overallMisses
+ .name(name() + ".overall_misses")
+ .desc("number of overall misses")
+ .flags(total)
+ ;
+ overallMisses = demandMisses + misses[Packet::SoftPFReq] +
+ misses[Packet::HardPFReq] + misses[Packet::Writeback];
+
+ // Miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ missLatency[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name() + "." + cstr + "_miss_latency")
+ .desc("number of " + cstr + " miss cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMissLatency
+ .name(name() + ".demand_miss_latency")
+ .desc("number of demand (read+write) miss cycles")
+ .flags(total)
+ ;
+ demandMissLatency = missLatency[Packet::ReadReq] + missLatency[Packet::WriteReq];
+
+ overallMissLatency
+ .name(name() + ".overall_miss_latency")
+ .desc("number of overall miss cycles")
+ .flags(total)
+ ;
+ overallMissLatency = demandMissLatency + missLatency[Packet::SoftPFReq] +
+ missLatency[Packet::HardPFReq];
+
+ // access formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ accesses[access_idx]
+ .name(name() + "." + cstr + "_accesses")
+ .desc("number of " + cstr + " accesses(hits+misses)")
+ .flags(total | nozero | nonan)
+ ;
+
+ accesses[access_idx] = hits[access_idx] + misses[access_idx];
+ }
+
+ demandAccesses
+ .name(name() + ".demand_accesses")
+ .desc("number of demand (read+write) accesses")
+ .flags(total)
+ ;
+ demandAccesses = demandHits + demandMisses;
+
+ overallAccesses
+ .name(name() + ".overall_accesses")
+ .desc("number of overall (read+write) accesses")
+ .flags(total)
+ ;
+ overallAccesses = overallHits + overallMisses;
+
+ // miss rate formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ missRate[access_idx]
+ .name(name() + "." + cstr + "_miss_rate")
+ .desc("miss rate for " + cstr + " accesses")
+ .flags(total | nozero | nonan)
+ ;
+
+ missRate[access_idx] = misses[access_idx] / accesses[access_idx];
+ }
+
+ demandMissRate
+ .name(name() + ".demand_miss_rate")
+ .desc("miss rate for demand accesses")
+ .flags(total)
+ ;
+ demandMissRate = demandMisses / demandAccesses;
+
+ overallMissRate
+ .name(name() + ".overall_miss_rate")
+ .desc("miss rate for overall accesses")
+ .flags(total)
+ ;
+ overallMissRate = overallMisses / overallAccesses;
+
+ // miss latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMissLatency[access_idx]
+ .name(name() + "." + cstr + "_avg_miss_latency")
+ .desc("average " + cstr + " miss latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMissLatency[access_idx] =
+ missLatency[access_idx] / misses[access_idx];
+ }
+
+ demandAvgMissLatency
+ .name(name() + ".demand_avg_miss_latency")
+ .desc("average overall miss latency")
+ .flags(total)
+ ;
+ demandAvgMissLatency = demandMissLatency / demandMisses;
+
+ overallAvgMissLatency
+ .name(name() + ".overall_avg_miss_latency")
+ .desc("average overall miss latency")
+ .flags(total)
+ ;
+ overallAvgMissLatency = overallMissLatency / overallMisses;
+
+ blocked_cycles.init(NUM_BLOCKED_CAUSES);
+ blocked_cycles
+ .name(name() + ".blocked_cycles")
+ .desc("number of cycles access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+
+ blocked_causes.init(NUM_BLOCKED_CAUSES);
+ blocked_causes
+ .name(name() + ".blocked")
+ .desc("number of cycles access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+ avg_blocked
+ .name(name() + ".avg_blocked_cycles")
+ .desc("average number of cycles each access was blocked")
+ .subname(Blocked_NoMSHRs, "no_mshrs")
+ .subname(Blocked_NoTargets, "no_targets")
+ ;
+
+ avg_blocked = blocked_cycles / blocked_causes;
+
+ fastWrites
+ .name(name() + ".fast_writes")
+ .desc("number of fast writes performed")
+ ;
+
+ cacheCopies
+ .name(name() + ".cache_copies")
+ .desc("number of cache copies performed")
+ ;
+
+}
diff --git a/src/mem/cache/base_cache.hh b/src/mem/cache/base_cache.hh
new file mode 100644
index 000000000..069dbab58
--- /dev/null
+++ b/src/mem/cache/base_cache.hh
@@ -0,0 +1,559 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declares a basic cache interface BaseCache.
+ */
+
+#ifndef __BASE_CACHE_HH__
+#define __BASE_CACHE_HH__
+
+#include <vector>
+#include <string>
+#include <list>
+#include <inttypes.h>
+
+#include "base/misc.hh"
+#include "base/statistics.hh"
+#include "base/trace.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/port.hh"
+#include "mem/request.hh"
+#include "sim/eventq.hh"
+
+/**
+ * Reasons for Caches to be Blocked.
+ */
+enum BlockedCause{
+ Blocked_NoMSHRs,
+ Blocked_NoTargets,
+ Blocked_NoWBBuffers,
+ Blocked_Coherence,
+ Blocked_Copy,
+ NUM_BLOCKED_CAUSES
+};
+
+/**
+ * Reasons for cache to request a bus.
+ */
+enum RequestCause{
+ Request_MSHR,
+ Request_WB,
+ Request_Coherence,
+ Request_PF
+};
+
+/**
+ * A basic cache interface. Implements some common functions for speed.
+ */
+class BaseCache : public MemObject
+{
+ class CachePort : public Port
+ {
+ public:
+ BaseCache *cache;
+
+ CachePort(const std::string &_name, BaseCache *_cache, bool _isCpuSide);
+
+ protected:
+ virtual bool recvTiming(Packet *pkt);
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop);
+
+ virtual int deviceBlockSize();
+
+ virtual void recvRetry();
+
+ public:
+ void setBlocked();
+
+ void clearBlocked();
+
+ bool blocked;
+
+ bool mustSendRetry;
+
+ bool isCpuSide;
+ };
+
+ struct CacheEvent : public Event
+ {
+ CachePort *cachePort;
+ Packet *pkt;
+
+ CacheEvent(CachePort *_cachePort);
+ CacheEvent(CachePort *_cachePort, Packet *_pkt);
+ void process();
+ const char *description();
+ };
+
+ protected:
+ CachePort *cpuSidePort;
+ CachePort *memSidePort;
+
+ public:
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+
+ private:
+ //To be defined in cache_impl.hh not in base class
+ virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide)
+ {
+ fatal("No implementation");
+ }
+
+ void recvStatusChange(Port::Status status, bool isCpuSide)
+ {
+ if (status == Port::RangeChange)
+ {
+ if (!isCpuSide)
+ {
+ cpuSidePort->sendStatusChange(Port::RangeChange);
+ }
+ else
+ {
+ memSidePort->sendStatusChange(Port::RangeChange);
+ }
+ }
+ }
+
+ virtual Packet *getPacket()
+ {
+ fatal("No implementation");
+ }
+
+ virtual Packet *getCoherencePacket()
+ {
+ fatal("No implementation");
+ }
+
+ virtual void sendResult(Packet* &pkt, bool success)
+ {
+
+ fatal("No implementation");
+ }
+
+ /**
+ * Bit vector of the blocking reasons for the access path.
+ * @sa #BlockedCause
+ */
+ uint8_t blocked;
+
+ /**
+ * Bit vector for the blocking reasons for the snoop path.
+ * @sa #BlockedCause
+ */
+ uint8_t blockedSnoop;
+
+ /**
+ * Bit vector for the outstanding requests for the master interface.
+ */
+ uint8_t masterRequests;
+
+ /**
+ * Bit vector for the outstanding requests for the slave interface.
+ */
+ uint8_t slaveRequests;
+
+ protected:
+
+ /** True if this cache is connected to the CPU. */
+ bool topLevelCache;
+
+ /** Stores time the cache blocked for statistics. */
+ Tick blockedCycle;
+
+ /** Block size of this cache */
+ const int blkSize;
+
+ /** The number of misses to trigger an exit event. */
+ Counter missCount;
+
+ public:
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+
+ /** Number of hits per thread for each type of command. @sa Packet::Command */
+ Stats::Vector<> hits[NUM_MEM_CMDS];
+ /** Number of hits for demand accesses. */
+ Stats::Formula demandHits;
+ /** Number of hit for all accesses. */
+ Stats::Formula overallHits;
+
+ /** Number of misses per thread for each type of command. @sa Packet::Command */
+ Stats::Vector<> misses[NUM_MEM_CMDS];
+ /** Number of misses for demand accesses. */
+ Stats::Formula demandMisses;
+ /** Number of misses for all accesses. */
+ Stats::Formula overallMisses;
+
+ /**
+ * Total number of cycles per thread/command spent waiting for a miss.
+ * Used to calculate the average miss latency.
+ */
+ Stats::Vector<> missLatency[NUM_MEM_CMDS];
+ /** Total number of cycles spent waiting for demand misses. */
+ Stats::Formula demandMissLatency;
+ /** Total number of cycles spent waiting for all misses. */
+ Stats::Formula overallMissLatency;
+
+ /** The number of accesses per command and thread. */
+ Stats::Formula accesses[NUM_MEM_CMDS];
+ /** The number of demand accesses. */
+ Stats::Formula demandAccesses;
+ /** The number of overall accesses. */
+ Stats::Formula overallAccesses;
+
+ /** The miss rate per command and thread. */
+ Stats::Formula missRate[NUM_MEM_CMDS];
+ /** The miss rate of all demand accesses. */
+ Stats::Formula demandMissRate;
+ /** The miss rate for all accesses. */
+ Stats::Formula overallMissRate;
+
+ /** The average miss latency per command and thread. */
+ Stats::Formula avgMissLatency[NUM_MEM_CMDS];
+ /** The average miss latency for demand misses. */
+ Stats::Formula demandAvgMissLatency;
+ /** The average miss latency for all misses. */
+ Stats::Formula overallAvgMissLatency;
+
+ /** The total number of cycles blocked for each blocked cause. */
+ Stats::Vector<> blocked_cycles;
+ /** The number of times this cache blocked for each blocked cause. */
+ Stats::Vector<> blocked_causes;
+
+ /** The average number of cycles blocked for each blocked cause. */
+ Stats::Formula avg_blocked;
+
+ /** The number of fast writes (WH64) performed. */
+ Stats::Scalar<> fastWrites;
+
+ /** The number of cache copies performed. */
+ Stats::Scalar<> cacheCopies;
+
+ /**
+ * @}
+ */
+
+ /**
+ * Register stats for this object.
+ */
+ virtual void regStats();
+
+ public:
+
+ class Params
+ {
+ public:
+ /** List of address ranges of this cache. */
+ std::vector<Range<Addr> > addrRange;
+ /** The hit latency for this cache. */
+ int hitLatency;
+ /** The block size of this cache. */
+ int blkSize;
+ /**
+ * The maximum number of misses this cache should handle before
+ * ending the simulation.
+ */
+ Counter maxMisses;
+
+ /**
+ * Construct an instance of this parameter class.
+ */
+ Params(std::vector<Range<Addr> > addr_range,
+ int hit_latency, int _blkSize, Counter max_misses)
+ : addrRange(addr_range), hitLatency(hit_latency), blkSize(_blkSize),
+ maxMisses(max_misses)
+ {
+ }
+ };
+
+ /**
+ * Create and initialize a basic cache object.
+ * @param name The name of this cache.
+ * @param hier_params Pointer to the HierParams object for this hierarchy
+ * of this cache.
+ * @param params The parameter object for this BaseCache.
+ */
+ BaseCache(const std::string &name, Params &params)
+ : MemObject(name), blocked(0), blockedSnoop(0), masterRequests(0),
+ slaveRequests(0), topLevelCache(false), blkSize(params.blkSize),
+ missCount(params.maxMisses)
+ {
+ //Start ports at null if more than one is created we should panic
+ cpuSidePort = NULL;
+ memSidePort = NULL;
+ }
+
+ virtual void init();
+
+ /**
+ * Query block size of a cache.
+ * @return The block size
+ */
+ int getBlockSize() const
+ {
+ return blkSize;
+ }
+
+ /**
+ * Returns true if this cache is connect to the CPU.
+ * @return True if this is a L1 cache.
+ */
+ bool isTopLevel()
+ {
+ return topLevelCache;
+ }
+
+ /**
+ * Returns true if the cache is blocked for accesses.
+ */
+ bool isBlocked()
+ {
+ return blocked != 0;
+ }
+
+ /**
+ * Returns true if the cache is blocked for snoops.
+ */
+ bool isBlockedForSnoop()
+ {
+ return blockedSnoop != 0;
+ }
+
+ /**
+ * Marks the access path of the cache as blocked for the given cause. This
+ * also sets the blocked flag in the slave interface.
+ * @param cause The reason for the cache blocking.
+ */
+ void setBlocked(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ if (blocked == 0) {
+ blocked_causes[cause]++;
+ blockedCycle = curTick;
+ }
+ blocked |= flag;
+ DPRINTF(Cache,"Blocking for cause %s\n", cause);
+ cpuSidePort->setBlocked();
+ }
+
+ /**
+ * Marks the snoop path of the cache as blocked for the given cause. This
+ * also sets the blocked flag in the master interface.
+ * @param cause The reason to block the snoop path.
+ */
+ void setBlockedForSnoop(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ blockedSnoop |= flag;
+ memSidePort->setBlocked();
+ }
+
+ /**
+ * Marks the cache as unblocked for the given cause. This also clears the
+ * blocked flags in the appropriate interfaces.
+ * @param cause The newly unblocked cause.
+ * @warning Calling this function can cause a blocked request on the bus to
+ * access the cache. The cache must be in a state to handle that request.
+ */
+ void clearBlocked(BlockedCause cause)
+ {
+ uint8_t flag = 1 << cause;
+ DPRINTF(Cache,"Unblocking for cause %s, causes left=%i\n",
+ cause, blocked);
+ if (blocked & flag)
+ {
+ blocked &= ~flag;
+ if (!isBlocked()) {
+ blocked_cycles[cause] += curTick - blockedCycle;
+ DPRINTF(Cache,"Unblocking from all causes\n");
+ cpuSidePort->clearBlocked();
+ }
+ }
+ if (blockedSnoop & flag)
+ {
+ blockedSnoop &= ~flag;
+ if (!isBlockedForSnoop()) {
+ memSidePort->clearBlocked();
+ }
+ }
+ }
+
+ /**
+ * True if the master bus should be requested.
+ * @return True if there are outstanding requests for the master bus.
+ */
+ bool doMasterRequest()
+ {
+ return masterRequests != 0;
+ }
+
+ /**
+ * Request the master bus for the given cause and time.
+ * @param cause The reason for the request.
+ * @param time The time to make the request.
+ */
+ void setMasterRequest(RequestCause cause, Tick time)
+ {
+ if (!doMasterRequest())
+ {
+ BaseCache::CacheEvent * reqCpu = new BaseCache::CacheEvent(memSidePort);
+ reqCpu->schedule(time);
+ }
+ uint8_t flag = 1<<cause;
+ masterRequests |= flag;
+ }
+
+ /**
+ * Clear the master bus request for the given cause.
+ * @param cause The request reason to clear.
+ */
+ void clearMasterRequest(RequestCause cause)
+ {
+ uint8_t flag = 1<<cause;
+ masterRequests &= ~flag;
+ }
+
+ /**
+ * Return true if the slave bus should be requested.
+ * @return True if there are outstanding requests for the slave bus.
+ */
+ bool doSlaveRequest()
+ {
+ return slaveRequests != 0;
+ }
+
+ /**
+ * Request the slave bus for the given reason and time.
+ * @param cause The reason for the request.
+ * @param time The time to make the request.
+ */
+ void setSlaveRequest(RequestCause cause, Tick time)
+ {
+ uint8_t flag = 1<<cause;
+ slaveRequests |= flag;
+ assert("Implement\n" && 0);
+// si->pktuest(time);
+ }
+
+ /**
+ * Clear the slave bus request for the given reason.
+ * @param cause The request reason to clear.
+ */
+ void clearSlaveRequest(RequestCause cause)
+ {
+ uint8_t flag = 1<<cause;
+ slaveRequests &= ~flag;
+ }
+
+ /**
+ * Send a response to the slave interface.
+ * @param pkt The request being responded to.
+ * @param time The time the response is ready.
+ */
+ void respond(Packet *pkt, Tick time)
+ {
+ pkt->makeTimingResponse();
+ pkt->result = Packet::Success;
+ CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+ reqCpu->schedule(time);
+ }
+
+ /**
+ * Send a reponse to the slave interface and calculate miss latency.
+ * @param pkt The request to respond to.
+ * @param time The time the response is ready.
+ */
+ void respondToMiss(Packet *pkt, Tick time)
+ {
+ if (!pkt->req->isUncacheable()) {
+ missLatency[pkt->cmdToIndex()][pkt->req->getThreadNum()] += time - pkt->time;
+ }
+ pkt->makeTimingResponse();
+ pkt->result = Packet::Success;
+ CacheEvent *reqCpu = new CacheEvent(cpuSidePort, pkt);
+ reqCpu->schedule(time);
+ }
+
+ /**
+ * Suppliess the data if cache to cache transfers are enabled.
+ * @param pkt The bus transaction to fulfill.
+ */
+ void respondToSnoop(Packet *pkt)
+ {
+ assert("Implement\n" && 0);
+// mi->respond(pkt,curTick + hitLatency);
+ }
+
+ /**
+ * Notification from master interface that a address range changed. Nothing
+ * to do for a cache.
+ */
+ void rangeChange() {}
+
+ void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop, bool isCpuSide)
+ {
+ if (isCpuSide)
+ {
+ AddrRangeList dummy;
+ memSidePort->getPeerAddressRanges(resp, dummy);
+ }
+ else
+ {
+ //This is where snoops get updated
+ return;
+ }
+ }
+};
+
+#endif //__BASE_CACHE_HH__
diff --git a/src/mem/cache/cache.cc b/src/mem/cache/cache.cc
new file mode 100644
index 000000000..db66c096e
--- /dev/null
+++ b/src/mem/cache/cache.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ * Lisa Hsu
+ * Kevin Lim
+ */
+
+/**
+ * @file
+ * Cache template instantiations.
+ */
+
+#include "mem/config/cache.hh"
+#include "mem/config/compression.hh"
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#if defined(USE_CACHE_LRU)
+#include "mem/cache/tags/lru.hh"
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#include "mem/cache/tags/fa_lru.hh"
+#endif
+
+#if defined(USE_CACHE_IIC)
+#include "mem/cache/tags/iic.hh"
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+#include "mem/cache/tags/split.hh"
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+#include "mem/cache/tags/split_lifo.hh"
+#endif
+
+#include "base/compression/null_compression.hh"
+#if defined(USE_LZSS_COMPRESSION)
+#include "base/compression/lzss_compression.hh"
+#endif
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/coherence/simple_coherence.hh"
+
+#include "mem/cache/cache_impl.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+
+#if defined(USE_CACHE_FALRU)
+template class Cache<CacheTags<FALRU,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<FALRU,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<FALRU,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_IIC)
+template class Cache<CacheTags<IIC,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<IIC,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<IIC,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<IIC,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_LRU)
+template class Cache<CacheTags<LRU,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<LRU,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<LRU,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<LRU,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+template class Cache<CacheTags<Split,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<Split,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<Split,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<Split,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+template class Cache<CacheTags<SplitLIFO,NullCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,NullCompression>, MissQueue, UniCoherence>;
+#if defined(USE_LZSS_COMPRESSION)
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, BlockingBuffer, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, BlockingBuffer, UniCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, MissQueue, SimpleCoherence>;
+template class Cache<CacheTags<SplitLIFO,LZSSCompression>, MissQueue, UniCoherence>;
+#endif
+#endif
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
new file mode 100644
index 000000000..989b8743e
--- /dev/null
+++ b/src/mem/cache/cache.hh
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Dave Greene
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Describes a cache based on template policies.
+ */
+
+#ifndef __CACHE_HH__
+#define __CACHE_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+#include "cpu/smt.hh" // SMT_MAX_THREADS
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/prefetch/prefetcher.hh"
+
+//Forward decleration
+class MSHR;
+
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering, class Coherence>
+class Cache : public BaseCache
+{
+ public:
+ /** Define the type of cache block to use. */
+ typedef typename TagStore::BlkType BlkType;
+
+ bool prefetchAccess;
+ protected:
+
+ /** Tag and data Storage */
+ TagStore *tags;
+ /** Miss and Writeback handler */
+ Buffering *missQueue;
+ /** Coherence protocol. */
+ Coherence *coherence;
+
+ /** Prefetcher */
+ Prefetcher<TagStore, Buffering> *prefetcher;
+
+ /** Do fast copies in this cache. */
+ bool doCopy;
+
+ /** Block on a delayed copy. */
+ bool blockOnCopy;
+
+ /**
+ * The clock ratio of the outgoing bus.
+ * Used for calculating critical word first.
+ */
+ int busRatio;
+
+ /**
+ * The bus width in bytes of the outgoing bus.
+ * Used for calculating critical word first.
+ */
+ int busWidth;
+
+ /**
+ * The latency of a hit in this device.
+ */
+ int hitLatency;
+
+ /**
+ * A permanent mem req to always be used to cause invalidations.
+ * Used to append to target list, to cause an invalidation.
+ */
+ Packet * invalidatePkt;
+
+ /**
+ * Temporarily move a block into a MSHR.
+ * @todo Remove this when LSQ/SB are fixed and implemented in memtest.
+ */
+ void pseudoFill(Addr addr);
+
+ /**
+ * Temporarily move a block into an existing MSHR.
+ * @todo Remove this when LSQ/SB are fixed and implemented in memtest.
+ */
+ void pseudoFill(MSHR *mshr);
+
+ public:
+
+ class Params
+ {
+ public:
+ TagStore *tags;
+ Buffering *missQueue;
+ Coherence *coherence;
+ bool doCopy;
+ bool blockOnCopy;
+ BaseCache::Params baseParams;
+ Prefetcher<TagStore, Buffering> *prefetcher;
+ bool prefetchAccess;
+ int hitLatency;
+
+ Params(TagStore *_tags, Buffering *mq, Coherence *coh,
+ bool do_copy, BaseCache::Params params,
+ Prefetcher<TagStore, Buffering> *_prefetcher,
+ bool prefetch_access, int hit_latency)
+ : tags(_tags), missQueue(mq), coherence(coh), doCopy(do_copy),
+ blockOnCopy(false), baseParams(params),
+ prefetcher(_prefetcher), prefetchAccess(prefetch_access),
+ hitLatency(hit_latency)
+ {
+ }
+ };
+
+ /** Instantiates a basic cache object. */
+ Cache(const std::string &_name, Params &params);
+
+ virtual bool doTimingAccess(Packet *pkt, CachePort *cachePort,
+ bool isCpuSide);
+
+ virtual Tick doAtomicAccess(Packet *pkt, bool isCpuSide);
+
+ virtual void doFunctionalAccess(Packet *pkt, bool isCpuSide);
+
+ virtual void recvStatusChange(Port::Status status, bool isCpuSide);
+
+ void regStats();
+
+ /**
+ * Performs the access specified by the request.
+ * @param pkt The request to perform.
+ * @return The result of the access.
+ */
+ bool access(Packet * &pkt);
+
+ /**
+ * Selects a request to send on the bus.
+ * @return The memory request to service.
+ */
+ virtual Packet * getPacket();
+
+ /**
+ * Was the request was sent successfully?
+ * @param pkt The request.
+ * @param success True if the request was sent successfully.
+ */
+ virtual void sendResult(Packet * &pkt, bool success);
+
+ /**
+ * Handles a response (cache line fill/write ack) from the bus.
+ * @param pkt The request being responded to.
+ */
+ void handleResponse(Packet * &pkt);
+
+ /**
+ * Start handling a copy transaction.
+ * @param pkt The copy request to perform.
+ */
+ void startCopy(Packet * &pkt);
+
+ /**
+ * Handle a delayed copy transaction.
+ * @param pkt The delayed copy request to continue.
+ * @param addr The address being responded to.
+ * @param blk The block of the current response.
+ * @param mshr The mshr being handled.
+ */
+ void handleCopy(Packet * &pkt, Addr addr, BlkType *blk, MSHR *mshr);
+
+ /**
+ * Selects a coherence message to forward to lower levels of the hierarchy.
+ * @return The coherence message to forward.
+ */
+ virtual Packet * getCoherencePacket();
+
+ /**
+ * Snoops bus transactions to maintain coherence.
+ * @param pkt The current bus transaction.
+ */
+ void snoop(Packet * &pkt);
+
+ void snoopResponse(Packet * &pkt);
+
+ /**
+ * Invalidates the block containing address if found.
+ * @param addr The address to look for.
+ * @param asid The address space ID of the address.
+ * @todo Is this function necessary?
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Squash all requests associated with specified thread.
+ * intended for use by I-cache.
+ * @param threadNum The thread to squash.
+ */
+ void squash(int threadNum)
+ {
+ missQueue->squash(threadNum);
+ }
+
+ /**
+ * Return the number of outstanding misses in a Cache.
+ * Default returns 0.
+ *
+ * @retval unsigned The number of missing still outstanding.
+ */
+ unsigned outstandingMisses() const
+ {
+ return missQueue->getMisses();
+ }
+
+ /**
+ * Perform the access specified in the request and return the estimated
+ * time of completion. This function can either update the hierarchy state
+ * or just perform the access wherever the data is found depending on the
+ * state of the update flag.
+ * @param pkt The memory request to satisfy
+ * @param update If true, update the hierarchy, otherwise just perform the
+ * request.
+ * @return The estimated completion time.
+ */
+ Tick probe(Packet * &pkt, bool update);
+
+ /**
+ * Snoop for the provided request in the cache and return the estimated
+ * time of completion.
+ * @todo Can a snoop probe not change state?
+ * @param pkt The memory request to satisfy
+ * @param update If true, update the hierarchy, otherwise just perform the
+ * request.
+ * @return The estimated completion time.
+ */
+ Tick snoopProbe(Packet * &pkt, bool update);
+};
+
+#endif // __CACHE_HH__
diff --git a/src/mem/cache/cache_blk.hh b/src/mem/cache/cache_blk.hh
new file mode 100644
index 000000000..a75c9611d
--- /dev/null
+++ b/src/mem/cache/cache_blk.hh
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/** @file
+ * Definitions of a simple cache block class.
+ */
+
+#ifndef __CACHE_BLK_HH__
+#define __CACHE_BLK_HH__
+
+#include "sim/root.hh" // for Tick
+#include "arch/isa_traits.hh" // for Addr
+
+#include <iostream>
+
+/**
+ * Cache block status bit assignments
+ */
+enum CacheBlkStatusBits {
+ /** valid, readable */
+ BlkValid = 0x01,
+ /** write permission */
+ BlkWritable = 0x02,
+ /** dirty (modified) */
+ BlkDirty = 0x04,
+ /** compressed */
+ BlkCompressed = 0x08,
+ /** block was referenced */
+ BlkReferenced = 0x10,
+ /** block was a hardware prefetch yet unaccessed*/
+ BlkHWPrefetched = 0x20
+};
+
+/**
+ * A Basic Cache block.
+ * Contains the tag, status, and a pointer to data.
+ */
+class CacheBlk
+{
+ public:
+ /** The address space ID of this block. */
+ int asid;
+ /** Data block tag value. */
+ Addr tag;
+ /**
+ * Contains a copy of the data in this block for easy access. This is used
+ * for efficient execution when the data could be actually stored in
+ * another format (COW, compressed, sub-blocked, etc). In all cases the
+ * data stored here should be kept consistant with the actual data
+ * referenced by this block.
+ */
+ uint8_t *data;
+ /** the number of bytes stored in this block. */
+ int size;
+
+ /** block state: OR of CacheBlkStatusBit */
+ typedef unsigned State;
+
+ /** The current status of this block. @sa CacheBlockStatusBits */
+ State status;
+
+ /** Which curTick will this block be accessable */
+ Tick whenReady;
+
+ /**
+ * The set this block belongs to.
+ * @todo Move this into subclasses when we fix CacheTags to use them.
+ */
+ int set;
+
+ /** Number of references to this block since it was brought in. */
+ int refCount;
+
+ CacheBlk()
+ : asid(-1), tag(0), data(0) ,size(0), status(0), whenReady(0),
+ set(-1), refCount(0)
+ {}
+
+ /**
+ * Copy the state of the given block into this one.
+ * @param rhs The block to copy.
+ * @return a const reference to this block.
+ */
+ const CacheBlk& operator=(const CacheBlk& rhs)
+ {
+ asid = rhs.asid;
+ tag = rhs.tag;
+ data = rhs.data;
+ size = rhs.size;
+ status = rhs.status;
+ whenReady = rhs.whenReady;
+ set = rhs.set;
+ refCount = rhs.refCount;
+ return *this;
+ }
+
+ /**
+ * Checks the write permissions of this block.
+ * @return True if the block is writable.
+ */
+ bool isWritable() const
+ {
+ const int needed_bits = BlkWritable | BlkValid;
+ return (status & needed_bits) == needed_bits;
+ }
+
+ /**
+ * Checks that a block is valid (readable).
+ * @return True if the block is valid.
+ */
+ bool isValid() const
+ {
+ return (status & BlkValid) != 0;
+ }
+
+ /**
+ * Check to see if a block has been written.
+ * @return True if the block is dirty.
+ */
+ bool isModified() const
+ {
+ return (status & BlkDirty) != 0;
+ }
+
+ /**
+ * Check to see if this block contains compressed data.
+ * @return True iF the block's data is compressed.
+ */
+ bool isCompressed() const
+ {
+ return (status & BlkCompressed) != 0;
+ }
+
+ /**
+ * Check if this block has been referenced.
+ * @return True if the block has been referenced.
+ */
+ bool isReferenced() const
+ {
+ return (status & BlkReferenced) != 0;
+ }
+
+ /**
+ * Check if this block was the result of a hardware prefetch, yet to
+ * be touched.
+ * @return True if the block was a hardware prefetch, unaccesed.
+ */
+ bool isPrefetch() const
+ {
+ return (status & BlkHWPrefetched) != 0;
+ }
+
+
+};
+
+/**
+ * Output a CacheBlk to the given ostream.
+ * @param out The stream for the output.
+ * @param blk The cache block to print.
+ *
+ * @return The output stream.
+ */
+inline std::ostream &
+operator<<(std::ostream &out, const CacheBlk &blk)
+{
+ out << std::hex << std::endl;
+ out << " Tag: " << blk.tag << std::endl;
+ out << " Status: " << blk.status << std::endl;
+
+ return(out << std::dec);
+}
+
+#endif //__CACHE_BLK_HH__
diff --git a/src/mem/cache/cache_builder.cc b/src/mem/cache/cache_builder.cc
new file mode 100644
index 000000000..05a149a1c
--- /dev/null
+++ b/src/mem/cache/cache_builder.cc
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Simobject instatiation of caches.
+ */
+#include <vector>
+
+// Must be included first to determine which caches we want
+#include "mem/config/cache.hh"
+#include "mem/config/compression.hh"
+#include "mem/config/prefetch.hh"
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/cache.hh"
+#include "mem/bus.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+#include "sim/builder.hh"
+
+// Tag Templates
+#if defined(USE_CACHE_LRU)
+#include "mem/cache/tags/lru.hh"
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#include "mem/cache/tags/fa_lru.hh"
+#endif
+
+#if defined(USE_CACHE_IIC)
+#include "mem/cache/tags/iic.hh"
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+#include "mem/cache/tags/split.hh"
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+#include "mem/cache/tags/split_lifo.hh"
+#endif
+
+// Compression Templates
+#include "base/compression/null_compression.hh"
+#if defined(USE_LZSS_COMPRESSION)
+#include "base/compression/lzss_compression.hh"
+#endif
+
+// CacheTags Templates
+#include "mem/cache/tags/cache_tags.hh"
+
+// MissQueue Templates
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+// Coherence Templates
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/coherence/simple_coherence.hh"
+
+//Prefetcher Headers
+#if defined(USE_GHB)
+#include "mem/cache/prefetch/ghb_prefetcher.hh"
+#endif
+#if defined(USE_TAGGED)
+#include "mem/cache/prefetch/tagged_prefetcher.hh"
+#endif
+#if defined(USE_STRIDED)
+#include "mem/cache/prefetch/stride_prefetcher.hh"
+#endif
+
+
+using namespace std;
+using namespace TheISA;
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(BaseCache)
+
+ Param<int> size;
+ Param<int> assoc;
+ Param<int> block_size;
+ Param<int> latency;
+ Param<int> mshrs;
+ Param<int> tgts_per_mshr;
+ Param<int> write_buffers;
+ Param<bool> prioritizeRequests;
+// SimObjectParam<Bus *> in_bus;
+// SimObjectParam<Bus *> out_bus;
+ Param<bool> do_copy;
+ SimObjectParam<CoherenceProtocol *> protocol;
+ Param<Addr> trace_addr;
+ Param<int> hash_delay;
+#if defined(USE_CACHE_IIC)
+ SimObjectParam<Repl *> repl;
+#endif
+ Param<bool> compressed_bus;
+ Param<bool> store_compressed;
+ Param<bool> adaptive_compression;
+ Param<int> compression_latency;
+ Param<int> subblock_size;
+ Param<Counter> max_miss_count;
+// SimObjectParam<HierParams *> hier;
+ VectorParam<Range<Addr> > addr_range;
+// SimObjectParam<MemTraceWriter *> mem_trace;
+ Param<bool> split;
+ Param<int> split_size;
+ Param<bool> lifo;
+ Param<bool> two_queue;
+ Param<bool> prefetch_miss;
+ Param<bool> prefetch_access;
+ Param<int> prefetcher_size;
+ Param<bool> prefetch_past_page;
+ Param<bool> prefetch_serial_squash;
+ Param<Tick> prefetch_latency;
+ Param<int> prefetch_degree;
+ Param<string> prefetch_policy;
+ Param<bool> prefetch_cache_check_push;
+ Param<bool> prefetch_use_cpu_id;
+ Param<bool> prefetch_data_accesses_only;
+ Param<int> hit_latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(BaseCache)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(BaseCache)
+
+ INIT_PARAM(size, "capacity in bytes"),
+ INIT_PARAM(assoc, "associativity"),
+ INIT_PARAM(block_size, "block size in bytes"),
+ INIT_PARAM(latency, "hit latency in CPU cycles"),
+ INIT_PARAM(mshrs, "number of MSHRs (max outstanding requests)"),
+ INIT_PARAM(tgts_per_mshr, "max number of accesses per MSHR"),
+ INIT_PARAM_DFLT(write_buffers, "number of write buffers", 8),
+ INIT_PARAM_DFLT(prioritizeRequests, "always service demand misses first",
+ false),
+/* INIT_PARAM_DFLT(in_bus, "incoming bus object", NULL),
+ INIT_PARAM(out_bus, "outgoing bus object"),
+*/
+ INIT_PARAM_DFLT(do_copy, "perform fast copies in the cache", false),
+ INIT_PARAM_DFLT(protocol, "coherence protocol to use in the cache", NULL),
+ INIT_PARAM_DFLT(trace_addr, "address to trace", 0),
+
+ INIT_PARAM_DFLT(hash_delay, "time in cycles of hash access",1),
+#if defined(USE_CACHE_IIC)
+ INIT_PARAM_DFLT(repl, "replacement policy",NULL),
+#endif
+ INIT_PARAM_DFLT(compressed_bus,
+ "This cache connects to a compressed memory",
+ false),
+ INIT_PARAM_DFLT(store_compressed, "Store compressed data in the cache",
+ false),
+ INIT_PARAM_DFLT(adaptive_compression, "Use an adaptive compression scheme",
+ false),
+ INIT_PARAM_DFLT(compression_latency,
+ "Latency in cycles of compression algorithm",
+ 0),
+ INIT_PARAM_DFLT(subblock_size,
+ "Size of subblock in IIC used for compression",
+ 0),
+ INIT_PARAM_DFLT(max_miss_count,
+ "The number of misses to handle before calling exit",
+ 0),
+/* INIT_PARAM_DFLT(hier,
+ "Hierarchy global variables",
+ &defaultHierParams),
+*/
+ INIT_PARAM_DFLT(addr_range, "The address range in bytes",
+ vector<Range<Addr> >(1,RangeIn((Addr)0, MaxAddr))),
+// INIT_PARAM_DFLT(mem_trace, "Memory trace to write accesses to", NULL),
+ INIT_PARAM_DFLT(split, "Whether this is a partitioned cache", false),
+ INIT_PARAM_DFLT(split_size, "the number of \"ways\" belonging to the LRU partition", 0),
+ INIT_PARAM_DFLT(lifo, "whether you are using a LIFO repl. policy", false),
+ INIT_PARAM_DFLT(two_queue, "whether the lifo should have two queue replacement", false),
+ INIT_PARAM_DFLT(prefetch_miss, "wheter you are using the hardware prefetcher from Miss stream", false),
+ INIT_PARAM_DFLT(prefetch_access, "wheter you are using the hardware prefetcher from Access stream", false),
+ INIT_PARAM_DFLT(prefetcher_size, "Number of entries in the harware prefetch queue", 100),
+ INIT_PARAM_DFLT(prefetch_past_page, "Allow prefetches to cross virtual page boundaries", false),
+ INIT_PARAM_DFLT(prefetch_serial_squash, "Squash prefetches with a later time on a subsequent miss", false),
+ INIT_PARAM_DFLT(prefetch_latency, "Latency of the prefetcher", 10),
+ INIT_PARAM_DFLT(prefetch_degree, "Degree of the prefetch depth", 1),
+ INIT_PARAM_DFLT(prefetch_policy, "Type of prefetcher to use", "none"),
+ INIT_PARAM_DFLT(prefetch_cache_check_push, "Check if in cash on push or pop of prefetch queue", true),
+ INIT_PARAM_DFLT(prefetch_use_cpu_id, "Use the CPU ID to seperate calculations of prefetches", true),
+ INIT_PARAM_DFLT(prefetch_data_accesses_only, "Only prefetch on data not on instruction accesses", false),
+ INIT_PARAM_DFLT(hit_latency, "Hit Latecny for a succesful access", 1)
+END_INIT_SIM_OBJECT_PARAMS(BaseCache)
+
+
+#define BUILD_CACHE(t, comp, b, c) do { \
+ Prefetcher<CacheTags<t, comp>, b> *pf; \
+ if (pf_policy == "tagged") { \
+ BUILD_TAGGED_PREFETCHER(t, comp, b); \
+ } \
+ else if (pf_policy == "stride") { \
+ BUILD_STRIDED_PREFETCHER(t, comp, b); \
+ } \
+ else if (pf_policy == "ghb") { \
+ BUILD_GHB_PREFETCHER(t, comp, b); \
+ } \
+ else { \
+ BUILD_NULL_PREFETCHER(t, comp, b); \
+ } \
+ Cache<CacheTags<t, comp>, b, c>::Params params(tagStore, mq, coh, \
+ do_copy, base_params, \
+ /*in_bus, out_bus,*/ pf, \
+ prefetch_access, hit_latency); \
+ Cache<CacheTags<t, comp>, b, c> *retval = \
+ new Cache<CacheTags<t, comp>, b, c>(getInstanceName(), /*hier,*/ \
+ params); \
+/* if (in_bus == NULL) { \
+ retval->setSlaveInterface(new MemoryInterface<Cache<CacheTags<t, comp>, b, c> >(getInstanceName(), hier, retval, mem_trace)); \
+ } else { \
+ retval->setSlaveInterface(new SlaveInterface<Cache<CacheTags<t, comp>, b, c>, Bus>(getInstanceName(), hier, retval, in_bus, mem_trace)); \
+ } \
+ retval->setMasterInterface(new MasterInterface<Cache<CacheTags<t, comp>, b, c>, Bus>(getInstanceName(), hier, retval, out_bus)); \
+ out_bus->rangeChange(); \
+ return retval; \
+*/return retval; \
+ } while (0)
+
+#define BUILD_CACHE_PANIC(x) do { \
+ panic("%s not compiled into M5", x); \
+ } while (0)
+
+#if defined(USE_LZSS_COMPRESSION)
+#define BUILD_COMPRESSED_CACHE(TAGS, tags, b, c) do { \
+ if (compressed_bus || store_compressed){ \
+ CacheTags<TAGS, LZSSCompression> *tagStore = \
+ new CacheTags<TAGS, LZSSCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression, \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, LZSSCompression, b, c); \
+ } else { \
+ CacheTags<TAGS, NullCompression> *tagStore = \
+ new CacheTags<TAGS, NullCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression, \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, NullCompression, b, c); \
+ } \
+ } while (0)
+#else
+#define BUILD_COMPRESSED_CACHE(TAGS, tags, b, c) do { \
+ if (compressed_bus || store_compressed){ \
+ BUILD_CACHE_PANIC("compressed caches"); \
+ } else { \
+ CacheTags<TAGS, NullCompression> *tagStore = \
+ new CacheTags<TAGS, NullCompression>(tags, \
+ compression_latency, \
+ true, store_compressed, \
+ adaptive_compression \
+ prefetch_miss); \
+ BUILD_CACHE(TAGS, NullCompression, b, c); \
+ } \
+ } while (0)
+#endif
+
+#if defined(USE_CACHE_FALRU)
+#define BUILD_FALRU_CACHE(b,c) do { \
+ FALRU *tags = new FALRU(block_size, size, latency); \
+ BUILD_COMPRESSED_CACHE(FALRU, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_FALRU_CACHE(b, c) BUILD_CACHE_PANIC("falru cache")
+#endif
+
+#if defined(USE_CACHE_LRU)
+#define BUILD_LRU_CACHE(b, c) do { \
+ LRU *tags = new LRU(numSets, block_size, assoc, latency); \
+ BUILD_COMPRESSED_CACHE(LRU, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_LRU_CACHE(b, c) BUILD_CACHE_PANIC("lru cache")
+#endif
+
+#if defined(USE_CACHE_SPLIT)
+#define BUILD_SPLIT_CACHE(b, c) do { \
+ Split *tags = new Split(numSets, block_size, assoc, split_size, lifo, \
+ two_queue, latency); \
+ BUILD_COMPRESSED_CACHE(Split, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_SPLIT_CACHE(b, c) BUILD_CACHE_PANIC("split cache")
+#endif
+
+#if defined(USE_CACHE_SPLIT_LIFO)
+#define BUILD_SPLIT_LIFO_CACHE(b, c) do { \
+ SplitLIFO *tags = new SplitLIFO(block_size, size, assoc, \
+ latency, two_queue, -1); \
+ BUILD_COMPRESSED_CACHE(SplitLIFO, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_SPLIT_LIFO_CACHE(b, c) BUILD_CACHE_PANIC("lifo cache")
+#endif
+
+#if defined(USE_CACHE_IIC)
+#define BUILD_IIC_CACHE(b ,c) do { \
+ IIC *tags = new IIC(iic_params); \
+ BUILD_COMPRESSED_CACHE(IIC, tags, b, c); \
+ } while (0)
+#else
+#define BUILD_IIC_CACHE(b, c) BUILD_CACHE_PANIC("iic")
+#endif
+
+#define BUILD_CACHES(b, c) do { \
+ if (repl == NULL) { \
+ if (numSets == 1) { \
+ BUILD_FALRU_CACHE(b, c); \
+ } else { \
+ if (split == true) { \
+ BUILD_SPLIT_CACHE(b, c); \
+ } else if (lifo == true) { \
+ BUILD_SPLIT_LIFO_CACHE(b, c); \
+ } else { \
+ BUILD_LRU_CACHE(b, c); \
+ } \
+ } \
+ } else { \
+ BUILD_IIC_CACHE(b, c); \
+ } \
+ } while (0)
+
+#define BUILD_COHERENCE(b) do { \
+ if (protocol == NULL) { \
+ UniCoherence *coh = new UniCoherence(); \
+ BUILD_CACHES(b, UniCoherence); \
+ } else { \
+ SimpleCoherence *coh = new SimpleCoherence(protocol); \
+ BUILD_CACHES(b, SimpleCoherence); \
+ } \
+ } while (0)
+
+#if defined(USE_TAGGED)
+#define BUILD_TAGGED_PREFETCHER(t, comp, b) pf = new \
+ TaggedPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree)
+#else
+#define BUILD_TAGGED_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("Tagged Prefetcher")
+#endif
+
+#if defined(USE_STRIDED)
+#define BUILD_STRIDED_PREFETCHER(t, comp, b) pf = new \
+ StridePrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree, \
+ prefetch_use_cpu_id)
+#else
+#define BUILD_STRIDED_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("Stride Prefetcher")
+#endif
+
+#if defined(USE_GHB)
+#define BUILD_GHB_PREFETCHER(t, comp, b) pf = new \
+ GHBPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree, \
+ prefetch_use_cpu_id)
+#else
+#define BUILD_GHB_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("GHB Prefetcher")
+#endif
+
+#if defined(USE_TAGGED)
+#define BUILD_NULL_PREFETCHER(t, comp, b) pf = new \
+ TaggedPrefetcher<CacheTags<t, comp>, b>(prefetcher_size, \
+ !prefetch_past_page, \
+ prefetch_serial_squash, \
+ prefetch_cache_check_push, \
+ prefetch_data_accesses_only, \
+ prefetch_latency, \
+ prefetch_degree)
+#else
+#define BUILD_NULL_PREFETCHER(t, comp, b) BUILD_CACHE_PANIC("NULL Prefetcher (uses Tagged)")
+#endif
+
+CREATE_SIM_OBJECT(BaseCache)
+{
+ string name = getInstanceName();
+ int numSets = size / (assoc * block_size);
+ string pf_policy = prefetch_policy;
+ if (subblock_size == 0) {
+ subblock_size = block_size;
+ }
+
+ // Build BaseCache param object
+ BaseCache::Params base_params(addr_range, latency,
+ block_size, max_miss_count);
+
+ //Warnings about prefetcher policy
+ if (pf_policy == "none" && (prefetch_miss || prefetch_access)) {
+ panic("With no prefetcher, you shouldn't prefetch from"
+ " either miss or access stream\n");
+ }
+ if ((pf_policy == "tagged" || pf_policy == "stride" ||
+ pf_policy == "ghb") && !(prefetch_miss || prefetch_access)) {
+ warn("With this prefetcher you should chose a prefetch"
+ " stream (miss or access)\nNo Prefetching will occur\n");
+ }
+ if ((pf_policy == "tagged" || pf_policy == "stride" ||
+ pf_policy == "ghb") && prefetch_miss && prefetch_access) {
+ panic("Can't do prefetches from both miss and access"
+ " stream\n");
+ }
+ if (pf_policy != "tagged" && pf_policy != "stride" &&
+ pf_policy != "ghb" && pf_policy != "none") {
+ panic("Unrecognized form of a prefetcher: %s, try using"
+ "['none','stride','tagged','ghb']\n", pf_policy);
+ }
+
+#if defined(USE_CACHE_IIC)
+ // Build IIC params
+ IIC::Params iic_params;
+ iic_params.size = size;
+ iic_params.numSets = numSets;
+ iic_params.blkSize = block_size;
+ iic_params.assoc = assoc;
+ iic_params.hashDelay = hash_delay;
+ iic_params.hitLatency = latency;
+ iic_params.rp = repl;
+ iic_params.subblockSize = subblock_size;
+#else
+ const void *repl = NULL;
+#endif
+
+ if (mshrs == 1 /*|| out_bus->doEvents() == false*/) {
+ BlockingBuffer *mq = new BlockingBuffer(true);
+ BUILD_COHERENCE(BlockingBuffer);
+ } else {
+ MissQueue *mq = new MissQueue(mshrs, tgts_per_mshr, write_buffers,
+ true, prefetch_miss);
+ BUILD_COHERENCE(MissQueue);
+ }
+ return NULL;
+}
+
+REGISTER_SIM_OBJECT("BaseCache", BaseCache)
+
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
new file mode 100644
index 000000000..11cd84e88
--- /dev/null
+++ b/src/mem/cache/cache_impl.hh
@@ -0,0 +1,672 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Dave Greene
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Cache definitions.
+ */
+
+#include <assert.h>
+#include <math.h>
+
+#include <cassert>
+#include <iostream>
+#include <string>
+
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "cpu/smt.hh"
+
+#include "mem/cache/cache.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/prefetch/prefetcher.hh"
+
+#include "sim/sim_events.hh" // for SimExitEvent
+
+template<class TagStore, class Buffering, class Coherence>
+bool
+Cache<TagStore,Buffering,Coherence>::
+doTimingAccess(Packet *pkt, CachePort *cachePort, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
+ pkt->req->setScResult(1);
+ }
+ access(pkt);
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoop(pkt);
+ }
+ return true;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::
+doAtomicAccess(Packet *pkt, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ //Temporary solution to LL/SC
+ if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
+ pkt->req->setScResult(1);
+ }
+
+ probe(pkt, true);
+ //TEMP ALWAYS SUCCES FOR NOW
+ pkt->result = Packet::Success;
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoopProbe(pkt, true);
+ }
+ //Fix this timing info
+ return hitLatency;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::
+doFunctionalAccess(Packet *pkt, bool isCpuSide)
+{
+ if (isCpuSide)
+ {
+ //TEMP USE CPU?THREAD 0 0
+ pkt->req->setThreadContext(0,0);
+
+ //Temporary solution to LL/SC
+ if (pkt->isWrite() && (pkt->req->getFlags() & LOCKED)) {
+ assert("Can't handle LL/SC on functional path\n");
+ }
+
+ probe(pkt, true);
+ //TEMP ALWAYS SUCCESFUL FOR NOW
+ pkt->result = Packet::Success;
+ }
+ else
+ {
+ if (pkt->isResponse())
+ handleResponse(pkt);
+ else
+ snoopProbe(pkt, true);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::
+recvStatusChange(Port::Status status, bool isCpuSide)
+{
+
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Cache<TagStore,Buffering,Coherence>::
+Cache(const std::string &_name,
+ Cache<TagStore,Buffering,Coherence>::Params &params)
+ : BaseCache(_name, params.baseParams),
+ prefetchAccess(params.prefetchAccess),
+ tags(params.tags), missQueue(params.missQueue),
+ coherence(params.coherence), prefetcher(params.prefetcher),
+ doCopy(params.doCopy), blockOnCopy(params.blockOnCopy)
+{
+//FIX BUS POINTERS
+// if (params.in == NULL) {
+ topLevelCache = true;
+// }
+//PLEASE FIX THIS, BUS SIZES NOT BEING USED
+ tags->setCache(this, blkSize, 1/*params.out->width, params.out->clockRate*/);
+ tags->setPrefetcher(prefetcher);
+ missQueue->setCache(this);
+ missQueue->setPrefetcher(prefetcher);
+ coherence->setCache(this);
+ prefetcher->setCache(this);
+ prefetcher->setTags(tags);
+ prefetcher->setBuffer(missQueue);
+#if 0
+ invalidatePkt = new Packet;
+ invalidatePkt->cmd = Packet::InvalidateReq;
+#endif
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::regStats()
+{
+ BaseCache::regStats();
+ tags->regStats(name());
+ missQueue->regStats(name());
+ coherence->regStats(name());
+ prefetcher->regStats(name());
+}
+
+template<class TagStore, class Buffering, class Coherence>
+bool
+Cache<TagStore,Buffering,Coherence>::access(PacketPtr &pkt)
+{
+//@todo Add back in MemDebug Calls
+// MemDebug::cacheAccess(pkt);
+ BlkType *blk = NULL;
+ PacketList writebacks;
+ int size = blkSize;
+ int lat = hitLatency;
+ if (prefetchAccess) {
+ //We are determining prefetches on access stream, call prefetcher
+ prefetcher->handleMiss(pkt, curTick);
+ }
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->isInvalidate() && !pkt->isRead()
+ && !pkt->isWrite()) {
+ //Upgrade or Invalidate
+ //Look into what happens if two slave caches on bus
+ DPRINTF(Cache, "%s %x ? blk_addr: %x\n", pkt->cmdString(),
+ pkt->getAddr() & (((ULL(1))<<48)-1),
+ pkt->getAddr() & ~((Addr)blkSize - 1));
+
+ //@todo Should this return latency have the hit latency in it?
+// respond(pkt,curTick+lat);
+ pkt->flags |= SATISFIED;
+// return MA_HIT; //@todo, return values
+ return true;
+ }
+ blk = tags->handleAccess(pkt, lat, writebacks);
+ } else {
+ size = pkt->getSize();
+ }
+ // If this is a block size write/hint (WH64) allocate the block here
+ // if the coherence protocol allows it.
+ /** @todo make the fast write alloc (wh64) work with coherence. */
+ /** @todo Do we want to do fast writes for writebacks as well? */
+ if (!blk && pkt->getSize() >= blkSize && coherence->allowFastWrites() &&
+ (pkt->cmd == Packet::WriteReq || pkt->cmd == Packet::WriteInvalidateReq) ) {
+ // not outstanding misses, can do this
+ MSHR* outstanding_miss = missQueue->findMSHR(pkt->getAddr());
+ if (pkt->cmd == Packet::WriteInvalidateReq || !outstanding_miss) {
+ if (outstanding_miss) {
+ warn("WriteInv doing a fastallocate"
+ "with an outstanding miss to the same address\n");
+ }
+ blk = tags->handleFill(NULL, pkt, BlkValid | BlkWritable,
+ writebacks);
+ ++fastWrites;
+ }
+ }
+ while (!writebacks.empty()) {
+ missQueue->doWriteback(writebacks.front());
+ writebacks.pop_front();
+ }
+ DPRINTF(Cache, "%s %x %s blk_addr: %x pc %x\n", pkt->cmdString(),
+ pkt->getAddr() & (((ULL(1))<<48)-1), (blk) ? "hit" : "miss",
+ pkt->getAddr() & ~((Addr)blkSize - 1), pkt->req->getPC());
+ if (blk) {
+ // Hit
+ hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ // clear dirty bit if write through
+ if (pkt->needsResponse())
+ respond(pkt, curTick+lat);
+// return MA_HIT;
+ return true;
+ }
+
+ // Miss
+ if (!pkt->req->isUncacheable()) {
+ misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ /** @todo Move miss count code into BaseCache */
+ if (missCount) {
+ --missCount;
+ if (missCount == 0)
+ new SimLoopExitEvent(curTick, "A cache reached the maximum miss count");
+ }
+ }
+ missQueue->handleMiss(pkt, size, curTick + hitLatency);
+// return MA_CACHE_MISS;
+ return true;
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Packet *
+Cache<TagStore,Buffering,Coherence>::getPacket()
+{
+ Packet * pkt = missQueue->getPacket();
+ if (pkt) {
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->cmd == Packet::HardPFReq) misses[Packet::HardPFReq][pkt->req->getThreadNum()]++;
+ BlkType *blk = tags->findBlock(pkt);
+ Packet::Command cmd = coherence->getBusCmd(pkt->cmd,
+ (blk)? blk->status : 0);
+ missQueue->setBusCmd(pkt, cmd);
+ }
+ }
+
+ assert(!doMasterRequest() || missQueue->havePending());
+ assert(!pkt || pkt->time <= curTick);
+ return pkt;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::sendResult(PacketPtr &pkt, bool success)
+{
+ if (success) {
+ missQueue->markInService(pkt);
+ //Temp Hack for UPGRADES
+ if (pkt->cmd == Packet::UpgradeReq) {
+ handleResponse(pkt);
+ }
+ } else if (pkt && !pkt->req->isUncacheable()) {
+ missQueue->restoreOrigCmd(pkt);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::handleResponse(Packet * &pkt)
+{
+ BlkType *blk = NULL;
+ if (pkt->senderState) {
+// MemDebug::cacheResponse(pkt);
+ DPRINTF(Cache, "Handling reponse to %x, blk addr: %x\n",pkt->getAddr(),
+ pkt->getAddr() & (((ULL(1))<<48)-1));
+
+ if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
+ blk = tags->findBlock(pkt);
+ CacheBlk::State old_state = (blk) ? blk->status : 0;
+ PacketList writebacks;
+ blk = tags->handleFill(blk, (MSHR*)pkt->senderState,
+ coherence->getNewState(pkt,old_state),
+ writebacks);
+ while (!writebacks.empty()) {
+ missQueue->doWriteback(writebacks.front());
+ }
+ }
+ missQueue->handleResponse(pkt, curTick + hitLatency);
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::pseudoFill(Addr addr)
+{
+ // Need to temporarily move this blk into MSHRs
+ MSHR *mshr = missQueue->allocateTargetList(addr);
+ int lat;
+ PacketList dummy;
+ // Read the data into the mshr
+ BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
+ assert(dummy.empty());
+ assert(mshr->pkt->flags & SATISFIED);
+ // can overload order since it isn't used on non pending blocks
+ mshr->order = blk->status;
+ // temporarily remove the block from the cache.
+ tags->invalidateBlk(addr);
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::pseudoFill(MSHR *mshr)
+{
+ // Need to temporarily move this blk into MSHRs
+ assert(mshr->pkt->cmd == Packet::ReadReq);
+ int lat;
+ PacketList dummy;
+ // Read the data into the mshr
+ BlkType *blk = tags->handleAccess(mshr->pkt, lat, dummy, false);
+ assert(dummy.empty());
+ assert(mshr->pkt->flags & SATISFIED);
+ // can overload order since it isn't used on non pending blocks
+ mshr->order = blk->status;
+ // temporarily remove the block from the cache.
+ tags->invalidateBlk(mshr->pkt->getAddr());
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+Packet *
+Cache<TagStore,Buffering,Coherence>::getCoherencePacket()
+{
+ return coherence->getPacket();
+}
+
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::snoop(Packet * &pkt)
+{
+
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ BlkType *blk = tags->findBlock(pkt);
+ MSHR *mshr = missQueue->findMSHR(blk_addr);
+ if (isTopLevel() && coherence->hasProtocol()) { //@todo Move this into handle bus req
+ //If we find an mshr, and it is in service, we need to NACK or invalidate
+ if (mshr) {
+ if (mshr->inService) {
+ if ((mshr->pkt->isInvalidate() || !mshr->pkt->isCacheFill())
+ && (pkt->cmd != Packet::InvalidateReq && pkt->cmd != Packet::WriteInvalidateReq)) {
+ //If the outstanding request was an invalidate (upgrade,readex,..)
+ //Then we need to ACK the request until we get the data
+ //Also NACK if the outstanding request is not a cachefill (writeback)
+ pkt->flags |= NACKED_LINE;
+ return;
+ }
+ else {
+ //The supplier will be someone else, because we are waiting for
+ //the data. This should cause this cache to be forced to go to
+ //the shared state, not the exclusive even though the shared line
+ //won't be asserted. But for now we will just invlidate ourselves
+ //and allow the other cache to go into the exclusive state.
+ //@todo Make it so a read to a pending read doesn't invalidate.
+ //@todo Make it so that a read to a pending read can't be exclusive now.
+
+ //Set the address so find match works
+ invalidatePkt->addrOverride(pkt->getAddr());
+
+ //Append the invalidate on
+ missQueue->addTarget(mshr,invalidatePkt);
+ DPRINTF(Cache, "Appending Invalidate to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
+ return;
+ }
+ }
+ }
+ //We also need to check the writeback buffers and handle those
+ std::vector<MSHR *> writebacks;
+ if (missQueue->findWrites(blk_addr, writebacks)) {
+ DPRINTF(Cache, "Snoop hit in writeback to blk_addr: %x\n", pkt->getAddr() & (((ULL(1))<<48)-1));
+
+ //Look through writebacks for any non-uncachable writes, use that
+ for (int i=0; i<writebacks.size(); i++) {
+ mshr = writebacks[i];
+
+ if (!mshr->pkt->req->isUncacheable()) {
+ if (pkt->isRead()) {
+ //Only Upgrades don't get here
+ //Supply the data
+ pkt->flags |= SATISFIED;
+
+ //If we are in an exclusive protocol, make it ask again
+ //to get write permissions (upgrade), signal shared
+ pkt->flags |= SHARED_LINE;
+
+ assert(pkt->isRead());
+ Addr offset = pkt->getAddr() & ~(blkSize - 1);
+ assert(offset < blkSize);
+ assert(pkt->getSize() <= blkSize);
+ assert(offset + pkt->getSize() <=blkSize);
+ memcpy(pkt->getPtr<uint8_t>(), mshr->pkt->getPtr<uint8_t>() + offset, pkt->getSize());
+
+ respondToSnoop(pkt);
+ }
+
+ if (pkt->isInvalidate()) {
+ //This must be an upgrade or other cache will take ownership
+ missQueue->markInService(mshr->pkt);
+ }
+ return;
+ }
+ }
+ }
+ }
+ CacheBlk::State new_state;
+ bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
+ if (satisfy) {
+ tags->handleSnoop(blk, new_state, pkt);
+ respondToSnoop(pkt);
+ return;
+ }
+ tags->handleSnoop(blk, new_state);
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::snoopResponse(Packet * &pkt)
+{
+ //Need to handle the response, if NACKED
+ if (pkt->flags & NACKED_LINE) {
+ //Need to mark it as not in service, and retry for bus
+ assert(0); //Yeah, we saw a NACK come through
+
+ //For now this should never get called, we return false when we see a NACK
+ //instead, by doing this we allow the bus_blocked mechanism to handle the retry
+ //For now it retrys in just 2 cycles, need to figure out how to change that
+ //Eventually we will want to also have success come in as a parameter
+ //Need to make sure that we handle the functionality that happens on successufl
+ //return of the sendAddr function
+ }
+}
+
+template<class TagStore, class Buffering, class Coherence>
+void
+Cache<TagStore,Buffering,Coherence>::invalidateBlk(Addr addr)
+{
+ tags->invalidateBlk(addr);
+}
+
+
+/**
+ * @todo Fix to not assume write allocate
+ */
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::probe(Packet * &pkt, bool update)
+{
+// MemDebug::cacheProbe(pkt);
+ if (!pkt->req->isUncacheable()) {
+ if (pkt->isInvalidate() && !pkt->isRead()
+ && !pkt->isWrite()) {
+ //Upgrade or Invalidate, satisfy it, don't forward
+ DPRINTF(Cache, "%s %x ? blk_addr: %x\n", pkt->cmdString(),
+ pkt->getAddr() & (((ULL(1))<<48)-1),
+ pkt->getAddr() & ~((Addr)blkSize - 1));
+ pkt->flags |= SATISFIED;
+ return 0;
+ }
+ }
+
+ PacketList writebacks;
+ int lat;
+ BlkType *blk = tags->handleAccess(pkt, lat, writebacks, update);
+
+ if (!blk) {
+ // Need to check for outstanding misses and writes
+ Addr blk_addr = pkt->getAddr() & ~(blkSize - 1);
+
+ // There can only be one matching outstanding miss.
+ MSHR* mshr = missQueue->findMSHR(blk_addr);
+
+ // There can be many matching outstanding writes.
+ std::vector<MSHR*> writes;
+ missQueue->findWrites(blk_addr, writes);
+
+ if (!update) {
+ memSidePort->sendFunctional(pkt);
+ // Check for data in MSHR and writebuffer.
+ if (mshr) {
+ warn("Found outstanding miss on an non-update probe");
+ MSHR::TargetList *targets = mshr->getTargetList();
+ MSHR::TargetList::iterator i = targets->begin();
+ MSHR::TargetList::iterator end = targets->end();
+ for (; i != end; ++i) {
+ Packet * target = *i;
+ // If the target contains data, and it overlaps the
+ // probed request, need to update data
+ if (target->isWrite() && target->intersect(pkt)) {
+ uint8_t* pkt_data;
+ uint8_t* write_data;
+ int data_size;
+ if (target->getAddr() < pkt->getAddr()) {
+ int offset = pkt->getAddr() - target->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>();
+ write_data = target->getPtr<uint8_t>() + offset;
+ data_size = target->getSize() - offset;
+ assert(data_size > 0);
+ if (data_size > pkt->getSize())
+ data_size = pkt->getSize();
+ } else {
+ int offset = target->getAddr() - pkt->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>() + offset;
+ write_data = target->getPtr<uint8_t>();
+ data_size = pkt->getSize() - offset;
+ assert(data_size > pkt->getSize());
+ if (data_size > target->getSize())
+ data_size = target->getSize();
+ }
+
+ if (pkt->isWrite()) {
+ memcpy(pkt_data, write_data, data_size);
+ } else {
+ memcpy(write_data, pkt_data, data_size);
+ }
+ }
+ }
+ }
+ for (int i = 0; i < writes.size(); ++i) {
+ Packet * write = writes[i]->pkt;
+ if (write->intersect(pkt)) {
+ warn("Found outstanding write on an non-update probe");
+ uint8_t* pkt_data;
+ uint8_t* write_data;
+ int data_size;
+ if (write->getAddr() < pkt->getAddr()) {
+ int offset = pkt->getAddr() - write->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>();
+ write_data = write->getPtr<uint8_t>() + offset;
+ data_size = write->getSize() - offset;
+ assert(data_size > 0);
+ if (data_size > pkt->getSize())
+ data_size = pkt->getSize();
+ } else {
+ int offset = write->getAddr() - pkt->getAddr();
+ pkt_data = pkt->getPtr<uint8_t>() + offset;
+ write_data = write->getPtr<uint8_t>();
+ data_size = pkt->getSize() - offset;
+ assert(data_size > pkt->getSize());
+ if (data_size > write->getSize())
+ data_size = write->getSize();
+ }
+
+ if (pkt->isWrite()) {
+ memcpy(pkt_data, write_data, data_size);
+ } else {
+ memcpy(write_data, pkt_data, data_size);
+ }
+
+ }
+ }
+ return 0;
+ } else {
+ // update the cache state and statistics
+ if (mshr || !writes.empty()){
+ // Can't handle it, return pktuest unsatisfied.
+ return 0;
+ }
+ if (!pkt->req->isUncacheable()) {
+ // Fetch the cache block to fill
+ BlkType *blk = tags->findBlock(pkt);
+ Packet::Command temp_cmd = coherence->getBusCmd(pkt->cmd,
+ (blk)? blk->status : 0);
+
+ Packet * busPkt = new Packet(pkt->req,temp_cmd, -1, blkSize);
+
+ busPkt->allocate();
+
+ busPkt->time = curTick;
+
+ lat = memSidePort->sendAtomic(busPkt);
+
+/* if (!(busPkt->flags & SATISFIED)) {
+ // blocked at a higher level, just return
+ return 0;
+ }
+
+*/ misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+
+ CacheBlk::State old_state = (blk) ? blk->status : 0;
+ tags->handleFill(blk, busPkt,
+ coherence->getNewState(busPkt, old_state),
+ writebacks, pkt);
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ memSidePort->sendAtomic(writebacks.front());
+ writebacks.pop_front();
+ }
+ return lat + hitLatency;
+ } else {
+ return memSidePort->sendAtomic(pkt);
+ }
+ }
+ } else {
+ // There was a cache hit.
+ // Handle writebacks if needed
+ while (!writebacks.empty()){
+ memSidePort->sendAtomic(writebacks.front());
+ writebacks.pop_front();
+ }
+
+ if (update) {
+ hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ } else if (pkt->isWrite()) {
+ // Still need to change data in all locations.
+ return memSidePort->sendAtomic(pkt);
+ }
+ return curTick + lat;
+ }
+ fatal("Probe not handled.\n");
+ return 0;
+}
+
+template<class TagStore, class Buffering, class Coherence>
+Tick
+Cache<TagStore,Buffering,Coherence>::snoopProbe(PacketPtr &pkt, bool update)
+{
+ Addr blk_addr = pkt->getAddr() & ~(Addr(blkSize-1));
+ BlkType *blk = tags->findBlock(pkt);
+ MSHR *mshr = missQueue->findMSHR(blk_addr);
+ CacheBlk::State new_state = 0;
+ bool satisfy = coherence->handleBusRequest(pkt,blk,mshr, new_state);
+ if (satisfy) {
+ tags->handleSnoop(blk, new_state, pkt);
+ return hitLatency;
+ }
+ tags->handleSnoop(blk, new_state);
+ return 0;
+}
+
diff --git a/src/mem/cache/coherence/coherence_protocol.cc b/src/mem/cache/coherence/coherence_protocol.cc
new file mode 100644
index 000000000..bcf3ce9c5
--- /dev/null
+++ b/src/mem/cache/coherence/coherence_protocol.cc
@@ -0,0 +1,567 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Definitions of CoherenceProtocol.
+ */
+
+#include <string>
+
+#include "base/misc.hh"
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/cache.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+#include "sim/builder.hh"
+
+using namespace std;
+
+
+CoherenceProtocol::StateTransition::StateTransition()
+ : busCmd(Packet::InvalidCmd), newState(-1), snoopFunc(invalidTransition)
+{
+}
+
+
+void
+CoherenceProtocol::regStats()
+{
+ // Even though we count all the possible transitions in the
+ // requestCount and snoopCount arrays, most of these are invalid,
+ // so we just select the interesting ones to print here.
+
+ requestCount[Invalid][Packet::ReadReq]
+ .name(name() + ".read_invalid")
+ .desc("read misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::WriteReq]
+ .name(name() +".write_invalid")
+ .desc("write misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::SoftPFReq]
+ .name(name() +".swpf_invalid")
+ .desc("soft prefetch misses to invalid blocks")
+ ;
+
+ requestCount[Invalid][Packet::HardPFReq]
+ .name(name() +".hwpf_invalid")
+ .desc("hard prefetch misses to invalid blocks")
+ ;
+
+ requestCount[Shared][Packet::WriteReq]
+ .name(name() + ".write_shared")
+ .desc("write misses to shared blocks")
+ ;
+
+ requestCount[Owned][Packet::WriteReq]
+ .name(name() + ".write_owned")
+ .desc("write misses to owned blocks")
+ ;
+
+ snoopCount[Shared][Packet::ReadReq]
+ .name(name() + ".snoop_read_shared")
+ .desc("read snoops on shared blocks")
+ ;
+
+ snoopCount[Shared][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_shared")
+ .desc("readEx snoops on shared blocks")
+ ;
+
+ snoopCount[Shared][Packet::UpgradeReq]
+ .name(name() + ".snoop_upgrade_shared")
+ .desc("upgradee snoops on shared blocks")
+ ;
+
+ snoopCount[Modified][Packet::ReadReq]
+ .name(name() + ".snoop_read_modified")
+ .desc("read snoops on modified blocks")
+ ;
+
+ snoopCount[Modified][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_modified")
+ .desc("readEx snoops on modified blocks")
+ ;
+
+ snoopCount[Owned][Packet::ReadReq]
+ .name(name() + ".snoop_read_owned")
+ .desc("read snoops on owned blocks")
+ ;
+
+ snoopCount[Owned][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_owned")
+ .desc("readEx snoops on owned blocks")
+ ;
+
+ snoopCount[Owned][Packet::UpgradeReq]
+ .name(name() + ".snoop_upgrade_owned")
+ .desc("upgrade snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::ReadReq]
+ .name(name() + ".snoop_read_exclusive")
+ .desc("read snoops on exclusive blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::ReadExReq]
+ .name(name() + ".snoop_readex_exclusive")
+ .desc("readEx snoops on exclusive blocks")
+ ;
+
+ snoopCount[Shared][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_shared")
+ .desc("Invalidate snoops on shared blocks")
+ ;
+
+ snoopCount[Owned][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_owned")
+ .desc("Invalidate snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_exclusive")
+ .desc("Invalidate snoops on exclusive blocks")
+ ;
+
+ snoopCount[Modified][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_modified")
+ .desc("Invalidate snoops on modified blocks")
+ ;
+
+ snoopCount[Invalid][Packet::InvalidateReq]
+ .name(name() + ".snoop_inv_invalid")
+ .desc("Invalidate snoops on invalid blocks")
+ ;
+
+ snoopCount[Shared][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_shared")
+ .desc("WriteInvalidate snoops on shared blocks")
+ ;
+
+ snoopCount[Owned][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_owned")
+ .desc("WriteInvalidate snoops on owned blocks")
+ ;
+
+ snoopCount[Exclusive][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_exclusive")
+ .desc("WriteInvalidate snoops on exclusive blocks")
+ ;
+
+ snoopCount[Modified][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_modified")
+ .desc("WriteInvalidate snoops on modified blocks")
+ ;
+
+ snoopCount[Invalid][Packet::WriteInvalidateReq]
+ .name(name() + ".snoop_writeinv_invalid")
+ .desc("WriteInvalidate snoops on invalid blocks")
+ ;
+}
+
+
+bool
+CoherenceProtocol::invalidateTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ // invalidate the block
+ new_state = (blk->status & ~stateMask) | Invalid;
+ return false;
+}
+
+
+bool
+CoherenceProtocol::supplyTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state
+ )
+{
+ return true;
+}
+
+
+bool
+CoherenceProtocol::supplyAndGotoSharedTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Shared;
+ pkt->flags |= SHARED_LINE;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+
+bool
+CoherenceProtocol::supplyAndGotoOwnedTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Owned;
+ pkt->flags |= SHARED_LINE;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+
+bool
+CoherenceProtocol::supplyAndInvalidateTrans(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Invalid;
+ return supplyTrans(cache, pkt, blk, mshr, new_state);
+}
+
+bool
+CoherenceProtocol::assertShared(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ new_state = (blk->status & ~stateMask) | Shared;
+ pkt->flags |= SHARED_LINE;
+ return false;
+}
+
+CoherenceProtocol::CoherenceProtocol(const string &name,
+ const string &protocol,
+ const bool doUpgrades)
+ : SimObject(name)
+{
+ if ((protocol == "mosi" || protocol == "moesi") && !doUpgrades) {
+ cerr << "CoherenceProtocol: ownership protocols require upgrade transactions"
+ << "(write miss on owned block generates ReadExcl, which will clobber dirty block)"
+ << endl;
+ fatal("");
+ }
+
+ Packet::Command writeToSharedCmd = doUpgrades ? Packet::UpgradeReq : Packet::ReadExReq;
+ Packet::Command writeToSharedResp = doUpgrades ? Packet::UpgradeResp : Packet::ReadExResp;
+
+//@todo add in hardware prefetch to this list
+ if (protocol == "msi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Shared);
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoSharedTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+
+ if (doUpgrades) {
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ }
+ }
+
+ else if(protocol == "mesi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Exclusive);
+ //It will move into shared if the shared line is asserted in the
+ //getNewState function
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Exclusive][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoSharedTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+
+ if (doUpgrades) {
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ }
+ }
+
+ else if(protocol == "mosi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ transitionTable[Owned][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Shared);
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+ transitionTable[Owned][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ //Tansitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ }
+
+ else if(protocol == "moesi") {
+ // incoming requests: specify outgoing bus request
+ transitionTable[Invalid][Packet::ReadReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::WriteReq].onRequest(Packet::ReadExReq);
+ transitionTable[Shared][Packet::WriteReq].onRequest(writeToSharedCmd);
+ transitionTable[Owned][Packet::WriteReq].onRequest(writeToSharedCmd);
+ //Prefetching causes a read
+ transitionTable[Invalid][Packet::SoftPFReq].onRequest(Packet::ReadReq);
+ transitionTable[Invalid][Packet::HardPFReq].onRequest(Packet::ReadReq);
+
+ // on response to given request: specify new state
+ transitionTable[Invalid][Packet::ReadResp].onResponse(Exclusive);
+ //It will move into shared if the shared line is asserted in the
+ //getNewState function
+ transitionTable[Invalid][Packet::ReadExResp].onResponse(Modified);
+ transitionTable[Shared][writeToSharedResp].onResponse(Modified);
+ transitionTable[Owned][writeToSharedResp].onResponse(Modified);
+
+ // bus snoop transition functions
+ transitionTable[Invalid][Packet::ReadReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::ReadExReq].onSnoop(nullTransition);
+ transitionTable[Invalid][Packet::UpgradeReq].onSnoop(nullTransition);
+ transitionTable[Shared][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Shared][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::ReadReq].onSnoop(assertShared);
+ transitionTable[Exclusive][Packet::ReadExReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Modified][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::ReadReq].onSnoop(supplyAndGotoOwnedTrans);
+ transitionTable[Owned][Packet::ReadExReq].onSnoop(supplyAndInvalidateTrans);
+ transitionTable[Owned][Packet::UpgradeReq].onSnoop(invalidateTrans);
+ //Transitions on seeing a DMA (writeInv(samelevel) or DMAInv)
+ transitionTable[Invalid][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::InvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Invalid][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Shared][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Exclusive][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Modified][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ transitionTable[Owned][Packet::WriteInvalidateReq].onSnoop(invalidateTrans);
+ }
+
+ else {
+ cerr << "CoherenceProtocol: unrecognized protocol " << protocol
+ << endl;
+ fatal("");
+ }
+}
+
+
+Packet::Command
+CoherenceProtocol::getBusCmd(Packet::Command cmdIn, CacheBlk::State state,
+ MSHR *mshr)
+{
+ state &= stateMask;
+ int cmd_idx = (int) cmdIn;
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+ Packet::Command cmdOut = transitionTable[state][cmd_idx].busCmd;
+
+ assert(cmdOut != Packet::InvalidCmd);
+
+ ++requestCount[state][cmd_idx];
+
+ return cmdOut;
+}
+
+
+CacheBlk::State
+CoherenceProtocol::getNewState(Packet * &pkt, CacheBlk::State oldState)
+{
+ CacheBlk::State state = oldState & stateMask;
+ int cmd_idx = pkt->cmdToIndex();
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+ CacheBlk::State newState = transitionTable[state][cmd_idx].newState;
+
+ //Check if it's exclusive and the shared line was asserted,
+ //then goto shared instead
+ if (newState == Exclusive && (pkt->flags & SHARED_LINE)) {
+ newState = Shared;
+ }
+
+ assert(newState != -1);
+
+ //Make sure not to loose any other state information
+ newState = (oldState & ~stateMask) | newState;
+ return newState;
+}
+
+
+bool
+CoherenceProtocol::handleBusRequest(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk,
+ MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ if (blk == NULL) {
+ // nothing to do if we don't have a block
+ return false;
+ }
+
+ CacheBlk::State state = blk->status & stateMask;
+ int cmd_idx = pkt->cmdToIndex();
+
+ assert(0 <= state && state <= stateMax);
+ assert(0 <= cmd_idx && cmd_idx < NUM_MEM_CMDS);
+
+// assert(mshr == NULL); // can't currently handle outstanding requests
+ //Check first if MSHR, and also insure, if there is one, that it is not in service
+ assert(!mshr || mshr->inService == 0);
+ ++snoopCount[state][cmd_idx];
+
+ bool ret = transitionTable[state][cmd_idx].snoopFunc(cache, pkt, blk, mshr,
+ new_state);
+
+
+
+ return ret;
+}
+
+bool
+CoherenceProtocol::nullTransition(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ // do nothing
+ if (blk)
+ new_state = blk->status;
+ return false;
+}
+
+
+bool
+CoherenceProtocol::invalidTransition(BaseCache *cache, Packet * &pkt,
+ CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State & new_state)
+{
+ panic("Invalid transition");
+ return false;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+ Param<string> protocol;
+ Param<bool> do_upgrades;
+
+END_DECLARE_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+ INIT_PARAM(protocol, "name of coherence protocol"),
+ INIT_PARAM_DFLT(do_upgrades, "use upgrade transactions?", true)
+
+END_INIT_SIM_OBJECT_PARAMS(CoherenceProtocol)
+
+
+CREATE_SIM_OBJECT(CoherenceProtocol)
+{
+ return new CoherenceProtocol(getInstanceName(), protocol,
+ do_upgrades);
+}
+
+REGISTER_SIM_OBJECT("CoherenceProtocol", CoherenceProtocol)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/coherence/coherence_protocol.hh b/src/mem/cache/coherence/coherence_protocol.hh
new file mode 100644
index 000000000..b5d7d80aa
--- /dev/null
+++ b/src/mem/cache/coherence/coherence_protocol.hh
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Declaration of CoherenceProcotol a basic coherence policy.
+ */
+#ifndef __COHERENCE_PROTOCOL_HH__
+#define __COHERENCE_PROTOCOL_HH__
+
+#include <string>
+
+#include "sim/sim_object.hh"
+#include "mem/packet.hh"
+#include "mem/cache/cache_blk.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class MSHR;
+
+/**
+ * A simple coherence policy for the memory hierarchy. Currently implements
+ * MSI, MESI, and MOESI protocols.
+ */
+class CoherenceProtocol : public SimObject
+{
+ public:
+ /**
+ * Contruct and initialize this policy.
+ * @param name The name of this policy.
+ * @param protocol The string representation of the protocol to use.
+ * @param doUpgrades True if bus upgrades should be used.
+ */
+ CoherenceProtocol(const std::string &name, const std::string &protocol,
+ const bool doUpgrades);
+
+ /**
+ * Destructor.
+ */
+ virtual ~CoherenceProtocol() {};
+
+ /**
+ * Register statistics
+ */
+ virtual void regStats();
+
+ /**
+ * Get the proper bus command for the given command and status.
+ * @param cmd The request's command.
+ * @param status The current state of the cache block.
+ * @param mshr The MSHR matching the request.
+ * @return The proper bus command, as determined by the protocol.
+ */
+ Packet::Command getBusCmd(Packet::Command cmd, CacheBlk::State status,
+ MSHR *mshr = NULL);
+
+ /**
+ * Return the proper state given the current state and the bus response.
+ * @param pkt The bus response.
+ * @param oldState The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt,
+ CacheBlk::State oldState);
+
+ /**
+ * Handle snooped bus requests.
+ * @param cache The cache that snooped the request.
+ * @param pkt The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state The new coherence state of the block.
+ * @return True if the request should be satisfied locally.
+ */
+ bool handleBusRequest(BaseCache *cache, Packet * &pkt, CacheBlk *blk,
+ MSHR *mshr, CacheBlk::State &new_state);
+
+ protected:
+ /** Snoop function type. */
+ typedef bool (*SnoopFuncType)(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ //
+ // Standard snoop transition functions
+ //
+
+ /**
+ * Do nothing transition.
+ */
+ static bool nullTransition(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalid transition, basically panic.
+ */
+ static bool invalidTransition(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalidate block, move to Invalid state.
+ */
+ static bool invalidateTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data, no state transition.
+ */
+ static bool supplyTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data and go to Shared state.
+ */
+ static bool supplyAndGotoSharedTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Supply data and go to Owned state.
+ */
+ static bool supplyAndGotoOwnedTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Invalidate block, supply data, and go to Invalid state.
+ */
+ static bool supplyAndInvalidateTrans(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Assert the shared line for a block that is shared/exclusive.
+ */
+ static bool assertShared(BaseCache *, Packet *&, CacheBlk *,
+ MSHR *, CacheBlk::State&);
+
+ /**
+ * Definition of protocol state transitions.
+ */
+ class StateTransition
+ {
+ friend class CoherenceProtocol;
+
+ /** The bus command of this transition. */
+ Packet::Command busCmd;
+ /** The state to transition to. */
+ int newState;
+ /** The snoop function for this transition. */
+ SnoopFuncType snoopFunc;
+
+ /**
+ * Constructor, defaults to invalid transition.
+ */
+ StateTransition();
+
+ /**
+ * Initialize bus command.
+ * @param cmd The bus command to use.
+ */
+ void onRequest(Packet::Command cmd)
+ {
+ busCmd = cmd;
+ }
+
+ /**
+ * Set the transition state.
+ * @param s The new state.
+ */
+ void onResponse(CacheBlk::State s)
+ {
+ newState = s;
+ }
+
+ /**
+ * Initialize the snoop function.
+ * @param f The new snoop function.
+ */
+ void onSnoop(SnoopFuncType f)
+ {
+ snoopFunc = f;
+ }
+ };
+
+ friend class CoherenceProtocol::StateTransition;
+
+ /** Mask to select status bits relevant to coherence protocol. */
+ const static CacheBlk::State
+ stateMask = BlkValid | BlkWritable | BlkDirty;
+
+ /** The Modified (M) state. */
+ const static CacheBlk::State
+ Modified = BlkValid | BlkWritable | BlkDirty;
+ /** The Owned (O) state. */
+ const static CacheBlk::State
+ Owned = BlkValid | BlkDirty;
+ /** The Exclusive (E) state. */
+ const static CacheBlk::State
+ Exclusive = BlkValid | BlkWritable;
+ /** The Shared (S) state. */
+ const static CacheBlk::State
+ Shared = BlkValid;
+ /** The Invalid (I) state. */
+ const static CacheBlk::State
+ Invalid = 0;
+
+ /**
+ * Maximum state encoding value (used to size transition lookup
+ * table). Could be more than number of states, depends on
+ * encoding of status bits.
+ */
+ const static int stateMax = stateMask;
+
+ /**
+ * The table of all possible transitions, organized by starting state and
+ * request command.
+ */
+ StateTransition transitionTable[stateMax+1][NUM_MEM_CMDS];
+
+ /**
+ * @addtogroup CoherenceStatistics
+ * @{
+ */
+ /**
+ * State accesses from parent cache.
+ */
+ Stats::Scalar<> requestCount[stateMax+1][NUM_MEM_CMDS];
+ /**
+ * State accesses from snooped requests.
+ */
+ Stats::Scalar<> snoopCount[stateMax+1][NUM_MEM_CMDS];
+ /**
+ * @}
+ */
+};
+
+#endif // __COHERENCE_PROTOCOL_HH__
diff --git a/src/mem/cache/coherence/simple_coherence.hh b/src/mem/cache/coherence/simple_coherence.hh
new file mode 100644
index 000000000..71d8f36f4
--- /dev/null
+++ b/src/mem/cache/coherence/simple_coherence.hh
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Declaration of a simple coherence policy.
+ */
+
+#ifndef __SIMPLE_COHERENCE_HH__
+#define __SIMPLE_COHERENCE_HH__
+
+#include <string>
+
+#include "mem/packet.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "mem/cache/coherence/coherence_protocol.hh"
+
+class BaseCache;
+
+/**
+ * A simple MP coherence policy. This policy assumes an atomic bus and only one
+ * level of cache.
+ */
+class SimpleCoherence
+{
+ protected:
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+ /** Pointer to the coherence protocol. */
+ CoherenceProtocol *protocol;
+
+ public:
+ /**
+ * Construct and initialize this coherence policy.
+ * @param _protocol The coherence protocol to use.
+ */
+ SimpleCoherence(CoherenceProtocol *_protocol)
+ : protocol(_protocol)
+ {
+ }
+
+ /**
+ * Set the pointer to the parent cache.
+ * @param _cache The parent cache.
+ */
+ void setCache(BaseCache *_cache)
+ {
+ cache = _cache;
+ }
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to stat descriptions.
+ */
+ void regStats(const std::string &name)
+ {
+ }
+
+ /**
+ * This policy does not forward invalidates, return NULL.
+ * @return NULL.
+ */
+ Packet * getPacket()
+ {
+ return NULL;
+ }
+
+ /**
+ * Return the proper state given the current state and the bus response.
+ * @param pkt The bus response.
+ * @param current The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt, CacheBlk::State current)
+ {
+ return protocol->getNewState(pkt, current);
+ }
+
+ /**
+ * Handle snooped bus requests.
+ * @param pkt The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state Return the new state for the block.
+ */
+ bool handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state)
+ {
+// assert(mshr == NULL);
+//Got rid of, there could be an MSHR, but it can't be in service
+ if (blk != NULL)
+ {
+ if (pkt->cmd != Packet::Writeback) {
+ return protocol->handleBusRequest(cache, pkt, blk, mshr,
+ new_state);
+ }
+ else { //It is a writeback, must be ownership protocol, just keep state
+ new_state = blk->status;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Get the proper bus command for the given command and status.
+ * @param cmd The request's command.
+ * @param state The current state of the cache block.
+ * @return The proper bus command, as determined by the protocol.
+ */
+ Packet::Command getBusCmd(Packet::Command &cmd, CacheBlk::State state)
+ {
+ if (cmd == Packet::Writeback) return Packet::Writeback;
+ return protocol->getBusCmd(cmd, state);
+ }
+
+ /**
+ * Return true if this coherence policy can handle fast cache writes.
+ */
+ bool allowFastWrites() { return false; }
+
+ bool hasProtocol() { return true; }
+};
+
+#endif //__SIMPLE_COHERENCE_HH__
+
+
+
+
+
+
+
+
diff --git a/src/mem/cache/coherence/uni_coherence.cc b/src/mem/cache/coherence/uni_coherence.cc
new file mode 100644
index 000000000..5ab706269
--- /dev/null
+++ b/src/mem/cache/coherence/uni_coherence.cc
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+#include "mem/cache/coherence/uni_coherence.hh"
+#include "mem/cache/base_cache.hh"
+
+#include "base/trace.hh"
+
+using namespace std;
+
+UniCoherence::UniCoherence()
+ : cshrs(50)
+{
+}
+
+Packet *
+UniCoherence::getPacket()
+{
+ bool unblock = cshrs.isFull();
+ Packet* pkt = cshrs.getReq();
+ cshrs.markInService((MSHR*)pkt->senderState);
+ if (!cshrs.havePending()) {
+ cache->clearSlaveRequest(Request_Coherence);
+ }
+ if (unblock) {
+ //since CSHRs are always used as buffers, should always get rid of one
+ assert(!cshrs.isFull());
+ cache->clearBlocked(Blocked_Coherence);
+ }
+ return pkt;
+}
+
+/**
+ * @todo add support for returning slave requests, not doing them here.
+ */
+bool
+UniCoherence::handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state)
+{
+ new_state = 0;
+ if (pkt->isInvalidate()) {
+ DPRINTF(Cache, "snoop inval on blk %x (blk ptr %x)\n",
+ pkt->getAddr(), blk);
+ if (!cache->isTopLevel()) {
+ // Forward to other caches
+ Packet * tmp = new Packet(pkt->req, Packet::InvalidateReq, -1);
+ cshrs.allocate(tmp);
+ cache->setSlaveRequest(Request_Coherence, curTick);
+ if (cshrs.isFull()) {
+ cache->setBlockedForSnoop(Blocked_Coherence);
+ }
+ }
+ } else {
+ if (blk) {
+ new_state = blk->status;
+ }
+ }
+ return false;
+}
diff --git a/src/mem/cache/coherence/uni_coherence.hh b/src/mem/cache/coherence/uni_coherence.hh
new file mode 100644
index 000000000..27b6c7fb5
--- /dev/null
+++ b/src/mem/cache/coherence/uni_coherence.hh
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+#ifndef __UNI_COHERENCE_HH__
+#define __UNI_COHERENCE_HH__
+
+#include "base/trace.hh"
+#include "base/misc.hh"
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "mem/packet.hh"
+
+class BaseCache;
+
+class UniCoherence
+{
+ protected:
+ /** Buffers to hold forwarded invalidates. */
+ MSHRQueue cshrs;
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+
+ public:
+ /**
+ * Construct and initialize this coherence policy.
+ */
+ UniCoherence();
+
+ /**
+ * Set the pointer to the parent cache.
+ * @param _cache The parent cache.
+ */
+ void setCache(BaseCache *_cache)
+ {
+ cache = _cache;
+ }
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to stat descriptions.
+ */
+ void regStats(const std::string &name)
+ {
+ }
+
+ /**
+ * Return Read.
+ * @param cmd The request's command.
+ * @param state The current state of the cache block.
+ * @return The proper bus command, as determined by the protocol.
+ * @todo Make changes so writebacks don't get here.
+ */
+ Packet::Command getBusCmd(Packet::Command &cmd, CacheBlk::State state)
+ {
+ if (cmd == Packet::HardPFReq && state)
+ warn("Trying to issue a prefetch to a block we already have\n");
+ if (cmd == Packet::Writeback)
+ return Packet::Writeback;
+ return Packet::ReadReq;
+ }
+
+ /**
+ * Just return readable and writeable.
+ * @param pkt The bus response.
+ * @param current The current block state.
+ * @return The new state.
+ */
+ CacheBlk::State getNewState(Packet * &pkt, CacheBlk::State current)
+ {
+ if (pkt->senderState) //Blocking Buffers don't get mshrs
+ {
+ if (((MSHR *)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "Marking a hardware prefetch as such in the state\n");
+ return BlkHWPrefetched | BlkValid | BlkWritable;
+ }
+ else {
+ return BlkValid | BlkWritable;
+ }
+ }
+ //@todo What about prefetching with blocking buffers
+ else
+ return BlkValid | BlkWritable;
+ }
+ /**
+ * Return outstanding invalidate to forward.
+ * @return The next invalidate to forward to lower levels of cache.
+ */
+ Packet * getPacket();
+
+ /**
+ * Handle snooped bus requests.
+ * @param pkt The snooped bus request.
+ * @param blk The cache block corresponding to the request, if any.
+ * @param mshr The MSHR corresponding to the request, if any.
+ * @param new_state The new coherence state of the block.
+ * @return True if the request should be satisfied locally.
+ */
+ bool handleBusRequest(Packet * &pkt, CacheBlk *blk, MSHR *mshr,
+ CacheBlk::State &new_state);
+
+ /**
+ * Return true if this coherence policy can handle fast cache writes.
+ */
+ bool allowFastWrites() { return true; }
+
+ bool hasProtocol() { return false; }
+};
+
+#endif //__UNI_COHERENCE_HH__
diff --git a/src/mem/cache/miss/blocking_buffer.cc b/src/mem/cache/miss/blocking_buffer.cc
new file mode 100644
index 000000000..67fc7ae56
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.cc
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of a simple buffer for a blocking cache.
+ */
+
+#include "cpu/smt.hh" //for maxThreadsPerCPU
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+#include "sim/eventq.hh" // for Event declaration.
+#include "mem/request.hh"
+
+/**
+ * @todo Move writebacks into shared BaseBuffer class.
+ */
+void
+BlockingBuffer::regStats(const std::string &name)
+{
+ using namespace Stats;
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+}
+
+void
+BlockingBuffer::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+BlockingBuffer::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+void
+BlockingBuffer::handleMiss(Packet * &pkt, int blk_size, Tick time)
+{
+ Addr blk_addr = pkt->getAddr() & ~(Addr)(blk_size - 1);
+ if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
+ !pkt->needsResponse())) {
+ if (!pkt->needsResponse()) {
+ wb.allocateAsBuffer(pkt);
+ } else {
+ wb.allocate(pkt->cmd, blk_addr, blk_size, pkt);
+ }
+
+ memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), blk_size);
+
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, time);
+ return;
+ }
+
+ if (!pkt->needsResponse()) {
+ miss.allocateAsBuffer(pkt);
+ } else {
+ miss.allocate(pkt->cmd, blk_addr, blk_size, pkt);
+ }
+ if (!pkt->req->isUncacheable()) {
+ miss.pkt->flags |= CACHE_LINE_FILL;
+ }
+ cache->setBlocked(Blocked_NoMSHRs);
+ cache->setMasterRequest(Request_MSHR, time);
+}
+
+Packet *
+BlockingBuffer::getPacket()
+{
+ if (miss.pkt && !miss.inService) {
+ return miss.pkt;
+ }
+ return wb.pkt;
+}
+
+void
+BlockingBuffer::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ MSHR *mshr = (MSHR*) pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill())
+ pkt->cmdOverride(cmd);
+}
+
+void
+BlockingBuffer::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmdOverride(((MSHR*)(pkt->senderState))->originalCmd);
+}
+
+void
+BlockingBuffer::markInService(Packet * &pkt)
+{
+ if (!pkt->isCacheFill() && pkt->isWrite()) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ assert((MSHR*)pkt->senderState == &wb);
+ cache->clearMasterRequest(Request_WB);
+ if (!pkt->needsResponse()) {
+ assert(wb.getNumTargets() == 0);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ wb.inService = true;
+ }
+ } else {
+ assert((MSHR*)pkt->senderState == &miss);
+ cache->clearMasterRequest(Request_MSHR);
+ if (!pkt->needsResponse()) {
+ assert(miss.getNumTargets() == 0);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ //mark in service
+ miss.inService = true;
+ }
+ }
+}
+
+void
+BlockingBuffer::handleResponse(Packet * &pkt, Tick time)
+{
+ if (pkt->isCacheFill()) {
+ // targets were handled in the cache tags
+ assert((MSHR*)pkt->senderState == &miss);
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ } else {
+ if (((MSHR*)(pkt->senderState))->hasTargets()) {
+ // Should only have 1 target if we had any
+ assert(((MSHR*)(pkt->senderState))->getNumTargets() == 1);
+ Packet * target = ((MSHR*)(pkt->senderState))->getTarget();
+ ((MSHR*)(pkt->senderState))->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), target->getSize());
+ }
+ cache->respond(target, time);
+ assert(!((MSHR*)(pkt->senderState))->hasTargets());
+ }
+
+ if (pkt->isWrite()) {
+ assert(((MSHR*)(pkt->senderState)) == &wb);
+ wb.deallocate();
+ cache->clearBlocked(Blocked_NoWBBuffers);
+ } else {
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ }
+ }
+}
+
+void
+BlockingBuffer::squash(int threadNum)
+{
+ if (miss.threadNum == threadNum) {
+ Packet * target = miss.getTarget();
+ miss.popTarget();
+ assert(target->req->getThreadNum() == threadNum);
+ target = NULL;
+ assert(!miss.hasTargets());
+ miss.ntargets=0;
+ if (!miss.inService) {
+ miss.deallocate();
+ cache->clearBlocked(Blocked_NoMSHRs);
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ }
+}
+
+void
+BlockingBuffer::doWriteback(Addr addr,
+ int size, uint8_t *data, bool compressed)
+{
+ // Generate request
+ Request * req = new Request(addr, size, 0);
+ Packet * pkt = new Packet(req, Packet::Writeback, -1);
+ pkt->allocate();
+ if (data) {
+ memcpy(pkt->getPtr<uint8_t>(), data, size);
+ }
+
+ if (compressed) {
+ pkt->flags |= COMPRESSED;
+ }
+
+ ///All writebacks charged to same thread @todo figure this out
+ writebacks[pkt->req->getThreadNum()]++;
+
+ wb.allocateAsBuffer(pkt);
+ cache->setMasterRequest(Request_WB, curTick);
+ cache->setBlocked(Blocked_NoWBBuffers);
+}
+
+
+
+void
+BlockingBuffer::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->req->getThreadNum()]++;
+
+ wb.allocateAsBuffer(pkt);
+
+ // Since allocate as buffer copies the request,
+ // need to copy data here.
+ memcpy(wb.pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
+
+ cache->setBlocked(Blocked_NoWBBuffers);
+ cache->setMasterRequest(Request_WB, curTick);
+}
diff --git a/src/mem/cache/miss/blocking_buffer.hh b/src/mem/cache/miss/blocking_buffer.hh
new file mode 100644
index 000000000..641d5a798
--- /dev/null
+++ b/src/mem/cache/miss/blocking_buffer.hh
@@ -0,0 +1,256 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a simple buffer for a blocking cache.
+ */
+
+#ifndef __BLOCKING_BUFFER_HH__
+#define __BLOCKING_BUFFER_HH__
+
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+
+/**
+ * Miss and writeback storage for a blocking cache.
+ */
+class BlockingBuffer
+{
+protected:
+ /** Miss storage. */
+ MSHR miss;
+ /** WB storage. */
+ MSHR wb;
+
+ //Params
+
+ /** Allocate on write misses. */
+ const bool writeAllocate;
+
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ BasePrefetcher* prefetcher;
+
+ /** Block size of the parent cache. */
+ int blkSize;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /**
+ * @}
+ */
+
+public:
+ /**
+ * Builds and initializes this buffer.
+ * @param write_allocate If true, treat write misses the same as reads.
+ */
+ BlockingBuffer(bool write_allocate)
+ : writeAllocate(write_allocate)
+ {
+ }
+
+ /**
+ * Register statistics for this object.
+ * @param name The name of the parent cache.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Called by the parent cache to set the back pointer.
+ * @param _cache A pointer to the parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ void setPrefetcher(BasePrefetcher *_prefetcher);
+
+ /**
+ * Handle a cache miss properly. Requests the bus and marks the cache as
+ * blocked.
+ * @param pkt The request that missed in the cache.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ */
+ void handleMiss(Packet * &pkt, int blk_size, Tick time);
+
+ /**
+ * Fetch the block for the given address and buffer the given target.
+ * @param addr The address to fetch.
+ * @param asid The address space of the address.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ * @param target The target for the fetch.
+ */
+ MSHR* fetchBlock(Addr addr, int blk_size, Tick time,
+ Packet * &target)
+ {
+ fatal("Unimplemented");
+ }
+
+ /**
+ * Selects a outstanding pktuest to service.
+ * @return The pktuest to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param pkt The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param pkt The request to reset.
+ */
+ void restoreOrigCmd(Packet * &pkt);
+
+ /**
+ * Marks a pktuest as in service (sent on the bus). This can have side
+ * effect since storage for no response commands is deallocated once they
+ * are successfully sent.
+ * @param pkt The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Frees the resources of the pktuest and unblock the cache.
+ * @param pkt The request that has been satisfied.
+ * @param time The time when the pktuest is satisfied.
+ */
+ void handleResponse(Packet * &pkt, Tick time);
+
+ /**
+ * Removes all outstanding pktuests for a given thread number. If a request
+ * has been sent to the bus, this function removes all of its targets.
+ * @param threadNum The thread number of the requests to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Return the current number of outstanding misses.
+ * @return the number of outstanding misses.
+ */
+ int getMisses()
+ {
+ return miss.getNumTargets();
+ }
+
+ /**
+ * Searches for the supplied address in the miss "queue".
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @return A pointer to miss if it matches.
+ */
+ MSHR* findMSHR(Addr addr)
+ {
+ if (miss.addr == addr && miss.pkt)
+ return &miss;
+ return NULL;
+ }
+
+ /**
+ * Searches for the supplied address in the write buffer.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @param writes List of pointers to the matching writes.
+ * @return True if there is a matching write.
+ */
+ bool findWrites(Addr addr, std::vector<MSHR*>& writes)
+ {
+ if (wb.addr == addr && wb.pkt) {
+ writes.push_back(&wb);
+ return true;
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Perform a writeback of dirty data to the given address.
+ * @param addr The address to write to.
+ * @param asid The address space id.
+ * @param size The number of bytes to write.
+ * @param data The data to write, can be NULL.
+ * @param compressed True if the data is compressed.
+ */
+ void doWriteback(Addr addr,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform a writeback pktuest.
+ * @param pkt The writeback request.
+ */
+ void doWriteback(Packet * &pkt);
+
+ /**
+ * Returns true if there are outstanding pktuests.
+ * @return True if there are outstanding pktuests.
+ */
+ bool havePending()
+ {
+ return !miss.inService || !wb.inService;
+ }
+
+ /**
+ * Add a target to the given MSHR. This assumes it is in the miss queue.
+ * @param mshr The mshr to add a target to.
+ * @param pkt The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &pkt)
+ {
+ fatal("Shouldn't call this on a blocking buffer.");
+ }
+
+ /**
+ * Dummy implmentation.
+ */
+ MSHR* allocateTargetList(Addr addr)
+ {
+ fatal("Unimplemented");
+ }
+};
+
+#endif // __BLOCKING_BUFFER_HH__
diff --git a/src/mem/cache/miss/miss_queue.cc b/src/mem/cache/miss/miss_queue.cc
new file mode 100644
index 000000000..76fb25716
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.cc
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Miss and writeback queue definitions.
+ */
+
+#include "cpu/smt.hh" //for maxThreadsPerCPU
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+
+using namespace std;
+
+// simple constructor
+/**
+ * @todo Remove the +16 from the write buffer constructor once we handle
+ * stalling on writebacks do to compression writes.
+ */
+MissQueue::MissQueue(int numMSHRs, int numTargets, int write_buffers,
+ bool write_allocate, bool prefetch_miss)
+ : mq(numMSHRs, 4), wb(write_buffers,numMSHRs+1000), numMSHR(numMSHRs),
+ numTarget(numTargets), writeBuffers(write_buffers),
+ writeAllocate(write_allocate), order(0), prefetchMiss(prefetch_miss)
+{
+ noTargetMSHR = NULL;
+}
+
+void
+MissQueue::regStats(const string &name)
+{
+ Request temp_req((Addr) NULL, 4, 0);
+ Packet::Command temp_cmd = Packet::ReadReq;
+ Packet temp_pkt(&temp_req, temp_cmd, 0); //@todo FIx command strings so this isn't neccessary
+ temp_pkt.allocate();
+
+ using namespace Stats;
+
+ writebacks
+ .init(maxThreadsPerCPU)
+ .name(name + ".writebacks")
+ .desc("number of writebacks")
+ .flags(total)
+ ;
+
+ // MSHR hit statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_hits[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_hits")
+ .desc("number of " + cstr + " MSHR hits")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrHits
+ .name(name + ".demand_mshr_hits")
+ .desc("number of demand (read+write) MSHR hits")
+ .flags(total)
+ ;
+ demandMshrHits = mshr_hits[Packet::ReadReq] + mshr_hits[Packet::WriteReq];
+
+ overallMshrHits
+ .name(name + ".overall_mshr_hits")
+ .desc("number of overall MSHR hits")
+ .flags(total)
+ ;
+ overallMshrHits = demandMshrHits + mshr_hits[Packet::SoftPFReq] +
+ mshr_hits[Packet::HardPFReq];
+
+ // MSHR miss statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_misses[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_misses")
+ .desc("number of " + cstr + " MSHR misses")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMisses
+ .name(name + ".demand_mshr_misses")
+ .desc("number of demand (read+write) MSHR misses")
+ .flags(total)
+ ;
+ demandMshrMisses = mshr_misses[Packet::ReadReq] + mshr_misses[Packet::WriteReq];
+
+ overallMshrMisses
+ .name(name + ".overall_mshr_misses")
+ .desc("number of overall MSHR misses")
+ .flags(total)
+ ;
+ overallMshrMisses = demandMshrMisses + mshr_misses[Packet::SoftPFReq] +
+ mshr_misses[Packet::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_miss_latency[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_miss_latency")
+ .desc("number of " + cstr + " MSHR miss cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ demandMshrMissLatency
+ .name(name + ".demand_mshr_miss_latency")
+ .desc("number of demand (read+write) MSHR miss cycles")
+ .flags(total)
+ ;
+ demandMshrMissLatency = mshr_miss_latency[Packet::ReadReq]
+ + mshr_miss_latency[Packet::WriteReq];
+
+ overallMshrMissLatency
+ .name(name + ".overall_mshr_miss_latency")
+ .desc("number of overall MSHR miss cycles")
+ .flags(total)
+ ;
+ overallMshrMissLatency = demandMshrMissLatency +
+ mshr_miss_latency[Packet::SoftPFReq] + mshr_miss_latency[Packet::HardPFReq];
+
+ // MSHR uncacheable statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_uncacheable[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_uncacheable")
+ .desc("number of " + cstr + " MSHR uncacheable")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheable
+ .name(name + ".overall_mshr_uncacheable_misses")
+ .desc("number of overall MSHR uncacheable misses")
+ .flags(total)
+ ;
+ overallMshrUncacheable = mshr_uncacheable[Packet::ReadReq]
+ + mshr_uncacheable[Packet::WriteReq] + mshr_uncacheable[Packet::SoftPFReq]
+ + mshr_uncacheable[Packet::HardPFReq];
+
+ // MSHR miss latency statistics
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshr_uncacheable_lat[access_idx]
+ .init(maxThreadsPerCPU)
+ .name(name + "." + cstr + "_mshr_uncacheable_latency")
+ .desc("number of " + cstr + " MSHR uncacheable cycles")
+ .flags(total | nozero | nonan)
+ ;
+ }
+
+ overallMshrUncacheableLatency
+ .name(name + ".overall_mshr_uncacheable_latency")
+ .desc("number of overall MSHR uncacheable cycles")
+ .flags(total)
+ ;
+ overallMshrUncacheableLatency = mshr_uncacheable_lat[Packet::ReadReq]
+ + mshr_uncacheable_lat[Packet::WriteReq]
+ + mshr_uncacheable_lat[Packet::SoftPFReq]
+ + mshr_uncacheable_lat[Packet::HardPFReq];
+
+#if 0
+ // MSHR access formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshrAccesses[access_idx]
+ .name(name + "." + cstr + "_mshr_accesses")
+ .desc("number of " + cstr + " mshr accesses(hits+misses)")
+ .flags(total | nozero | nonan)
+ ;
+ mshrAccesses[access_idx] =
+ mshr_hits[access_idx] + mshr_misses[access_idx]
+ + mshr_uncacheable[access_idx];
+ }
+
+ demandMshrAccesses
+ .name(name + ".demand_mshr_accesses")
+ .desc("number of demand (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ demandMshrAccesses = demandMshrHits + demandMshrMisses;
+
+ overallMshrAccesses
+ .name(name + ".overall_mshr_accesses")
+ .desc("number of overall (read+write) mshr accesses")
+ .flags(total | nozero | nonan)
+ ;
+ overallMshrAccesses = overallMshrHits + overallMshrMisses
+ + overallMshrUncacheable;
+#endif
+
+ // MSHR miss rate formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ mshrMissRate[access_idx]
+ .name(name + "." + cstr + "_mshr_miss_rate")
+ .desc("mshr miss rate for " + cstr + " accesses")
+ .flags(total | nozero | nonan)
+ ;
+
+ mshrMissRate[access_idx] =
+ mshr_misses[access_idx] / cache->accesses[access_idx];
+ }
+
+ demandMshrMissRate
+ .name(name + ".demand_mshr_miss_rate")
+ .desc("mshr miss rate for demand accesses")
+ .flags(total)
+ ;
+ demandMshrMissRate = demandMshrMisses / cache->demandAccesses;
+
+ overallMshrMissRate
+ .name(name + ".overall_mshr_miss_rate")
+ .desc("mshr miss rate for overall accesses")
+ .flags(total)
+ ;
+ overallMshrMissRate = overallMshrMisses / cache->overallAccesses;
+
+ // mshrMiss latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMshrMissLatency[access_idx]
+ .name(name + "." + cstr + "_avg_mshr_miss_latency")
+ .desc("average " + cstr + " mshr miss latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrMissLatency[access_idx] =
+ mshr_miss_latency[access_idx] / mshr_misses[access_idx];
+ }
+
+ demandAvgMshrMissLatency
+ .name(name + ".demand_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ demandAvgMshrMissLatency = demandMshrMissLatency / demandMshrMisses;
+
+ overallAvgMshrMissLatency
+ .name(name + ".overall_avg_mshr_miss_latency")
+ .desc("average overall mshr miss latency")
+ .flags(total)
+ ;
+ overallAvgMshrMissLatency = overallMshrMissLatency / overallMshrMisses;
+
+ // mshrUncacheable latency formulas
+ for (int access_idx = 0; access_idx < NUM_MEM_CMDS; ++access_idx) {
+ Packet::Command cmd = (Packet::Command)access_idx;
+ const string &cstr = temp_pkt.cmdIdxToString(cmd);
+
+ avgMshrUncacheableLatency[access_idx]
+ .name(name + "." + cstr + "_avg_mshr_uncacheable_latency")
+ .desc("average " + cstr + " mshr uncacheable latency")
+ .flags(total | nozero | nonan)
+ ;
+
+ avgMshrUncacheableLatency[access_idx] =
+ mshr_uncacheable_lat[access_idx] / mshr_uncacheable[access_idx];
+ }
+
+ overallAvgMshrUncacheableLatency
+ .name(name + ".overall_avg_mshr_uncacheable_latency")
+ .desc("average overall mshr uncacheable latency")
+ .flags(total)
+ ;
+ overallAvgMshrUncacheableLatency = overallMshrUncacheableLatency / overallMshrUncacheable;
+
+ mshr_cap_events
+ .init(maxThreadsPerCPU)
+ .name(name + ".mshr_cap_events")
+ .desc("number of times MSHR cap was activated")
+ .flags(total)
+ ;
+
+ //software prefetching stats
+ soft_prefetch_mshr_full
+ .init(maxThreadsPerCPU)
+ .name(name + ".soft_prefetch_mshr_full")
+ .desc("number of mshr full events for SW prefetching instrutions")
+ .flags(total)
+ ;
+
+ mshr_no_allocate_misses
+ .name(name +".no_allocate_misses")
+ .desc("Number of misses that were no-allocate")
+ ;
+
+}
+
+void
+MissQueue::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+MissQueue::setPrefetcher(BasePrefetcher *_prefetcher)
+{
+ prefetcher = _prefetcher;
+}
+
+MSHR*
+MissQueue::allocateMiss(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = mq.allocate(pkt, blkSize);
+ mshr->order = order++;
+ if (!pkt->req->isUncacheable() ){//&& !pkt->isNoAllocate()) {
+ // Mark this as a cache line fill
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ }
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ if (pkt->cmd != Packet::HardPFReq) {
+ //If we need to request the bus (not on HW prefetch), do so
+ cache->setMasterRequest(Request_MSHR, time);
+ }
+ return mshr;
+}
+
+
+MSHR*
+MissQueue::allocateWrite(Packet * &pkt, int size, Tick time)
+{
+ MSHR* mshr = wb.allocate(pkt,blkSize);
+ mshr->order = order++;
+
+//REMOVING COMPRESSION FOR NOW
+#if 0
+ if (pkt->isCompressed()) {
+ mshr->pkt->deleteData();
+ mshr->pkt->actualSize = pkt->actualSize;
+ mshr->pkt->data = new uint8_t[pkt->actualSize];
+ memcpy(mshr->pkt->data, pkt->data, pkt->actualSize);
+ } else {
+#endif
+ memcpy(mshr->pkt->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(), pkt->getSize());
+ //{
+
+ if (wb.isFull()) {
+ cache->setBlocked(Blocked_NoWBBuffers);
+ }
+
+ cache->setMasterRequest(Request_WB, time);
+
+ return mshr;
+}
+
+
+/**
+ * @todo Remove SW prefetches on mshr hits.
+ */
+void
+MissQueue::handleMiss(Packet * &pkt, int blkSize, Tick time)
+{
+// if (!cache->isTopLevel())
+ if (prefetchMiss) prefetcher->handleMiss(pkt, time);
+
+ int size = blkSize;
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
+ MSHR* mshr = NULL;
+ if (!pkt->req->isUncacheable()) {
+ mshr = mq.findMatch(blkAddr);
+ if (mshr) {
+ //@todo remove hw_pf here
+ mshr_hits[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ if (mshr->threadNum != pkt->req->getThreadNum()) {
+ mshr->threadNum = -1;
+ }
+ mq.allocateTarget(mshr, pkt);
+ if (mshr->pkt->isNoAllocate() && !pkt->isNoAllocate()) {
+ //We are adding an allocate after a no-allocate
+ mshr->pkt->flags &= ~NO_ALLOCATE;
+ }
+ if (mshr->getNumTargets() == numTarget) {
+ noTargetMSHR = mshr;
+ cache->setBlocked(Blocked_NoTargets);
+ mq.moveToFront(mshr);
+ }
+ return;
+ }
+ if (pkt->isNoAllocate()) {
+ //Count no-allocate requests differently
+ mshr_no_allocate_misses++;
+ }
+ else {
+ mshr_misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ }
+ } else {
+ //Count uncacheable accesses
+ mshr_uncacheable[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ size = pkt->getSize();
+ }
+ if (pkt->isWrite() && (pkt->req->isUncacheable() || !writeAllocate ||
+ !pkt->needsResponse())) {
+ /**
+ * @todo Add write merging here.
+ */
+ mshr = allocateWrite(pkt, blkSize, time);
+ return;
+ }
+
+ mshr = allocateMiss(pkt, blkSize, time);
+}
+
+MSHR*
+MissQueue::fetchBlock(Addr addr, int blk_size, Tick time,
+ Packet * &target)
+{
+ Addr blkAddr = addr & ~(Addr)(blk_size - 1);
+ assert(mq.findMatch(addr) == NULL);
+ MSHR *mshr = mq.allocateFetch(blkAddr, blk_size, target);
+ mshr->order = order++;
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ cache->setMasterRequest(Request_MSHR, time);
+ return mshr;
+}
+
+Packet *
+MissQueue::getPacket()
+{
+ Packet * pkt = mq.getReq();
+ if (((wb.isFull() && wb.inServiceMSHRs == 0) || !pkt ||
+ pkt->time > curTick) && wb.havePending()) {
+ pkt = wb.getReq();
+ // Need to search for earlier miss.
+ MSHR *mshr = mq.findPending(pkt);
+ if (mshr && mshr->order < ((MSHR*)(pkt->senderState))->order) {
+ // Service misses in order until conflict is cleared.
+ return mq.getReq();
+ }
+ }
+ if (pkt) {
+ MSHR* mshr = wb.findPending(pkt);
+ if (mshr /*&& mshr->order < pkt->senderState->order*/) {
+ // The only way this happens is if we are
+ // doing a write and we didn't have permissions
+ // then subsequently saw a writeback(owned got evicted)
+ // We need to make sure to perform the writeback first
+ // To preserve the dirty data, then we can issue the write
+ return wb.getReq();
+ }
+ }
+ else if (!mq.isFull()){
+ //If we have a miss queue slot, we can try a prefetch
+ pkt = prefetcher->getPacket();
+ if (pkt) {
+ //Update statistic on number of prefetches issued (hwpf_mshr_misses)
+ mshr_misses[pkt->cmdToIndex()][pkt->req->getThreadNum()]++;
+ //It will request the bus for the future, but should clear that immedieatley
+ allocateMiss(pkt, pkt->getSize(), curTick);
+ pkt = mq.getReq();
+ assert(pkt); //We should get back a req b/c we just put one in
+ }
+ }
+ return pkt;
+}
+
+void
+MissQueue::setBusCmd(Packet * &pkt, Packet::Command cmd)
+{
+ assert(pkt->senderState != 0);
+ MSHR * mshr = (MSHR*)pkt->senderState;
+ mshr->originalCmd = pkt->cmd;
+ if (pkt->isCacheFill() || pkt->isNoAllocate())
+ pkt->cmd = cmd;
+}
+
+void
+MissQueue::restoreOrigCmd(Packet * &pkt)
+{
+ pkt->cmd = ((MSHR*)(pkt->senderState))->originalCmd;
+}
+
+void
+MissQueue::markInService(Packet * &pkt)
+{
+ assert(pkt->senderState != 0);
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ /**
+ * @todo Should include MSHRQueue pointer in MSHR to select the correct
+ * one.
+ */
+ if ((!pkt->isCacheFill() && pkt->isWrite())) {
+ // Forwarding a write/ writeback, don't need to change
+ // the command
+ unblock = wb.isFull();
+ wb.markInService((MSHR*)pkt->senderState);
+ if (!wb.havePending()){
+ cache->clearMasterRequest(Request_WB);
+ }
+ if (unblock) {
+ // Do we really unblock?
+ unblock = !wb.isFull();
+ cause = Blocked_NoWBBuffers;
+ }
+ } else {
+ unblock = mq.isFull();
+ mq.markInService((MSHR*)pkt->senderState);
+ if (!mq.havePending()){
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (((MSHR*)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "%s:Marking a HW_PF in service\n",
+ cache->name());
+ //Also clear pending if need be
+ if (!prefetcher->havePending())
+ {
+ cache->clearMasterRequest(Request_PF);
+ }
+ }
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ if (unblock) {
+ cache->clearBlocked(cause);
+ }
+}
+
+
+void
+MissQueue::handleResponse(Packet * &pkt, Tick time)
+{
+ MSHR* mshr = (MSHR*)pkt->senderState;
+ if (((MSHR*)(pkt->senderState))->originalCmd == Packet::HardPFReq) {
+ DPRINTF(HWPrefetch, "%s:Handling the response to a HW_PF\n",
+ cache->name());
+ }
+#ifndef NDEBUG
+ int num_targets = mshr->getNumTargets();
+#endif
+
+ bool unblock = false;
+ bool unblock_target = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (pkt->isCacheFill() && !pkt->isNoAllocate()) {
+ mshr_miss_latency[mshr->originalCmd][pkt->req->getThreadNum()] +=
+ curTick - pkt->time;
+ // targets were handled in the cache tags
+ if (mshr == noTargetMSHR) {
+ // we always clear at least one target
+ unblock_target = true;
+ cause = Blocked_NoTargets;
+ noTargetMSHR = NULL;
+ }
+
+ if (mshr->hasTargets()) {
+ // Didn't satisfy all the targets, need to resend
+ Packet::Command cmd = mshr->getTarget()->cmd;
+ mq.markPending(mshr, cmd);
+ mshr->order = order++;
+ cache->setMasterRequest(Request_MSHR, time);
+ }
+ else {
+ unblock = mq.isFull();
+ mq.deallocate(mshr);
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ } else {
+ if (pkt->req->isUncacheable()) {
+ mshr_uncacheable_lat[pkt->cmd][pkt->req->getThreadNum()] +=
+ curTick - pkt->time;
+ }
+ if (mshr->hasTargets() && pkt->req->isUncacheable()) {
+ // Should only have 1 target if we had any
+ assert(num_targets == 1);
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
+ target->getSize());
+ }
+ cache->respond(target, time);
+ assert(!mshr->hasTargets());
+ }
+ else if (mshr->hasTargets()) {
+ //Must be a no_allocate with possibly more than one target
+ assert(mshr->pkt->isNoAllocate());
+ while (mshr->hasTargets()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+ if (pkt->isRead()) {
+ memcpy(target->getPtr<uint8_t>(), pkt->getPtr<uint8_t>(),
+ target->getSize());
+ }
+ cache->respond(target, time);
+ }
+ }
+
+ if (pkt->isWrite()) {
+ // If the wrtie buffer is full, we might unblock now
+ unblock = wb.isFull();
+ wb.deallocate(mshr);
+ if (unblock) {
+ // Did we really unblock?
+ unblock = !wb.isFull();
+ cause = Blocked_NoWBBuffers;
+ }
+ } else {
+ unblock = mq.isFull();
+ mq.deallocate(mshr);
+ if (unblock) {
+ unblock = !mq.isFull();
+ cause = Blocked_NoMSHRs;
+ }
+ }
+ }
+ if (unblock || unblock_target) {
+ cache->clearBlocked(cause);
+ }
+}
+
+void
+MissQueue::squash(int threadNum)
+{
+ bool unblock = false;
+ BlockedCause cause = NUM_BLOCKED_CAUSES;
+
+ if (noTargetMSHR && noTargetMSHR->threadNum == threadNum) {
+ noTargetMSHR = NULL;
+ unblock = true;
+ cause = Blocked_NoTargets;
+ }
+ if (mq.isFull()) {
+ unblock = true;
+ cause = Blocked_NoMSHRs;
+ }
+ mq.squash(threadNum);
+ if (!mq.havePending()) {
+ cache->clearMasterRequest(Request_MSHR);
+ }
+ if (unblock && !mq.isFull()) {
+ cache->clearBlocked(cause);
+ }
+
+}
+
+MSHR*
+MissQueue::findMSHR(Addr addr) const
+{
+ return mq.findMatch(addr);
+}
+
+bool
+MissQueue::findWrites(Addr addr, vector<MSHR*> &writes) const
+{
+ return wb.findMatches(addr,writes);
+}
+
+void
+MissQueue::doWriteback(Addr addr,
+ int size, uint8_t *data, bool compressed)
+{
+ // Generate request
+ Request * req = new Request(addr, size, 0);
+ Packet * pkt = new Packet(req, Packet::Writeback, -1);
+ pkt->allocate();
+ if (data) {
+ memcpy(pkt->getPtr<uint8_t>(), data, size);
+ }
+
+ if (compressed) {
+ pkt->flags |= COMPRESSED;
+ }
+
+ ///All writebacks charged to same thread @todo figure this out
+ writebacks[pkt->req->getThreadNum()]++;
+
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+void
+MissQueue::doWriteback(Packet * &pkt)
+{
+ writebacks[pkt->req->getThreadNum()]++;
+ allocateWrite(pkt, 0, curTick);
+}
+
+
+MSHR*
+MissQueue::allocateTargetList(Addr addr)
+{
+ MSHR* mshr = mq.allocateTargetList(addr, blkSize);
+ mshr->pkt->flags |= CACHE_LINE_FILL;
+ if (mq.isFull()) {
+ cache->setBlocked(Blocked_NoMSHRs);
+ }
+ return mshr;
+}
+
+bool
+MissQueue::havePending()
+{
+ return mq.havePending() || wb.havePending() || prefetcher->havePending();
+}
diff --git a/src/mem/cache/miss/miss_queue.hh b/src/mem/cache/miss/miss_queue.hh
new file mode 100644
index 000000000..505d1f90c
--- /dev/null
+++ b/src/mem/cache/miss/miss_queue.hh
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Miss and writeback queue declarations.
+ */
+
+#ifndef __MISS_QUEUE_HH__
+#define __MISS_QUEUE_HH__
+
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "mem/cache/miss/mshr_queue.hh"
+#include "base/statistics.hh"
+
+class BaseCache;
+class BasePrefetcher;
+/**
+ * Manages cache misses and writebacks. Contains MSHRs to store miss data
+ * and the writebuffer for writes/writebacks.
+ * @todo need to handle data on writes better (encapsulate).
+ * @todo need to make replacements/writebacks happen in Cache::access
+ */
+class MissQueue
+{
+ protected:
+ /** The MSHRs. */
+ MSHRQueue mq;
+ /** Write Buffer. */
+ MSHRQueue wb;
+
+ // PARAMTERS
+
+ /** The number of MSHRs in the miss queue. */
+ const int numMSHR;
+ /** The number of targets for each MSHR. */
+ const int numTarget;
+ /** The number of write buffers. */
+ const int writeBuffers;
+ /** True if the cache should allocate on a write miss. */
+ const bool writeAllocate;
+ /** Pointer to the parent cache. */
+ BaseCache* cache;
+
+ /** The Prefetcher */
+ BasePrefetcher *prefetcher;
+
+ /** The block size of the parent cache. */
+ int blkSize;
+
+ /** Increasing order number assigned to each incoming pktuest. */
+ uint64_t order;
+
+ bool prefetchMiss;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** Number of blocks written back per thread. */
+ Stats::Vector<> writebacks;
+
+ /** Number of misses that hit in the MSHRs per command and thread. */
+ Stats::Vector<> mshr_hits[NUM_MEM_CMDS];
+ /** Demand misses that hit in the MSHRs. */
+ Stats::Formula demandMshrHits;
+ /** Total number of misses that hit in the MSHRs. */
+ Stats::Formula overallMshrHits;
+
+ /** Number of misses that miss in the MSHRs, per command and thread. */
+ Stats::Vector<> mshr_misses[NUM_MEM_CMDS];
+ /** Demand misses that miss in the MSHRs. */
+ Stats::Formula demandMshrMisses;
+ /** Total number of misses that miss in the MSHRs. */
+ Stats::Formula overallMshrMisses;
+
+ /** Number of misses that miss in the MSHRs, per command and thread. */
+ Stats::Vector<> mshr_uncacheable[NUM_MEM_CMDS];
+ /** Total number of misses that miss in the MSHRs. */
+ Stats::Formula overallMshrUncacheable;
+
+ /** Total cycle latency of each MSHR miss, per command and thread. */
+ Stats::Vector<> mshr_miss_latency[NUM_MEM_CMDS];
+ /** Total cycle latency of demand MSHR misses. */
+ Stats::Formula demandMshrMissLatency;
+ /** Total cycle latency of overall MSHR misses. */
+ Stats::Formula overallMshrMissLatency;
+
+ /** Total cycle latency of each MSHR miss, per command and thread. */
+ Stats::Vector<> mshr_uncacheable_lat[NUM_MEM_CMDS];
+ /** Total cycle latency of overall MSHR misses. */
+ Stats::Formula overallMshrUncacheableLatency;
+
+ /** The total number of MSHR accesses per command and thread. */
+ Stats::Formula mshrAccesses[NUM_MEM_CMDS];
+ /** The total number of demand MSHR accesses. */
+ Stats::Formula demandMshrAccesses;
+ /** The total number of MSHR accesses. */
+ Stats::Formula overallMshrAccesses;
+
+ /** The miss rate in the MSHRs pre command and thread. */
+ Stats::Formula mshrMissRate[NUM_MEM_CMDS];
+ /** The demand miss rate in the MSHRs. */
+ Stats::Formula demandMshrMissRate;
+ /** The overall miss rate in the MSHRs. */
+ Stats::Formula overallMshrMissRate;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrMissLatency[NUM_MEM_CMDS];
+ /** The average latency of a demand MSHR miss. */
+ Stats::Formula demandAvgMshrMissLatency;
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrMissLatency;
+
+ /** The average latency of an MSHR miss, per command and thread. */
+ Stats::Formula avgMshrUncacheableLatency[NUM_MEM_CMDS];
+ /** The average overall latency of an MSHR miss. */
+ Stats::Formula overallAvgMshrUncacheableLatency;
+
+ /** The number of times a thread hit its MSHR cap. */
+ Stats::Vector<> mshr_cap_events;
+ /** The number of times software prefetches caused the MSHR to block. */
+ Stats::Vector<> soft_prefetch_mshr_full;
+
+ Stats::Scalar<> mshr_no_allocate_misses;
+
+ /**
+ * @}
+ */
+
+ private:
+ /** Pointer to the MSHR that has no targets. */
+ MSHR* noTargetMSHR;
+
+ /**
+ * Allocate a new MSHR to handle the provided miss.
+ * @param pkt The miss to buffer.
+ * @param size The number of bytes to fetch.
+ * @param time The time the miss occurs.
+ * @return A pointer to the new MSHR.
+ */
+ MSHR* allocateMiss(Packet * &pkt, int size, Tick time);
+
+ /**
+ * Allocate a new WriteBuffer to handle the provided write.
+ * @param pkt The write to handle.
+ * @param size The number of bytes to write.
+ * @param time The time the write occurs.
+ * @return A pointer to the new write buffer.
+ */
+ MSHR* allocateWrite(Packet * &pkt, int size, Tick time);
+
+ public:
+ /**
+ * Simple Constructor. Initializes all needed internal storage and sets
+ * parameters.
+ * @param numMSHRs The number of outstanding misses to handle.
+ * @param numTargets The number of outstanding targets to each miss.
+ * @param write_buffers The number of outstanding writes to handle.
+ * @param write_allocate If true, treat write misses the same as reads.
+ */
+ MissQueue(int numMSHRs, int numTargets, int write_buffers,
+ bool write_allocate, bool prefetch_miss);
+
+ /**
+ * Deletes all allocated internal storage.
+ */
+ ~MissQueue();
+
+ /**
+ * Register statistics for this object.
+ * @param name The name of the parent cache.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Called by the parent cache to set the back pointer.
+ * @param _cache A pointer to the parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ void setPrefetcher(BasePrefetcher *_prefetcher);
+
+ /**
+ * Handle a cache miss properly. Either allocate an MSHR for the pktuest,
+ * or forward it through the write buffer.
+ * @param pkt The request that missed in the cache.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ */
+ void handleMiss(Packet * &pkt, int blk_size, Tick time);
+
+ /**
+ * Fetch the block for the given address and buffer the given target.
+ * @param addr The address to fetch.
+ * @param asid The address space of the address.
+ * @param blk_size The block size of the cache.
+ * @param time The time the miss is detected.
+ * @param target The target for the fetch.
+ */
+ MSHR* fetchBlock(Addr addr, int blk_size, Tick time,
+ Packet * &target);
+
+ /**
+ * Selects a outstanding pktuest to service.
+ * @return The pktuest to service, NULL if none found.
+ */
+ Packet * getPacket();
+
+ /**
+ * Set the command to the given bus command.
+ * @param pkt The request to update.
+ * @param cmd The bus command to use.
+ */
+ void setBusCmd(Packet * &pkt, Packet::Command cmd);
+
+ /**
+ * Restore the original command in case of a bus transmission error.
+ * @param pkt The request to reset.
+ */
+ void restoreOrigCmd(Packet * &pkt);
+
+ /**
+ * Marks a pktuest as in service (sent on the bus). This can have side
+ * effect since storage for no response commands is deallocated once they
+ * are successfully sent.
+ * @param pkt The request that was sent on the bus.
+ */
+ void markInService(Packet * &pkt);
+
+ /**
+ * Collect statistics and free resources of a satisfied pktuest.
+ * @param pkt The request that has been satisfied.
+ * @param time The time when the pktuest is satisfied.
+ */
+ void handleResponse(Packet * &pkt, Tick time);
+
+ /**
+ * Removes all outstanding pktuests for a given thread number. If a request
+ * has been sent to the bus, this function removes all of its targets.
+ * @param threadNum The thread number of the requests to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Return the current number of outstanding misses.
+ * @return the number of outstanding misses.
+ */
+ int getMisses()
+ {
+ return mq.getAllocatedTargets();
+ }
+
+ /**
+ * Searches for the supplied address in the miss queue.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @return The MSHR that contains the address, NULL if not found.
+ * @warning Currently only searches the miss queue. If non write allocate
+ * might need to search the write buffer for coherence.
+ */
+ MSHR* findMSHR(Addr addr) const;
+
+ /**
+ * Searches for the supplied address in the write buffer.
+ * @param addr The address to look for.
+ * @param asid The address space id.
+ * @param writes The list of writes that match the address.
+ * @return True if any writes are found
+ */
+ bool findWrites(Addr addr, std::vector<MSHR*>& writes) const;
+
+ /**
+ * Perform a writeback of dirty data to the given address.
+ * @param addr The address to write to.
+ * @param asid The address space id.
+ * @param xc The execution context of the address space.
+ * @param size The number of bytes to write.
+ * @param data The data to write, can be NULL.
+ * @param compressed True if the data is compressed.
+ */
+ void doWriteback(Addr addr,
+ int size, uint8_t *data, bool compressed);
+
+ /**
+ * Perform the given writeback pktuest.
+ * @param pkt The writeback request.
+ */
+ void doWriteback(Packet * &pkt);
+
+ /**
+ * Returns true if there are outstanding pktuests.
+ * @return True if there are outstanding pktuests.
+ */
+ bool havePending();
+
+ /**
+ * Add a target to the given MSHR. This assumes it is in the miss queue.
+ * @param mshr The mshr to add a target to.
+ * @param pkt The target to add.
+ */
+ void addTarget(MSHR *mshr, Packet * &pkt)
+ {
+ mq.allocateTarget(mshr, pkt);
+ }
+
+ /**
+ * Allocate a MSHR to hold a list of targets to a block involved in a copy.
+ * If the block is marked done then the MSHR already holds the data to
+ * fill the block. Otherwise the block needs to be fetched.
+ * @param addr The address to buffer.
+ * @param asid The address space ID.
+ * @return A pointer to the allocated MSHR.
+ */
+ MSHR* allocateTargetList(Addr addr);
+
+};
+
+#endif //__MISS_QUEUE_HH__
diff --git a/src/mem/cache/miss/mshr.cc b/src/mem/cache/miss/mshr.cc
new file mode 100644
index 000000000..519ec5ebd
--- /dev/null
+++ b/src/mem/cache/miss/mshr.cc
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Dave Greene
+ */
+
+/**
+ * @file
+ * Miss Status and Handling Register (MSHR) definitions.
+ */
+
+#include <assert.h>
+#include <string>
+#include <vector>
+
+#include "mem/cache/miss/mshr.hh"
+#include "sim/root.hh" // for curTick
+#include "sim/host.hh"
+#include "base/misc.hh"
+#include "mem/cache/cache.hh"
+
+using namespace std;
+
+MSHR::MSHR()
+{
+ inService = false;
+ ntargets = 0;
+ threadNum = -1;
+}
+
+void
+MSHR::allocate(Packet::Command cmd, Addr _addr, int size,
+ Packet * &target)
+{
+ addr = _addr;
+ if (target)
+ {
+ //Have a request, just use it
+ pkt = new Packet(target->req, cmd, Packet::Broadcast, size);
+ pkt->time = curTick;
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState *)this;
+ allocateTarget(target);
+ }
+ else
+ {
+ //need a request first
+ Request * req = new Request();
+ req->setPhys(addr, size, 0);
+ //Thread context??
+ pkt = new Packet(req, cmd, Packet::Broadcast, size);
+ pkt->time = curTick;
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState *)this;
+ }
+}
+
+// Since we aren't sure if data is being used, don't copy here.
+/**
+ * @todo When we have a "global" data flag, might want to copy data here.
+ */
+void
+MSHR::allocateAsBuffer(Packet * &target)
+{
+ addr = target->getAddr();
+ threadNum = target->req->getThreadNum();
+ pkt = new Packet(target->req, target->cmd, -1);
+ pkt->allocate();
+ pkt->senderState = (Packet::SenderState*)this;
+ pkt->time = curTick;
+}
+
+void
+MSHR::deallocate()
+{
+ assert(targets.empty());
+ assert(ntargets == 0);
+ pkt = NULL;
+ inService = false;
+ //allocIter = NULL;
+ //readyIter = NULL;
+}
+
+/*
+ * Adds a target to an MSHR
+ */
+void
+MSHR::allocateTarget(Packet * &target)
+{
+ //If we append an invalidate and we issued a read to the bus,
+ //but now have some pending writes, we need to move
+ //the invalidate to before the first non-read
+ if (inService && pkt->isRead() && target->isInvalidate()) {
+ std::list<Packet *> temp;
+
+ while (!targets.empty()) {
+ if (!targets.front()->isRead()) break;
+ //Place on top of temp stack
+ temp.push_front(targets.front());
+ //Remove from targets
+ targets.pop_front();
+ }
+
+ //Now that we have all the reads off until first non-read, we can
+ //place the invalidate on
+ targets.push_front(target);
+
+ //Now we pop off the temp_stack and put them back
+ while (!temp.empty()) {
+ targets.push_front(temp.front());
+ temp.pop_front();
+ }
+ }
+ else {
+ targets.push_back(target);
+ }
+
+ ++ntargets;
+ assert(targets.size() == ntargets);
+ /**
+ * @todo really prioritize the target commands.
+ */
+
+ if (!inService && target->isWrite()) {
+ pkt->cmd = Packet::WriteReq;
+ }
+}
+
+
+
+void
+MSHR::dump()
+{
+ ccprintf(cerr,
+ "inService: %d thread: %d\n"
+ "Addr: %x ntargets %d\n"
+ "Targets:\n",
+ inService, threadNum, addr, ntargets);
+
+ TargetListIterator tar_it = targets.begin();
+ for (int i = 0; i < ntargets; i++) {
+ assert(tar_it != targets.end());
+
+ ccprintf(cerr, "\t%d: Addr: %x cmd: %d\n",
+ i, (*tar_it)->getAddr(), (*tar_it)->cmdToIndex());
+
+ tar_it++;
+ }
+ ccprintf(cerr, "\n");
+}
+
+MSHR::~MSHR()
+{
+ if (pkt)
+ pkt = NULL;
+}
diff --git a/src/mem/cache/miss/mshr.hh b/src/mem/cache/miss/mshr.hh
new file mode 100644
index 000000000..028259b35
--- /dev/null
+++ b/src/mem/cache/miss/mshr.hh
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Miss Status and Handling Register (MSHR) declaration.
+ */
+
+#ifndef __MSHR_HH__
+#define __MSHR_HH__
+
+#include "mem/packet.hh"
+#include <list>
+#include <deque>
+
+class MSHR;
+
+/**
+ * Miss Status and handling Register. This class keeps all the information
+ * needed to handle a cache miss including a list of target pktuests.
+ */
+class MSHR {
+ public:
+ /** Defines the Data structure of the MSHR targetlist. */
+ typedef std::list<Packet *> TargetList;
+ /** Target list iterator. */
+ typedef std::list<Packet *>::iterator TargetListIterator;
+ /** A list of MSHRs. */
+ typedef std::list<MSHR *> List;
+ /** MSHR list iterator. */
+ typedef List::iterator Iterator;
+ /** MSHR list const_iterator. */
+ typedef List::const_iterator ConstIterator;
+
+ /** Address of the miss. */
+ Addr addr;
+ /** Adress space id of the miss. */
+ short asid;
+ /** True if the pktuest has been sent to the bus. */
+ bool inService;
+ /** Thread number of the miss. */
+ int threadNum;
+ /** The pktuest that is forwarded to the next level of the hierarchy. */
+ Packet * pkt;
+ /** The number of currently allocated targets. */
+ short ntargets;
+ /** The original pktuesting command. */
+ Packet::Command originalCmd;
+ /** Order number of assigned by the miss queue. */
+ uint64_t order;
+
+ /**
+ * Pointer to this MSHR on the ready list.
+ * @sa MissQueue, MSHRQueue::readyList
+ */
+ Iterator readyIter;
+ /**
+ * Pointer to this MSHR on the allocated list.
+ * @sa MissQueue, MSHRQueue::allocatedList
+ */
+ Iterator allocIter;
+
+private:
+ /** List of all pktuests that match the address */
+ TargetList targets;
+
+public:
+ /**
+ * Allocate a miss to this MSHR.
+ * @param cmd The pktuesting command.
+ * @param addr The address of the miss.
+ * @param asid The address space id of the miss.
+ * @param size The number of bytes to pktuest.
+ * @param pkt The original miss.
+ */
+ void allocate(Packet::Command cmd, Addr addr, int size,
+ Packet * &pkt);
+
+ /**
+ * Allocate this MSHR as a buffer for the given pktuest.
+ * @param target The memory pktuest to buffer.
+ */
+ void allocateAsBuffer(Packet * &target);
+
+ /**
+ * Mark this MSHR as free.
+ */
+ void deallocate();
+
+ /**
+ * Add a pktuest to the list of targets.
+ * @param target The target.
+ */
+ void allocateTarget(Packet * &target);
+
+ /** A simple constructor. */
+ MSHR();
+ /** A simple destructor. */
+ ~MSHR();
+
+ /**
+ * Returns the current number of allocated targets.
+ * @return The current number of allocated targets.
+ */
+ int getNumTargets()
+ {
+ return(ntargets);
+ }
+
+ /**
+ * Returns a pointer to the target list.
+ * @return a pointer to the target list.
+ */
+ TargetList* getTargetList()
+ {
+ return &targets;
+ }
+
+ /**
+ * Returns a reference to the first target.
+ * @return A pointer to the first target.
+ */
+ Packet * getTarget()
+ {
+ return targets.front();
+ }
+
+ /**
+ * Pop first target.
+ */
+ void popTarget()
+ {
+ --ntargets;
+ targets.pop_front();
+ }
+
+ /**
+ * Returns true if there are targets left.
+ * @return true if there are targets
+ */
+ bool hasTargets()
+ {
+ return !targets.empty();
+ }
+
+ /**
+ * Prints the contents of this MSHR to stderr.
+ */
+ void dump();
+};
+
+#endif //__MSHR_HH__
diff --git a/src/mem/cache/miss/mshr_queue.cc b/src/mem/cache/miss/mshr_queue.cc
new file mode 100644
index 000000000..97a56119f
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.cc
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/** @file
+ * Definition of the MSHRQueue.
+ */
+
+#include "mem/cache/miss/mshr_queue.hh"
+#include "sim/eventq.hh"
+
+using namespace std;
+
+MSHRQueue::MSHRQueue(int num_mshrs, int reserve)
+ : numMSHRs(num_mshrs + reserve - 1), numReserve(reserve)
+{
+ allocated = 0;
+ inServiceMSHRs = 0;
+ allocatedTargets = 0;
+ registers = new MSHR[numMSHRs];
+ for (int i = 0; i < numMSHRs; ++i) {
+ freeList.push_back(&registers[i]);
+ }
+}
+
+MSHRQueue::~MSHRQueue()
+{
+ delete [] registers;
+}
+
+MSHR*
+MSHRQueue::findMatch(Addr addr) const
+{
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ return mshr;
+ }
+ }
+ return NULL;
+}
+
+bool
+MSHRQueue::findMatches(Addr addr, vector<MSHR*>& matches) const
+{
+ // Need an empty vector
+ assert(matches.empty());
+ bool retval = false;
+ MSHR::ConstIterator i = allocatedList.begin();
+ MSHR::ConstIterator end = allocatedList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr == addr) {
+ retval = true;
+ matches.push_back(mshr);
+ }
+ }
+ return retval;
+
+}
+
+MSHR*
+MSHRQueue::findPending(Packet * &pkt) const
+{
+ MSHR::ConstIterator i = pendingList.begin();
+ MSHR::ConstIterator end = pendingList.end();
+ for (; i != end; ++i) {
+ MSHR *mshr = *i;
+ if (mshr->addr < pkt->getAddr()) {
+ if (mshr->addr + mshr->pkt->getSize() > pkt->getAddr()) {
+ return mshr;
+ }
+ } else {
+ if (pkt->getAddr() + pkt->getSize() > mshr->addr) {
+ return mshr;
+ }
+ }
+
+ //need to check destination address for copies.
+ //TEMP NOT DOING COPIES
+#if 0
+ if (mshr->pkt->cmd == Copy) {
+ Addr dest = mshr->pkt->dest;
+ if (dest < pkt->addr) {
+ if (dest + mshr->pkt->size > pkt->addr) {
+ return mshr;
+ }
+ } else {
+ if (pkt->addr + pkt->size > dest) {
+ return mshr;
+ }
+ }
+ }
+#endif
+ }
+ return NULL;
+}
+
+MSHR*
+MSHRQueue::allocate(Packet * &pkt, int size)
+{
+ Addr aligned_addr = pkt->getAddr() & ~((Addr)size - 1);
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+
+ if (!pkt->needsResponse()) {
+ mshr->allocateAsBuffer(pkt);
+ } else {
+ assert(size !=0);
+ mshr->allocate(pkt->cmd, aligned_addr, size, pkt);
+ allocatedTargets += 1;
+ }
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateFetch(Addr addr, int size, Packet * &target)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ mshr->allocate(Packet::ReadReq, addr, size, target);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+
+ allocated += 1;
+ return mshr;
+}
+
+MSHR*
+MSHRQueue::allocateTargetList(Addr addr, int size)
+{
+ MSHR *mshr = freeList.front();
+ assert(mshr->getNumTargets() == 0);
+ freeList.pop_front();
+ Packet * dummy;
+ mshr->allocate(Packet::ReadReq, addr, size, dummy);
+ mshr->allocIter = allocatedList.insert(allocatedList.end(), mshr);
+ mshr->inService = true;
+ ++inServiceMSHRs;
+ ++allocated;
+ return mshr;
+}
+
+
+void
+MSHRQueue::deallocate(MSHR* mshr)
+{
+ deallocateOne(mshr);
+}
+
+MSHR::Iterator
+MSHRQueue::deallocateOne(MSHR* mshr)
+{
+ MSHR::Iterator retval = allocatedList.erase(mshr->allocIter);
+ freeList.push_front(mshr);
+ allocated--;
+ allocatedTargets -= mshr->getNumTargets();
+ if (mshr->inService) {
+ inServiceMSHRs--;
+ } else {
+ pendingList.erase(mshr->readyIter);
+ }
+ mshr->deallocate();
+ return retval;
+}
+
+void
+MSHRQueue::moveToFront(MSHR *mshr)
+{
+ if (!mshr->inService) {
+ assert(mshr == *(mshr->readyIter));
+ pendingList.erase(mshr->readyIter);
+ mshr->readyIter = pendingList.insert(pendingList.begin(), mshr);
+ }
+}
+
+void
+MSHRQueue::markInService(MSHR* mshr)
+{
+ //assert(mshr == pendingList.front());
+ if (!mshr->pkt->needsResponse()) {
+ assert(mshr->getNumTargets() == 0);
+ deallocate(mshr);
+ return;
+ }
+ mshr->inService = true;
+ pendingList.erase(mshr->readyIter);
+ //mshr->readyIter = NULL;
+ inServiceMSHRs += 1;
+ //pendingList.pop_front();
+}
+
+void
+MSHRQueue::markPending(MSHR* mshr, Packet::Command cmd)
+{
+ //assert(mshr->readyIter == NULL);
+ mshr->pkt->cmd = cmd;
+ mshr->pkt->flags &= ~SATISFIED;
+ mshr->inService = false;
+ --inServiceMSHRs;
+ /**
+ * @ todo might want to add rerequests to front of pending list for
+ * performance.
+ */
+ mshr->readyIter = pendingList.insert(pendingList.end(), mshr);
+}
+
+void
+MSHRQueue::squash(int threadNum)
+{
+ MSHR::Iterator i = allocatedList.begin();
+ MSHR::Iterator end = allocatedList.end();
+ for (; i != end;) {
+ MSHR *mshr = *i;
+ if (mshr->threadNum == threadNum) {
+ while (mshr->hasTargets()) {
+ Packet * target = mshr->getTarget();
+ mshr->popTarget();
+
+ assert(target->req->getThreadNum() == threadNum);
+ target = NULL;
+ }
+ assert(!mshr->hasTargets());
+ assert(mshr->ntargets==0);
+ if (!mshr->inService) {
+ i = deallocateOne(mshr);
+ } else {
+ //mshr->pkt->flags &= ~CACHE_LINE_FILL;
+ ++i;
+ }
+ } else {
+ ++i;
+ }
+ }
+}
diff --git a/src/mem/cache/miss/mshr_queue.hh b/src/mem/cache/miss/mshr_queue.hh
new file mode 100644
index 000000000..ea5f101b7
--- /dev/null
+++ b/src/mem/cache/miss/mshr_queue.hh
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/** @file
+ * Declaration of a structure to manage MSHRs.
+ */
+
+#ifndef __MSHR_QUEUE_HH__
+#define __MSHR_QUEUE_HH__
+
+#include <vector>
+#include "mem/cache/miss/mshr.hh"
+
+/**
+ * A Class for maintaining a list of pending and allocated memory pktuests.
+ */
+class MSHRQueue {
+ private:
+ /** MSHR storage. */
+ MSHR* registers;
+ /** Holds pointers to all allocated MSHRs. */
+ MSHR::List allocatedList;
+ /** Holds pointers to MSHRs that haven't been sent to the bus. */
+ MSHR::List pendingList;
+ /** Holds non allocated MSHRs. */
+ MSHR::List freeList;
+
+ // Parameters
+ /**
+ * The total number of MSHRs in this queue. This number is set as the
+ * number of MSHRs pktuested plus (numReserve - 1). This allows for
+ * the same number of effective MSHRs while still maintaining the reserve.
+ */
+ const int numMSHRs;
+
+ /**
+ * The number of MSHRs to hold in reserve. This is needed because copy
+ * operations can allocate upto 4 MSHRs at one time.
+ */
+ const int numReserve;
+
+ public:
+ /** The number of allocated MSHRs. */
+ int allocated;
+ /** The number of MSHRs that have been forwarded to the bus. */
+ int inServiceMSHRs;
+ /** The number of targets waiting for response. */
+ int allocatedTargets;
+
+ /**
+ * Create a queue with a given number of MSHRs.
+ * @param num_mshrs The number of MSHRs in this queue.
+ * @param reserve The minimum number of MSHRs needed to satisfy any access.
+ */
+ MSHRQueue(int num_mshrs, int reserve = 1);
+
+ /** Destructor */
+ ~MSHRQueue();
+
+ /**
+ * Find the first MSHR that matches the provide address and asid.
+ * @param addr The address to find.
+ * @param asid The address space id.
+ * @return Pointer to the matching MSHR, null if not found.
+ */
+ MSHR* findMatch(Addr addr) const;
+
+ /**
+ * Find and return all the matching MSHRs in the provided vector.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param matches The vector to return pointers to the matching MSHRs.
+ * @return True if any matches are found, false otherwise.
+ * @todo Typedef the vector??
+ */
+ bool findMatches(Addr addr, std::vector<MSHR*>& matches) const;
+
+ /**
+ * Find any pending pktuests that overlap the given request.
+ * @param pkt The request to find.
+ * @return A pointer to the earliest matching MSHR.
+ */
+ MSHR* findPending(Packet * &pkt) const;
+
+ /**
+ * Allocates a new MSHR for the pktuest and size. This places the request
+ * as the first target in the MSHR.
+ * @param pkt The request to handle.
+ * @param size The number in bytes to fetch from memory.
+ * @return The a pointer to the MSHR allocated.
+ *
+ * @pre There are free MSHRs.
+ */
+ MSHR* allocate(Packet * &pkt, int size = 0);
+
+ /**
+ * Allocate a read pktuest for the given address, and places the given
+ * target on the target list.
+ * @param addr The address to fetch.
+ * @param asid The address space for the fetch.
+ * @param size The number of bytes to pktuest.
+ * @param target The first target for the pktuest.
+ * @return Pointer to the new MSHR.
+ */
+ MSHR* allocateFetch(Addr addr, int size, Packet * &target);
+
+ /**
+ * Allocate a target list for the given address.
+ * @param addr The address to fetch.
+ * @param asid The address space for the fetch.
+ * @param size The number of bytes to pktuest.
+ * @return Pointer to the new MSHR.
+ */
+ MSHR* allocateTargetList(Addr addr, int size);
+
+ /**
+ * Removes the given MSHR from the queue. This places the MSHR on the
+ * free list.
+ * @param mshr
+ */
+ void deallocate(MSHR* mshr);
+
+ /**
+ * Allocates a target to the given MSHR. Used to keep track of the number
+ * of outstanding targets.
+ * @param mshr The MSHR to allocate the target to.
+ * @param pkt The target request.
+ */
+ void allocateTarget(MSHR* mshr, Packet * &pkt)
+ {
+ mshr->allocateTarget(pkt);
+ allocatedTargets += 1;
+ }
+
+ /**
+ * Remove a MSHR from the queue. Returns an iterator into the allocatedList
+ * for faster squash implementation.
+ * @param mshr The MSHR to remove.
+ * @return An iterator to the next entry in the allocatedList.
+ */
+ MSHR::Iterator deallocateOne(MSHR* mshr);
+
+ /**
+ * Moves the MSHR to the front of the pending list if it is not in service.
+ * @param mshr The mshr to move.
+ */
+ void moveToFront(MSHR *mshr);
+
+ /**
+ * Mark the given MSHR as in service. This removes the MSHR from the
+ * pendingList. Deallocates the MSHR if it does not expect a response.
+ * @param mshr The MSHR to mark in service.
+ */
+ void markInService(MSHR* mshr);
+
+ /**
+ * Mark an in service mshr as pending, used to resend a pktuest.
+ * @param mshr The MSHR to resend.
+ * @param cmd The command to resend.
+ */
+ void markPending(MSHR* mshr, Packet::Command cmd);
+
+ /**
+ * Squash outstanding pktuests with the given thread number. If a request
+ * is in service, just squashes the targets.
+ * @param threadNum The thread to squash.
+ */
+ void squash(int threadNum);
+
+ /**
+ * Returns true if the pending list is not empty.
+ * @return True if there are outstanding pktuests.
+ */
+ bool havePending() const
+ {
+ return !pendingList.empty();
+ }
+
+ /**
+ * Returns true if there are no free MSHRs.
+ * @return True if this queue is full.
+ */
+ bool isFull() const
+ {
+ return (allocated > numMSHRs - numReserve);
+ }
+
+ /**
+ * Returns the pktuest at the head of the pendingList.
+ * @return The next pktuest to service.
+ */
+ Packet * getReq() const
+ {
+ if (pendingList.empty()) {
+ return NULL;
+ }
+ MSHR* mshr = pendingList.front();
+ return mshr->pkt;
+ }
+
+ /**
+ * Returns the number of outstanding targets.
+ * @return the number of allocated targets.
+ */
+ int getAllocatedTargets() const
+ {
+ return allocatedTargets;
+ }
+
+};
+
+#endif //__MSHR_QUEUE_HH__
diff --git a/src/mem/cache/prefetch/base_prefetcher.cc b/src/mem/cache/prefetch/base_prefetcher.cc
new file mode 100644
index 000000000..5e50c48bd
--- /dev/null
+++ b/src/mem/cache/prefetch/base_prefetcher.cc
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Hardware Prefetcher Definition.
+ */
+
+#include "base/trace.hh"
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/prefetch/base_prefetcher.hh"
+#include "mem/request.hh"
+#include <list>
+
+BasePrefetcher::BasePrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData)
+ :size(size), pageStop(pageStop), serialSquash(serialSquash),
+ cacheCheckPush(cacheCheckPush), only_data(onlyData)
+{
+}
+
+void
+BasePrefetcher::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ blkSize = cache->getBlockSize();
+}
+
+void
+BasePrefetcher::regStats(const std::string &name)
+{
+ pfIdentified
+ .name(name + ".prefetcher.num_hwpf_identified")
+ .desc("number of hwpf identified")
+ ;
+
+ pfMSHRHit
+ .name(name + ".prefetcher.num_hwpf_already_in_mshr")
+ .desc("number of hwpf that were already in mshr")
+ ;
+
+ pfCacheHit
+ .name(name + ".prefetcher.num_hwpf_already_in_cache")
+ .desc("number of hwpf that were already in the cache")
+ ;
+
+ pfBufferHit
+ .name(name + ".prefetcher.num_hwpf_already_in_prefetcher")
+ .desc("number of hwpf that were already in the prefetch queue")
+ ;
+
+ pfRemovedFull
+ .name(name + ".prefetcher.num_hwpf_evicted")
+ .desc("number of hwpf removed due to no buffer left")
+ ;
+
+ pfRemovedMSHR
+ .name(name + ".prefetcher.num_hwpf_removed_MSHR_hit")
+ .desc("number of hwpf removed because MSHR allocated")
+ ;
+
+ pfIssued
+ .name(name + ".prefetcher.num_hwpf_issued")
+ .desc("number of hwpf issued")
+ ;
+
+ pfSpanPage
+ .name(name + ".prefetcher.num_hwpf_span_page")
+ .desc("number of hwpf spanning a virtual page")
+ ;
+
+ pfSquashed
+ .name(name + ".prefetcher.num_hwpf_squashed_from_miss")
+ .desc("number of hwpf that got squashed due to a miss aborting calculation time")
+ ;
+}
+
+Packet *
+BasePrefetcher::getPacket()
+{
+ DPRINTF(HWPrefetch, "%s:Requesting a hw_pf to issue\n", cache->name());
+
+ if (pf.empty()) {
+ DPRINTF(HWPrefetch, "%s:No HW_PF found\n", cache->name());
+ return NULL;
+ }
+
+ Packet * pkt;
+ bool keepTrying = false;
+ do {
+ pkt = *pf.begin();
+ pf.pop_front();
+ if (!cacheCheckPush) {
+ keepTrying = inCache(pkt);
+ }
+ if (pf.empty()) {
+ cache->clearMasterRequest(Request_PF);
+ if (keepTrying) return NULL; //None left, all were in cache
+ }
+ } while (keepTrying);
+
+ pfIssued++;
+ return pkt;
+}
+
+void
+BasePrefetcher::handleMiss(Packet * &pkt, Tick time)
+{
+ if (!pkt->req->isUncacheable() && !(pkt->req->isInstRead() && only_data))
+ {
+ //Calculate the blk address
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(blkSize-1);
+
+ //Check if miss is in pfq, if so remove it
+ std::list<Packet *>::iterator iter = inPrefetch(blkAddr);
+ if (iter != pf.end()) {
+ DPRINTF(HWPrefetch, "%s:Saw a miss to a queued prefetch, removing it\n", cache->name());
+ pfRemovedMSHR++;
+ pf.erase(iter);
+ if (pf.empty())
+ cache->clearMasterRequest(Request_PF);
+ }
+
+ //Remove anything in queue with delay older than time
+ //since everything is inserted in time order, start from end
+ //and work until pf.empty() or time is earlier
+ //This is done to emulate Aborting the previous work on a new miss
+ //Needed for serial calculators like GHB
+ if (serialSquash) {
+ iter = pf.end();
+ iter--;
+ while (!pf.empty() && ((*iter)->time >= time)) {
+ pfSquashed++;
+ pf.pop_back();
+ iter--;
+ }
+ if (pf.empty())
+ cache->clearMasterRequest(Request_PF);
+ }
+
+
+ std::list<Addr> addresses;
+ std::list<Tick> delays;
+ calculatePrefetch(pkt, addresses, delays);
+
+ std::list<Addr>::iterator addr = addresses.begin();
+ std::list<Tick>::iterator delay = delays.begin();
+ while (addr != addresses.end())
+ {
+ DPRINTF(HWPrefetch, "%s:Found a pf canidate, inserting into prefetch queue\n", cache->name());
+ //temp calc this here...
+ pfIdentified++;
+ //create a prefetch memreq
+ Request * prefetchReq = new Request(*addr, blkSize, 0);
+ Packet * prefetch;
+ prefetch = new Packet(prefetchReq, Packet::HardPFReq, -1);
+ prefetch->allocate();
+ prefetch->req->setThreadContext(pkt->req->getCpuNum(),
+ pkt->req->getThreadNum());
+
+ prefetch->time = time + (*delay); //@todo ADD LATENCY HERE
+ //... initialize
+
+ //Check if it is already in the cache
+ if (cacheCheckPush) {
+ if (inCache(prefetch)) {
+ addr++;
+ delay++;
+ continue;
+ }
+ }
+
+ //Check if it is already in the miss_queue
+ if (inMissQueue(prefetch->getAddr())) {
+ addr++;
+ delay++;
+ continue;
+ }
+
+ //Check if it is already in the pf buffer
+ if (inPrefetch(prefetch->getAddr()) != pf.end()) {
+ pfBufferHit++;
+ addr++;
+ delay++;
+ continue;
+ }
+
+ //We just remove the head if we are full
+ if (pf.size() == size)
+ {
+ DPRINTF(HWPrefetch, "%s:Inserting into prefetch queue, it was full removing oldest\n", cache->name());
+ pfRemovedFull++;
+ pf.pop_front();
+ }
+
+ pf.push_back(prefetch);
+ prefetch->flags |= CACHE_LINE_FILL;
+
+ //Make sure to request the bus, with proper delay
+ cache->setMasterRequest(Request_PF, prefetch->time);
+
+ //Increment through the list
+ addr++;
+ delay++;
+ }
+ }
+}
+
+std::list<Packet *>::iterator
+BasePrefetcher::inPrefetch(Addr address)
+{
+ //Guaranteed to only be one match, we always check before inserting
+ std::list<Packet *>::iterator iter;
+ for (iter=pf.begin(); iter != pf.end(); iter++) {
+ if (((*iter)->getAddr() & ~(Addr)(blkSize-1)) == address) {
+ return iter;
+ }
+ }
+ return pf.end();
+}
+
+
diff --git a/src/mem/cache/prefetch/base_prefetcher.hh b/src/mem/cache/prefetch/base_prefetcher.hh
new file mode 100644
index 000000000..d7ea41961
--- /dev/null
+++ b/src/mem/cache/prefetch/base_prefetcher.hh
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Miss and writeback queue declarations.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
+
+#include "mem/packet.hh"
+#include <list>
+
+class BaseCache;
+class BasePrefetcher
+{
+ protected:
+
+ /** The Prefetch Queue. */
+ std::list<Packet *> pf;
+
+ // PARAMETERS
+
+ /** The number of MSHRs in the Prefetch Queue. */
+ const int size;
+
+ /** Pointr to the parent cache. */
+ BaseCache* cache;
+
+ /** The block size of the parent cache. */
+ int blkSize;
+
+ /** Do we prefetch across page boundaries. */
+ bool pageStop;
+
+ /** Do we remove prefetches with later times than a new miss.*/
+ bool serialSquash;
+
+ /** Do we check if it is in the cache when inserting into buffer,
+ or removing.*/
+ bool cacheCheckPush;
+
+ /** Do we prefetch on only data reads, or on inst reads as well. */
+ bool only_data;
+
+ public:
+
+ Stats::Scalar<> pfIdentified;
+ Stats::Scalar<> pfMSHRHit;
+ Stats::Scalar<> pfCacheHit;
+ Stats::Scalar<> pfBufferHit;
+ Stats::Scalar<> pfRemovedFull;
+ Stats::Scalar<> pfRemovedMSHR;
+ Stats::Scalar<> pfIssued;
+ Stats::Scalar<> pfSpanPage;
+ Stats::Scalar<> pfSquashed;
+
+ void regStats(const std::string &name);
+
+ public:
+ BasePrefetcher(int numMSHRS, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData);
+
+ virtual ~BasePrefetcher() {}
+
+ void setCache(BaseCache *_cache);
+
+ void handleMiss(Packet * &pkt, Tick time);
+
+ Packet * getPacket();
+
+ bool havePending()
+ {
+ return !pf.empty();
+ }
+
+ virtual void calculatePrefetch(Packet * &pkt,
+ std::list<Addr> &addresses,
+ std::list<Tick> &delays) = 0;
+
+ virtual bool inCache(Packet * &pkt) = 0;
+
+ virtual bool inMissQueue(Addr address) = 0;
+
+ std::list<Packet *>::iterator inPrefetch(Addr address);
+};
+
+
+#endif //__MEM_CACHE_PREFETCH_BASE_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/ghb_prefetcher.cc b/src/mem/cache/prefetch/ghb_prefetcher.cc
new file mode 100644
index 000000000..247ec6e8b
--- /dev/null
+++ b/src/mem/cache/prefetch/ghb_prefetcher.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * GHB Prefetcher template instantiations.
+ */
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#include "mem/cache/tags/lru.hh"
+
+#include "base/compression/null_compression.hh"
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/prefetch/ghb_prefetcher.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template class GHBPrefetcher<CacheTags<LRU,NullCompression>, MissQueue>;
+template class GHBPrefetcher<CacheTags<LRU,NullCompression>, BlockingBuffer>;
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/prefetch/ghb_prefetcher.hh b/src/mem/cache/prefetch/ghb_prefetcher.hh
new file mode 100644
index 000000000..c22b763d1
--- /dev/null
+++ b/src/mem/cache/prefetch/ghb_prefetcher.hh
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a ghb prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class GHBPrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ Addr second_last_miss_addr[64/*MAX_CPUS*/];
+ Addr last_miss_addr[64/*MAX_CPUS*/];
+
+ Tick latency;
+ int degree;
+ bool useCPUId;
+
+ public:
+
+ GHBPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree, bool useCPUId)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree), useCPUId(useCPUId)
+ {
+ }
+
+ ~GHBPrefetcher() {}
+
+ void calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
+ std::list<Tick> &delays)
+ {
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1);
+ int cpuID = pkt->req->getCpuNum();
+ if (!useCPUId) cpuID = 0;
+
+
+ int new_stride = blkAddr - last_miss_addr[cpuID];
+ int old_stride = last_miss_addr[cpuID] -
+ second_last_miss_addr[cpuID];
+
+ second_last_miss_addr[cpuID] = last_miss_addr[cpuID];
+ last_miss_addr[cpuID] = blkAddr;
+
+ if (new_stride == old_stride) {
+ for (int d=1; d <= degree; d++) {
+ Addr newAddr = blkAddr + d * new_stride;
+ if (this->pageStop &&
+ (blkAddr & ~(TheISA::VMPageSize - 1)) !=
+ (newAddr & ~(TheISA::VMPageSize - 1)))
+ {
+ //Spanned the page, so now stop
+ this->pfSpanPage += degree - d + 1;
+ return;
+ }
+ else
+ {
+ addresses.push_back(newAddr);
+ delays.push_back(latency);
+ }
+ }
+ }
+ }
+};
+
+#endif // __MEM_CACHE_PREFETCH_GHB_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/stride_prefetcher.cc b/src/mem/cache/prefetch/stride_prefetcher.cc
new file mode 100644
index 000000000..93a096468
--- /dev/null
+++ b/src/mem/cache/prefetch/stride_prefetcher.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Stride Prefetcher template instantiations.
+ */
+
+#include "mem/cache/tags/cache_tags.hh"
+
+#include "mem/cache/tags/lru.hh"
+
+#include "base/compression/null_compression.hh"
+
+#include "mem/cache/miss/miss_queue.hh"
+#include "mem/cache/miss/blocking_buffer.hh"
+
+#include "mem/cache/prefetch/stride_prefetcher.hh"
+
+// Template Instantiations
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+template class StridePrefetcher<CacheTags<LRU,NullCompression>, MissQueue>;
+template class StridePrefetcher<CacheTags<LRU,NullCompression>, BlockingBuffer>;
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/prefetch/stride_prefetcher.hh b/src/mem/cache/prefetch/stride_prefetcher.hh
new file mode 100644
index 000000000..4a8ee7de4
--- /dev/null
+++ b/src/mem/cache/prefetch/stride_prefetcher.hh
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a strided prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
+
+#include "base/misc.hh" // fatal, panic, and warn
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class StridePrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ class strideEntry
+ {
+ public:
+ Addr IAddr;
+ Addr MAddr;
+ int stride;
+ int64_t confidence;
+
+/* bool operator < (strideEntry a,strideEntry b)
+ {
+ if (a.confidence == b.confidence) {
+ return true; //??????
+ }
+ else return a.confidence < b.confidence;
+ }*/
+ };
+ Addr* lastMissAddr[64/*MAX_CPUS*/];
+
+ std::list<strideEntry*> table[64/*MAX_CPUS*/];
+ Tick latency;
+ int degree;
+ bool useCPUId;
+
+
+ public:
+
+ StridePrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree, bool useCPUId)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree), useCPUId(useCPUId)
+ {
+ }
+
+ ~StridePrefetcher() {}
+
+ void calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
+ std::list<Tick> &delays)
+ {
+// Addr blkAddr = pkt->paddr & ~(Addr)(this->blkSize-1);
+ int cpuID = pkt->req->getCpuNum();
+ if (!useCPUId) cpuID = 0;
+
+ /* Scan Table for IAddr Match */
+/* std::list<strideEntry*>::iterator iter;
+ for (iter=table[cpuID].begin();
+ iter !=table[cpuID].end();
+ iter++) {
+ if ((*iter)->IAddr == pkt->pc) break;
+ }
+
+ if (iter != table[cpuID].end()) {
+ //Hit in table
+
+ int newStride = blkAddr - (*iter)->MAddr;
+ if (newStride == (*iter)->stride) {
+ (*iter)->confidence++;
+ }
+ else {
+ (*iter)->stride = newStride;
+ (*iter)->confidence--;
+ }
+
+ (*iter)->MAddr = blkAddr;
+
+ for (int d=1; d <= degree; d++) {
+ Addr newAddr = blkAddr + d * newStride;
+ if (this->pageStop &&
+ (blkAddr & ~(TheISA::VMPageSize - 1)) !=
+ (newAddr & ~(TheISA::VMPageSize - 1)))
+ {
+ //Spanned the page, so now stop
+ this->pfSpanPage += degree - d + 1;
+ return;
+ }
+ else
+ {
+ addresses.push_back(newAddr);
+ delays.push_back(latency);
+ }
+ }
+ }
+ else {
+ //Miss in table
+ //Find lowest confidence and replace
+
+ }
+*/ }
+};
+
+#endif // __MEM_CACHE_PREFETCH_STRIDE_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/tagged_prefetcher.hh b/src/mem/cache/prefetch/tagged_prefetcher.hh
new file mode 100644
index 000000000..17f500dd8
--- /dev/null
+++ b/src/mem/cache/prefetch/tagged_prefetcher.hh
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a tagged prefetcher based on template policies.
+ */
+
+#ifndef __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
+#define __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
+
+#include "mem/cache/prefetch/prefetcher.hh"
+
+/**
+ * A template-policy based cache. The behavior of the cache can be altered by
+ * supplying different template policies. TagStore handles all tag and data
+ * storage @sa TagStore. Buffering handles all misses and writes/writebacks
+ * @sa MissQueue. Coherence handles all coherence policy details @sa
+ * UniCoherence, SimpleMultiCoherence.
+ */
+template <class TagStore, class Buffering>
+class TaggedPrefetcher : public Prefetcher<TagStore, Buffering>
+{
+ protected:
+
+ Buffering* mq;
+ TagStore* tags;
+
+ Tick latency;
+ int degree;
+
+ public:
+
+ TaggedPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree);
+
+ ~TaggedPrefetcher() {}
+
+ void calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
+ std::list<Tick> &delays);
+};
+
+#endif // __MEM_CACHE_PREFETCH_TAGGED_PREFETCHER_HH__
diff --git a/src/mem/cache/prefetch/tagged_prefetcher_impl.hh b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
new file mode 100644
index 000000000..e554b3cec
--- /dev/null
+++ b/src/mem/cache/prefetch/tagged_prefetcher_impl.hh
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Describes a tagged prefetcher based on template policies.
+ */
+
+#include "arch/isa_traits.hh"
+#include "mem/cache/prefetch/tagged_prefetcher.hh"
+
+template <class TagStore, class Buffering>
+TaggedPrefetcher<TagStore, Buffering>::
+TaggedPrefetcher(int size, bool pageStop, bool serialSquash,
+ bool cacheCheckPush, bool onlyData,
+ Tick latency, int degree)
+ :Prefetcher<TagStore, Buffering>(size, pageStop, serialSquash,
+ cacheCheckPush, onlyData),
+ latency(latency), degree(degree)
+{
+}
+
+template <class TagStore, class Buffering>
+void
+TaggedPrefetcher<TagStore, Buffering>::
+calculatePrefetch(Packet * &pkt, std::list<Addr> &addresses,
+ std::list<Tick> &delays)
+{
+ Addr blkAddr = pkt->getAddr() & ~(Addr)(this->blkSize-1);
+
+ for (int d=1; d <= degree; d++) {
+ Addr newAddr = blkAddr + d*(this->blkSize);
+ if (this->pageStop &&
+ (blkAddr & ~(TheISA::VMPageSize - 1)) !=
+ (newAddr & ~(TheISA::VMPageSize - 1)))
+ {
+ //Spanned the page, so now stop
+ this->pfSpanPage += degree - d + 1;
+ return;
+ }
+ else
+ {
+ addresses.push_back(newAddr);
+ delays.push_back(latency);
+ }
+ }
+}
+
+
diff --git a/src/mem/cache/tags/base_tags.cc b/src/mem/cache/tags/base_tags.cc
new file mode 100644
index 000000000..153737300
--- /dev/null
+++ b/src/mem/cache/tags/base_tags.cc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Definitions of BaseTags.
+ */
+
+#include "mem/cache/tags/base_tags.hh"
+
+#include "mem/cache/base_cache.hh"
+#include "cpu/smt.hh" //maxThreadsPerCPU
+#include "sim/sim_exit.hh"
+
+using namespace std;
+
+void
+BaseTags::setCache(BaseCache *_cache)
+{
+ cache = _cache;
+ objName = cache->name();
+}
+
+void
+BaseTags::regStats(const string &name)
+{
+ using namespace Stats;
+ replacements
+ .init(maxThreadsPerCPU)
+ .name(name + ".replacements")
+ .desc("number of replacements")
+ .flags(total)
+ ;
+
+ tagsInUse
+ .name(name + ".tagsinuse")
+ .desc("Cycle average of tags in use")
+ ;
+
+ totalRefs
+ .name(name + ".total_refs")
+ .desc("Total number of references to valid blocks.")
+ ;
+
+ sampledRefs
+ .name(name + ".sampled_refs")
+ .desc("Sample count of references to valid blocks.")
+ ;
+
+ avgRefs
+ .name(name + ".avg_refs")
+ .desc("Average number of references to valid blocks.")
+ ;
+
+ avgRefs = totalRefs/sampledRefs;
+
+ warmupCycle
+ .name(name + ".warmup_cycle")
+ .desc("Cycle when the warmup percentage was hit.")
+ ;
+
+ registerExitCallback(new BaseTagsCallback(this));
+}
diff --git a/src/mem/cache/tags/base_tags.hh b/src/mem/cache/tags/base_tags.hh
new file mode 100644
index 000000000..b7b0c7ef0
--- /dev/null
+++ b/src/mem/cache/tags/base_tags.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Declaration of a common base class for cache tagstore objects.
+ */
+
+#ifndef __BASE_TAGS_HH__
+#define __BASE_TAGS_HH__
+
+#include <string>
+#include "base/statistics.hh"
+#include "base/callback.hh"
+
+class BaseCache;
+
+/**
+ * A common base class of Cache tagstore objects.
+ */
+class BaseTags
+{
+ protected:
+ /** Pointer to the parent cache. */
+ BaseCache *cache;
+
+ /** Local copy of the parent cache name. Used for DPRINTF. */
+ std::string objName;
+
+ /**
+ * The number of tags that need to be touched to meet the warmup
+ * percentage.
+ */
+ int warmupBound;
+ /** Marked true when the cache is warmed up. */
+ bool warmedUp;
+
+ // Statistics
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+
+ /** Number of replacements of valid blocks per thread. */
+ Stats::Vector<> replacements;
+ /** Per cycle average of the number of tags that hold valid data. */
+ Stats::Average<> tagsInUse;
+
+ /** The total number of references to a block before it is replaced. */
+ Stats::Scalar<> totalRefs;
+
+ /**
+ * The number of reference counts sampled. This is different from
+ * replacements because we sample all the valid blocks when the simulator
+ * exits.
+ */
+ Stats::Scalar<> sampledRefs;
+
+ /**
+ * Average number of references to a block before is was replaced.
+ * @todo This should change to an average stat once we have them.
+ */
+ Stats::Formula avgRefs;
+
+ /** The cycle that the warmup percentage was hit. */
+ Stats::Scalar<> warmupCycle;
+ /**
+ * @}
+ */
+
+ public:
+
+ /**
+ * Destructor.
+ */
+ virtual ~BaseTags() {}
+
+ /**
+ * Set the parent cache back pointer. Also copies the cache name to
+ * objName.
+ * @param _cache Pointer to parent cache.
+ */
+ void setCache(BaseCache *_cache);
+
+ /**
+ * Return the parent cache name.
+ * @return the parent cache name.
+ */
+ const std::string &name() const
+ {
+ return objName;
+ }
+
+ /**
+ * Register local statistics.
+ * @param name The name to preceed each statistic name.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Average in the reference count for valid blocks when the simulation
+ * exits.
+ */
+ virtual void cleanupRefs() {}
+};
+
+class BaseTagsCallback : public Callback
+{
+ BaseTags *tags;
+ public:
+ BaseTagsCallback(BaseTags *t) : tags(t) {}
+ virtual void process() { tags->cleanupRefs(); };
+};
+
+#endif //__BASE_TAGS_HH__
diff --git a/src/mem/cache/tags/fa_lru.cc b/src/mem/cache/tags/fa_lru.cc
new file mode 100644
index 000000000..784ba1311
--- /dev/null
+++ b/src/mem/cache/tags/fa_lru.cc
@@ -0,0 +1,334 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions a fully associative LRU tagstore.
+ */
+
+#include <sstream>
+
+#include <assert.h>
+
+#include "mem/cache/tags/fa_lru.hh"
+#include "base/intmath.hh"
+#include "base/misc.hh"
+
+using namespace std;
+
+FALRU::FALRU(int _blkSize, int _size, int hit_latency)
+ : blkSize(_blkSize), size(_size),
+ numBlks(size/blkSize), hitLatency(hit_latency)
+{
+ if (!isPowerOf2(blkSize))
+ fatal("cache block size (in bytes) `%d' must be a power of two",
+ blkSize);
+ if (!(hitLatency > 0))
+ fatal("Access latency in cycles must be at least one cycle");
+ if (!isPowerOf2(size))
+ fatal("Cache Size must be power of 2 for now");
+
+ // Track all cache sizes from 128K up by powers of 2
+ numCaches = floorLog2(size) - 17;
+ if (numCaches >0){
+ cacheBoundaries = new FALRUBlk *[numCaches];
+ cacheMask = (1 << numCaches) - 1;
+ } else {
+ cacheMask = 0;
+ }
+
+ warmedUp = false;
+ warmupBound = size/blkSize;
+
+ blks = new FALRUBlk[numBlks];
+ head = &(blks[0]);
+ tail = &(blks[numBlks-1]);
+
+ head->prev = NULL;
+ head->next = &(blks[1]);
+ head->inCache = cacheMask;
+
+ tail->prev = &(blks[numBlks-2]);
+ tail->next = NULL;
+ tail->inCache = 0;
+
+ int index = (1 << 17) / blkSize;
+ int j = 0;
+ int flags = cacheMask;
+ for (int i = 1; i < numBlks-1; i++) {
+ blks[i].inCache = flags;
+ if (i == index - 1){
+ cacheBoundaries[j] = &(blks[i]);
+ flags &= ~ (1<<j);
+ ++j;
+ index = index << 1;
+ }
+ blks[i].prev = &(blks[i-1]);
+ blks[i].next = &(blks[i+1]);
+ blks[i].isTouched = false;
+ }
+ assert(j == numCaches);
+ assert(index == numBlks);
+ //assert(check());
+}
+
+void
+FALRU::regStats(const string &name)
+{
+ using namespace Stats;
+ BaseTags::regStats(name);
+ hits
+ .init(numCaches+1)
+ .name(name + ".falru_hits")
+ .desc("The number of hits in each cache size.")
+ ;
+ misses
+ .init(numCaches+1)
+ .name(name + ".falru_misses")
+ .desc("The number of misses in each cache size.")
+ ;
+ accesses
+ .name(name + ".falru_accesses")
+ .desc("The number of accesses to the FA LRU cache.")
+ ;
+
+ for (int i = 0; i < numCaches+1; ++i) {
+ stringstream size_str;
+ if (i < 3){
+ size_str << (1<<(i+7)) <<"K";
+ } else {
+ size_str << (1<<(i-3)) <<"M";
+ }
+
+ hits.subname(i, size_str.str());
+ hits.subdesc(i, "Hits in a " + size_str.str() +" cache");
+ misses.subname(i, size_str.str());
+ misses.subdesc(i, "Misses in a " + size_str.str() +" cache");
+ }
+}
+
+FALRUBlk *
+FALRU::hashLookup(Addr addr) const
+{
+ tagIterator iter = tagHash.find(addr);
+ if (iter != tagHash.end()) {
+ return (*iter).second;
+ }
+ return NULL;
+}
+
+bool
+FALRU::probe(Addr addr) const
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+ return blk && blk->tag == blkAddr && blk->isValid();
+}
+
+void
+FALRU::invalidateBlk(Addr addr)
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = (*tagHash.find(blkAddr)).second;
+ if (blk) {
+ assert(blk->tag == blkAddr);
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+FALRUBlk*
+FALRU::findBlock(Addr addr, int &lat, int *inCache)
+{
+ accesses++;
+ int tmp_in_cache = 0;
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ tmp_in_cache = blk->inCache;
+ for (int i = 0; i < numCaches; i++) {
+ if (1<<i & blk->inCache) {
+ hits[i]++;
+ } else {
+ misses[i]++;
+ }
+ }
+ hits[numCaches]++;
+ if (blk != head){
+ moveToHead(blk);
+ }
+ } else {
+ blk = NULL;
+ for (int i = 0; i < numCaches+1; ++i) {
+ misses[i]++;
+ }
+ }
+ if (inCache) {
+ *inCache = tmp_in_cache;
+ }
+
+ lat = hitLatency;
+ //assert(check());
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findBlock(Packet * &pkt, int &lat, int *inCache)
+{
+ Addr addr = pkt->getAddr();
+
+ accesses++;
+ int tmp_in_cache = 0;
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ tmp_in_cache = blk->inCache;
+ for (int i = 0; i < numCaches; i++) {
+ if (1<<i & blk->inCache) {
+ hits[i]++;
+ } else {
+ misses[i]++;
+ }
+ }
+ hits[numCaches]++;
+ if (blk != head){
+ moveToHead(blk);
+ }
+ } else {
+ blk = NULL;
+ for (int i = 0; i < numCaches+1; ++i) {
+ misses[i]++;
+ }
+ }
+ if (inCache) {
+ *inCache = tmp_in_cache;
+ }
+
+ lat = hitLatency;
+ //assert(check());
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findBlock(Addr addr) const
+{
+ Addr blkAddr = blkAlign(addr);
+ FALRUBlk* blk = hashLookup(blkAddr);
+
+ if (blk && blk->isValid()) {
+ assert(blk->tag == blkAddr);
+ } else {
+ blk = NULL;
+ }
+ return blk;
+}
+
+FALRUBlk*
+FALRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ FALRUBlk * blk = tail;
+ assert(blk->inCache == 0);
+ moveToHead(blk);
+ tagHash.erase(blk->tag);
+ tagHash[blkAlign(pkt->getAddr())] = blk;
+ if (blk->isValid()) {
+ replacements[0]++;
+ } else {
+ tagsInUse++;
+ blk->isTouched = true;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+ }
+ //assert(check());
+ return blk;
+}
+
+void
+FALRU::moveToHead(FALRUBlk *blk)
+{
+ int updateMask = blk->inCache ^ cacheMask;
+ for (int i = 0; i < numCaches; i++){
+ if ((1<<i) & updateMask) {
+ cacheBoundaries[i]->inCache &= ~(1<<i);
+ cacheBoundaries[i] = cacheBoundaries[i]->prev;
+ } else if (cacheBoundaries[i] == blk) {
+ cacheBoundaries[i] = blk->prev;
+ }
+ }
+ blk->inCache = cacheMask;
+ if (blk != head) {
+ if (blk == tail){
+ assert(blk->next == NULL);
+ tail = blk->prev;
+ tail->next = NULL;
+ } else {
+ blk->prev->next = blk->next;
+ blk->next->prev = blk->prev;
+ }
+ blk->next = head;
+ blk->prev = NULL;
+ head->prev = blk;
+ head = blk;
+ }
+}
+
+bool
+FALRU::check()
+{
+ FALRUBlk* blk = head;
+ int size = 0;
+ int boundary = 1<<17;
+ int j = 0;
+ int flags = cacheMask;
+ while (blk) {
+ size += blkSize;
+ if (blk->inCache != flags) {
+ return false;
+ }
+ if (size == boundary && blk != tail) {
+ if (cacheBoundaries[j] != blk) {
+ return false;
+ }
+ flags &=~(1 << j);
+ boundary = boundary<<1;
+ ++j;
+ }
+ blk = blk->next;
+ }
+ return true;
+}
diff --git a/src/mem/cache/tags/fa_lru.hh b/src/mem/cache/tags/fa_lru.hh
new file mode 100644
index 000000000..f9d4d7109
--- /dev/null
+++ b/src/mem/cache/tags/fa_lru.hh
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a fully associative LRU tag store.
+ */
+
+#ifndef __FA_LRU_HH__
+#define __FA_LRU_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh"
+#include "mem/packet.hh"
+#include "base/hashmap.hh"
+#include "mem/cache/tags/base_tags.hh"
+
+/**
+ * A fully associative cache block.
+ */
+class FALRUBlk : public CacheBlk
+{
+public:
+ /** The previous block in LRU order. */
+ FALRUBlk *prev;
+ /** The next block in LRU order. */
+ FALRUBlk *next;
+ /** Has this block been touched? */
+ bool isTouched;
+
+ /**
+ * A bit mask of the sizes of cache that this block is resident in.
+ * Each bit represents a power of 2 in MB size cache.
+ * If bit 0 is set, this block is in a 1MB cache
+ * If bit 2 is set, this block is in a 4MB cache, etc.
+ * There is one bit for each cache smaller than the full size (default
+ * 16MB).
+ */
+ int inCache;
+};
+
+/**
+ * A fully associative LRU cache. Keeps statistics for accesses to a number of
+ * cache sizes at once.
+ */
+class FALRU : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this class. */
+ typedef FALRUBlk BlkType;
+ /** Typedef a list of pointers to the local block type. */
+ typedef std::list<FALRUBlk*> BlkList;
+ protected:
+ /** The block size of the cache. */
+ const int blkSize;
+ /** The size of the cache. */
+ const int size;
+ /** The number of blocks in the cache. */
+ const int numBlks; // calculated internally
+ /** The hit latency of the cache. */
+ const int hitLatency;
+
+ /** Array of pointers to blocks at the cache size boundaries. */
+ FALRUBlk **cacheBoundaries;
+ /** A mask for the FALRUBlk::inCache bits. */
+ int cacheMask;
+ /** The number of different size caches being tracked. */
+ int numCaches;
+
+ /** The cache blocks. */
+ FALRUBlk *blks;
+
+ /** The MRU block. */
+ FALRUBlk *head;
+ /** The LRU block. */
+ FALRUBlk *tail;
+
+ /** Hash table type mapping addresses to cache block pointers. */
+ typedef m5::hash_map<Addr, FALRUBlk *, m5::hash<Addr> > hash_t;
+ /** Iterator into the address hash table. */
+ typedef hash_t::const_iterator tagIterator;
+
+ /** The address hash table. */
+ hash_t tagHash;
+
+ /**
+ * Find the cache block for the given address.
+ * @param addr The address to find.
+ * @return The cache block of the address, if any.
+ */
+ FALRUBlk * hashLookup(Addr addr) const;
+
+ /**
+ * Move a cache block to the MRU position.
+ * @param blk The block to promote.
+ */
+ void moveToHead(FALRUBlk *blk);
+
+ /**
+ * Check to make sure all the cache boundaries are still where they should
+ * be. Used for debugging.
+ * @return True if everything is correct.
+ */
+ bool check();
+
+ /**
+ * @defgroup FALRUStats Fully Associative LRU specific statistics
+ * The FA lru stack lets us track multiple cache sizes at once. These
+ * statistics track the hits and misses for different cache sizes.
+ * @{
+ */
+
+ /** Hits in each cache size >= 128K. */
+ Stats::Vector<> hits;
+ /** Misses in each cache size >= 128K. */
+ Stats::Vector<> misses;
+ /** Total number of accesses. */
+ Stats::Scalar<> accesses;
+
+ /**
+ * @}
+ */
+
+public:
+ /**
+ * Construct and initialize this cache tagstore.
+ * @param blkSize The block size of the cache.
+ * @param size The size of the cache.
+ * @param hit_latency The hit latency of the cache.
+ */
+ FALRU(int blkSize, int size, int hit_latency);
+
+ /**
+ * Register the stats for this object.
+ * @param name The name to prepend to the stats name.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Return true if the address is found in the cache.
+ * @param asid The address space ID.
+ * @param addr The address to look for.
+ * @return True if the address is in the cache.
+ */
+ bool probe(Addr addr) const;
+
+ /**
+ * Invalidate the cache block that contains the given addr.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Find the block in the cache and update the replacement data. Returns
+ * the access latency and the in cache flags as a side effect
+ * @param addr The address to look for.
+ * @param asid The address space ID.
+ * @param lat The latency of the access.
+ * @param inCache The FALRUBlk::inCache flags.
+ * @return Pointer to the cache block.
+ */
+ FALRUBlk* findBlock(Addr addr, int &lat, int *inCache = 0);
+
+ /**
+ * Find the block in the cache and update the replacement data. Returns
+ * the access latency and the in cache flags as a side effect
+ * @param pkt The req whose block to find
+ * @param lat The latency of the access.
+ * @param inCache The FALRUBlk::inCache flags.
+ * @return Pointer to the cache block.
+ */
+ FALRUBlk* findBlock(Packet * &pkt, int &lat, int *inCache = 0);
+
+ /**
+ * Find the block in the cache, do not update the replacement data.
+ * @param addr The address to look for.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block.
+ */
+ FALRUBlk* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ FALRUBlk* findReplacement(Packet * &pkt, PacketList & writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Return the hit latency of this cache.
+ * @return The hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Return the block size of this cache.
+ * @return The block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size of this cache, always the block size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The aligned address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)(blkSize-1));
+ }
+
+ /**
+ * Generate the tag from the addres. For fully associative this is just the
+ * block address.
+ * @param addr The address to get the tag from.
+ * @param blk ignored here
+ * @return The tag.
+ */
+ Addr extractTag(Addr addr, FALRUBlk *blk) const
+ {
+ return blkAlign(addr);
+ }
+
+ /**
+ * Return the set of an address. Only one set in a fully associative cache.
+ * @param addr The address to get the set from.
+ * @return 0.
+ */
+ int extractSet(Addr addr) const
+ {
+ return 0;
+ }
+
+ /**
+ * Calculate the block offset of an address.
+ * @param addr the address to get the offset of.
+ * @return the block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & (Addr)(blkSize-1));
+ }
+
+ /**
+ * Regenerate the block address from the tag and the set.
+ * @param tag The tag of the block.
+ * @param set The set the block belongs to.
+ * @return the block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, int set) const
+ {
+ return (tag);
+ }
+
+ /**
+ * Read the data out of the internal storage of a cache block. FALRU
+ * currently doesn't support data storage.
+ * @param blk The cache block to read.
+ * @param data The buffer to read the data into.
+ * @return The data from the cache block.
+ */
+ void readData(FALRUBlk *blk, uint8_t *data)
+ {
+ }
+
+ /**
+ * Write data into the internal storage of a cache block. FALRU
+ * currently doesn't support data storage.
+ * @param blk The cache block to be written.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(FALRUBlk *blk, uint8_t *data, int size,
+ PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Unimplemented. Perform a cache block copy from block aligned addresses.
+ * @param source The block aligned source address.
+ * @param dest The block aligned destination adddress.
+ * @param asid The address space ID.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Unimplemented.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+};
+
+#endif
diff --git a/src/mem/cache/tags/iic.cc b/src/mem/cache/tags/iic.cc
new file mode 100644
index 000000000..1377c8613
--- /dev/null
+++ b/src/mem/cache/tags/iic.cc
@@ -0,0 +1,877 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of the Indirect Index Cache tagstore.
+ */
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include <math.h>
+
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/tags/iic.hh"
+#include "base/intmath.hh"
+#include "sim/root.hh" // for curTick
+
+#include "base/trace.hh" // for DPRINTF
+
+
+using namespace std;
+
+/** Track the number of accesses to each cache set. */
+#define PROFILE_IIC 1
+
+IIC::IIC(IIC::Params &params) :
+ hashSets(params.numSets), blkSize(params.blkSize), assoc(params.assoc),
+ hitLatency(params.hitLatency), subSize(params.subblockSize),
+ numSub(blkSize/subSize),
+ trivialSize((floorLog2(params.size/subSize)*numSub)/8),
+ tagShift(floorLog2(blkSize)), blkMask(blkSize - 1),
+ subShift(floorLog2(subSize)), subMask(numSub - 1),
+ hashDelay(params.hashDelay),
+ numBlocks(params.size/subSize),
+ numTags(hashSets * assoc + params.size/blkSize -1),
+ numSecondary(params.size/blkSize),
+ tagNull(numTags),
+ primaryBound(hashSets * assoc)
+{
+ int i;
+
+ // Check parameters
+ if (blkSize < 4 || !isPowerOf2(blkSize)) {
+ fatal("Block size must be at least 4 and a power of 2");
+ }
+ if (hashSets <= 0 || !isPowerOf2(hashSets)) {
+ fatal("# of hashsets must be non-zero and a power of 2");
+ }
+ if (assoc <= 0) {
+ fatal("associativity must be greater than zero");
+ }
+ if (hitLatency <= 0) {
+ fatal("access latency must be greater than zero");
+ }
+ if (numSub*subSize != blkSize) {
+ fatal("blocksize must be evenly divisible by subblock size");
+ }
+
+ // debug stuff
+ freeSecond = numSecondary;
+
+ warmedUp = false;
+ warmupBound = params.size/blkSize;
+
+ // Replacement Policy Initialization
+ repl = params.rp;
+ repl->setIIC(this);
+
+ //last_miss_time = 0
+
+ // allocate data reference counters
+ dataReferenceCount = new int[numBlocks];
+ memset(dataReferenceCount, 0, numBlocks*sizeof(int));
+
+ // Allocate storage for both internal data and block fast access data.
+ // We allocate it as one large chunk to reduce overhead and to make
+ // deletion easier.
+ int data_index = 0;
+ dataStore = new uint8_t[(numBlocks + numTags) * blkSize];
+ dataBlks = new uint8_t*[numBlocks];
+ for (i = 0; i < numBlocks; ++i) {
+ dataBlks[i] = &dataStore[data_index];
+ freeDataBlock(i);
+ data_index += subSize;
+ }
+
+ assert(data_index == numBlocks * subSize);
+
+ // allocate and init tag store
+ tagStore = new IICTag[numTags];
+
+ int blkIndex = 0;
+ // allocate and init sets
+ sets = new IICSet[hashSets];
+ for (i = 0; i < hashSets; ++i) {
+ sets[i].assoc = assoc;
+ sets[i].tags = new IICTag*[assoc];
+ sets[i].chain_ptr = tagNull;
+
+ for (int j = 0; j < assoc; ++j) {
+ IICTag *tag = &tagStore[blkIndex++];
+ tag->chain_ptr = tagNull;
+ tag->data_ptr.resize(numSub);
+ tag->size = blkSize;
+ tag->trivialData = new uint8_t[trivialSize];
+ tag->numData = 0;
+ sets[i].tags[j] = tag;
+ tag->set = i;
+ tag->data = &dataStore[data_index];
+ data_index += blkSize;
+ }
+ }
+
+ assert(blkIndex == primaryBound);
+
+ for (i = primaryBound; i < tagNull; i++) {
+ tagStore[i].chain_ptr = i+1;
+ //setup data ptrs to subblocks
+ tagStore[i].data_ptr.resize(numSub);
+ tagStore[i].size = blkSize;
+ tagStore[i].trivialData = new uint8_t[trivialSize];
+ tagStore[i].numData = 0;
+ tagStore[i].set = 0;
+ tagStore[i].data = &dataStore[data_index];
+ data_index += blkSize;
+ }
+ freelist = primaryBound;
+}
+
+IIC::~IIC()
+{
+ delete [] dataReferenceCount;
+ delete [] dataStore;
+ delete [] tagStore;
+ delete [] sets;
+}
+
+/* register cache stats */
+void
+IIC::regStats(const string &name)
+{
+ using namespace Stats;
+
+ BaseTags::regStats(name);
+
+ hitHashDepth.init(0, 20, 1);
+ missHashDepth.init(0, 20, 1);
+ setAccess.init(0, hashSets, 1);
+
+ /** IIC Statistics */
+ hitHashDepth
+ .name(name + ".hit_hash_depth_dist")
+ .desc("Dist. of Hash lookup depths")
+ .flags(pdf)
+ ;
+
+ missHashDepth
+ .name(name + ".miss_hash_depth_dist")
+ .desc("Dist. of Hash lookup depths")
+ .flags(pdf)
+ ;
+
+ repl->regStats(name);
+
+ if (PROFILE_IIC)
+ setAccess
+ .name(name + ".set_access_dist")
+ .desc("Dist. of Accesses across sets")
+ .flags(pdf)
+ ;
+
+ missDepthTotal
+ .name(name + ".miss_depth_total")
+ .desc("Total of miss depths")
+ ;
+
+ hashMiss
+ .name(name + ".hash_miss")
+ .desc("Total of misses in hash table")
+ ;
+
+ hitDepthTotal
+ .name(name + ".hit_depth_total")
+ .desc("Total of hit depths")
+ ;
+
+ hashHit
+ .name(name + ".hash_hit")
+ .desc("Total of hites in hash table")
+ ;
+}
+
+// probe cache for presence of given block.
+bool
+IIC::probe(Addr addr) const
+{
+ return (findBlock(addr) != NULL);
+}
+
+IICTag*
+IIC::findBlock(Addr addr, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+ int set_lat;
+
+ unsigned long chain_ptr;
+
+ if (PROFILE_IIC)
+ setAccess.sample(set);
+
+ IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
+ set_lat = 1;
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
+ set_lat += secondary_depth;
+ // set depth for statistics fix this later!!! egh
+ sets[set].depth = set_lat;
+
+ if (tag_ptr != NULL) {
+ /* need to move tag into primary table */
+ // need to preserve chain: fix this egh
+ sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
+ tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
+ tag_ptr = sets[set].findTag(tag, chain_ptr);
+ assert(tag_ptr!=NULL);
+ }
+
+ }
+ set_lat = set_lat * hashDelay + hitLatency;
+ if (tag_ptr != NULL) {
+ // IIC replacement: if this is not the first element of
+ // list, reorder
+ sets[set].moveToHead(tag_ptr);
+
+ hitHashDepth.sample(sets[set].depth);
+ hashHit++;
+ hitDepthTotal += sets[set].depth;
+ tag_ptr->status |= BlkReferenced;
+ lat = set_lat;
+ if (tag_ptr->whenReady > curTick && tag_ptr->whenReady - curTick > set_lat) {
+ lat = tag_ptr->whenReady - curTick;
+ }
+
+ tag_ptr->refCount += 1;
+ }
+ else {
+ // fall through: cache block not found, not a hit...
+ missHashDepth.sample(sets[set].depth);
+ hashMiss++;
+ missDepthTotal += sets[set].depth;
+ lat = set_lat;
+ }
+ return tag_ptr;
+}
+
+IICTag*
+IIC::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+ int set_lat;
+
+ unsigned long chain_ptr;
+
+ if (PROFILE_IIC)
+ setAccess.sample(set);
+
+ IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
+ set_lat = 1;
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
+ set_lat += secondary_depth;
+ // set depth for statistics fix this later!!! egh
+ sets[set].depth = set_lat;
+
+ if (tag_ptr != NULL) {
+ /* need to move tag into primary table */
+ // need to preserve chain: fix this egh
+ sets[set].tags[assoc-1]->chain_ptr = tag_ptr->chain_ptr;
+ tagSwap(tag_ptr - tagStore, sets[set].tags[assoc-1] - tagStore);
+ tag_ptr = sets[set].findTag(tag, chain_ptr);
+ assert(tag_ptr!=NULL);
+ }
+
+ }
+ set_lat = set_lat * hashDelay + hitLatency;
+ if (tag_ptr != NULL) {
+ // IIC replacement: if this is not the first element of
+ // list, reorder
+ sets[set].moveToHead(tag_ptr);
+
+ hitHashDepth.sample(sets[set].depth);
+ hashHit++;
+ hitDepthTotal += sets[set].depth;
+ tag_ptr->status |= BlkReferenced;
+ lat = set_lat;
+ if (tag_ptr->whenReady > curTick && tag_ptr->whenReady - curTick > set_lat) {
+ lat = tag_ptr->whenReady - curTick;
+ }
+
+ tag_ptr->refCount += 1;
+ }
+ else {
+ // fall through: cache block not found, not a hit...
+ missHashDepth.sample(sets[set].depth);
+ hashMiss++;
+ missDepthTotal += sets[set].depth;
+ lat = set_lat;
+ }
+ return tag_ptr;
+}
+
+IICTag*
+IIC::findBlock(Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = hash(addr);
+
+ unsigned long chain_ptr;
+
+ IICTag *tag_ptr = sets[set].findTag(tag, chain_ptr);
+ if (tag_ptr == NULL && chain_ptr != tagNull) {
+ int secondary_depth;
+ tag_ptr = secondaryChain(tag, chain_ptr, &secondary_depth);
+ }
+ return tag_ptr;
+}
+
+
+IICTag*
+IIC::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ DPRINTF(IIC, "Finding Replacement for %x\n", pkt->getAddr());
+ unsigned set = hash(pkt->getAddr());
+ IICTag *tag_ptr;
+ unsigned long *tmp_data = new unsigned long[numSub];
+
+ // Get a enough subblocks for a full cache line
+ for (int i = 0; i < numSub; ++i){
+ tmp_data[i] = getFreeDataBlock(writebacks);
+ assert(dataReferenceCount[tmp_data[i]]==0);
+ }
+
+ tag_ptr = getFreeTag(set, writebacks);
+
+ tag_ptr->set = set;
+ for (int i=0; i< numSub; ++i) {
+ tag_ptr->data_ptr[i] = tmp_data[i];
+ dataReferenceCount[tag_ptr->data_ptr[i]]++;
+ }
+ tag_ptr->numData = numSub;
+ assert(tag_ptr - tagStore < primaryBound); // make sure it is in primary
+ tag_ptr->chain_ptr = tagNull;
+ sets[set].moveToHead(tag_ptr);
+ delete [] tmp_data;
+
+ list<unsigned long> tag_indexes;
+ repl->doAdvance(tag_indexes);
+ while (!tag_indexes.empty()) {
+ if (!tagStore[tag_indexes.front()].isCompressed()) {
+ compress_blocks.push_back(&tagStore[tag_indexes.front()]);
+ }
+ tag_indexes.pop_front();
+ }
+
+ tag_ptr->re = (void*)repl->add(tag_ptr-tagStore);
+
+ return tag_ptr;
+}
+
+void
+IIC::freeReplacementBlock(PacketList & writebacks)
+{
+ IICTag *tag_ptr;
+ unsigned long data_ptr;
+ /* consult replacement policy */
+ tag_ptr = &tagStore[repl->getRepl()];
+ assert(tag_ptr->isValid());
+
+ DPRINTF(Cache, "Replacing %x in IIC: %s\n",
+ regenerateBlkAddr(tag_ptr->tag,0),
+ tag_ptr->isModified() ? "writeback" : "clean");
+ /* write back replaced block data */
+ if (tag_ptr && (tag_ptr->isValid())) {
+ replacements[0]++;
+ totalRefs += tag_ptr->refCount;
+ ++sampledRefs;
+ tag_ptr->refCount = 0;
+
+ if (tag_ptr->isModified()) {
+/* Packet * writeback =
+ buildWritebackReq(regenerateBlkAddr(tag_ptr->tag, 0),
+ tag_ptr->req->asid, tag_ptr->xc, blkSize,
+ tag_ptr->data,
+ tag_ptr->size);
+*/
+ Request *writebackReq = new Request(regenerateBlkAddr(tag_ptr->tag, 0),
+ blkSize, 0);
+ Packet *writeback = new Packet(writebackReq, Packet::Writeback, -1);
+ writeback->allocate();
+ memcpy(writeback->getPtr<uint8_t>(), tag_ptr->data, blkSize);
+
+ writebacks.push_back(writeback);
+ }
+ }
+
+ // free the data blocks
+ for (int i = 0; i < tag_ptr->numData; ++i) {
+ data_ptr = tag_ptr->data_ptr[i];
+ assert(dataReferenceCount[data_ptr]>0);
+ if (--dataReferenceCount[data_ptr] == 0) {
+ freeDataBlock(data_ptr);
+ }
+ }
+ freeTag(tag_ptr);
+}
+
+unsigned long
+IIC::getFreeDataBlock(PacketList & writebacks)
+{
+ struct IICTag *tag_ptr;
+ unsigned long data_ptr;
+
+ tag_ptr = NULL;
+ /* find data block */
+ while (blkFreelist.empty()) {
+ freeReplacementBlock(writebacks);
+ }
+
+ data_ptr = blkFreelist.front();
+ blkFreelist.pop_front();
+ DPRINTF(IICMore,"Found free data at %d\n",data_ptr);
+ return data_ptr;
+}
+
+
+
+IICTag*
+IIC::getFreeTag(int set, PacketList & writebacks)
+{
+ unsigned long tag_index;
+ IICTag *tag_ptr;
+ // Add new tag
+ tag_ptr = sets[set].findFree();
+ // if no free in primary, and secondary exists
+ if (!tag_ptr && numSecondary) {
+ // need to spill a tag into secondary storage
+ while (freelist == tagNull) {
+ // get replacements until one is in secondary
+ freeReplacementBlock(writebacks);
+ }
+
+ tag_index = freelist;
+ freelist = tagStore[freelist].chain_ptr;
+ freeSecond--;
+
+ assert(tag_index != tagNull);
+ tagSwap(tag_index, sets[set].tags[assoc-1] - tagStore);
+ tagStore[tag_index].chain_ptr = sets[set].chain_ptr;
+ sets[set].chain_ptr = tag_index;
+
+ tag_ptr = sets[set].tags[assoc-1];
+ }
+ DPRINTF(IICMore,"Found free tag at %d\n",tag_ptr - tagStore);
+ tagsInUse++;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+
+ return tag_ptr;
+}
+
+void
+IIC::freeTag(IICTag *tag_ptr)
+{
+ unsigned long tag_index, tmp_index;
+ // Fix tag_ptr
+ if (tag_ptr) {
+ // we have a tag to clear
+ DPRINTF(IICMore,"Freeing Tag for %x\n",
+ regenerateBlkAddr(tag_ptr->tag,0));
+ tagsInUse--;
+ tag_ptr->status = 0;
+ tag_ptr->numData = 0;
+ tag_ptr->re = NULL;
+ tag_index = tag_ptr - tagStore;
+ if (tag_index >= primaryBound) {
+ // tag_ptr points to secondary store
+ assert(tag_index < tagNull); // remove this?? egh
+ if (tag_ptr->chain_ptr == tagNull) {
+ // need to fix chain list
+ unsigned tmp_set = hash(tag_ptr->tag << tagShift);
+ if (sets[tmp_set].chain_ptr == tag_index) {
+ sets[tmp_set].chain_ptr = tagNull;
+ } else {
+ tmp_index = sets[tmp_set].chain_ptr;
+ while (tmp_index != tagNull
+ && tagStore[tmp_index].chain_ptr != tag_index) {
+ tmp_index = tagStore[tmp_index].chain_ptr;
+ }
+ assert(tmp_index != tagNull);
+ tagStore[tmp_index].chain_ptr = tagNull;
+ }
+ tag_ptr->chain_ptr = freelist;
+ freelist = tag_index;
+ freeSecond++;
+ } else {
+ // copy next chained entry to this tag location
+ tmp_index = tag_ptr->chain_ptr;
+ tagSwap(tmp_index, tag_index);
+ tagStore[tmp_index].chain_ptr = freelist;
+ freelist = tmp_index;
+ freeSecond++;
+ }
+ } else {
+ // tag_ptr in primary hash table
+ assert(tag_index < primaryBound);
+ tag_ptr->status = 0;
+ unsigned tmp_set = hash(tag_ptr->tag << tagShift);
+ if (sets[tmp_set].chain_ptr != tagNull) { // collapse chain
+ tmp_index = sets[tmp_set].chain_ptr;
+ tagSwap(tag_index, tmp_index);
+ tagStore[tmp_index].chain_ptr = freelist;
+ freelist = tmp_index;
+ freeSecond++;
+ sets[tmp_set].chain_ptr = tag_ptr->chain_ptr;
+ sets[tmp_set].moveToTail(tag_ptr);
+ }
+ }
+ }
+}
+
+void
+IIC::freeDataBlock(unsigned long data_ptr)
+{
+ assert(dataReferenceCount[data_ptr] == 0);
+ DPRINTF(IICMore, "Freeing data at %d\n", data_ptr);
+ blkFreelist.push_front(data_ptr);
+}
+
+/** Use a simple modulo hash. */
+#define SIMPLE_HASH 0
+
+unsigned
+IIC::hash(Addr addr) const {
+#if SIMPLE_HASH
+ return extractTag(addr) % iic_hash_size;
+#else
+ Addr tag, mask, x, y;
+ tag = extractTag(addr);
+ mask = hashSets-1; /* assumes iic_hash_size is a power of 2 */
+ x = tag & mask;
+ y = (tag >> (int)(::log(hashSets)/::log(2))) & mask;
+ assert (x < hashSets && y < hashSets);
+ return x ^ y;
+#endif
+}
+
+
+void
+IICSet::moveToHead(IICTag *tag)
+{
+ if (tags[0] == tag)
+ return;
+
+ // write 'next' block into blks[i], moving up from MRU toward LRU
+ // until we overwrite the block we moved to head.
+
+ // start by setting up to write 'blk' into blks[0]
+ int i = 0;
+ IICTag *next = tag;
+
+ do {
+ assert(i < assoc);
+ // swap blks[i] and next
+ IICTag *tmp = tags[i];
+ tags[i] = next;
+ next = tmp;
+ ++i;
+ } while (next != tag);
+}
+
+void
+IICSet::moveToTail(IICTag *tag)
+{
+ if (tags[assoc-1] == tag)
+ return;
+
+ // write 'next' block into blks[i], moving up from MRU toward LRU
+ // until we overwrite the block we moved to head.
+
+ // start by setting up to write 'blk' into blks[0]
+ int i = assoc - 1;
+ IICTag *next = tag;
+
+ do {
+ assert(i >= 0);
+ // swap blks[i] and next
+ IICTag *tmp = tags[i];
+ tags[i] = next;
+ next = tmp;
+ --i;
+ } while (next != tag);
+}
+
+void
+IIC::tagSwap(unsigned long index1, unsigned long index2)
+{
+ DPRINTF(IIC,"Swapping tag[%d]=%x for tag[%d]=%x\n",index1,
+ tagStore[index1].tag<<tagShift, index2,
+ tagStore[index2].tag<<tagShift);
+ IICTag tmp_tag;
+ tmp_tag = tagStore[index1];
+ tagStore[index1] = tagStore[index2];
+ tagStore[index2] = tmp_tag;
+ if (tagStore[index1].isValid())
+ repl->fixTag(tagStore[index1].re, index2, index1);
+ if (tagStore[index2].isValid())
+ repl->fixTag(tagStore[index2].re, index1, index2);
+}
+
+
+IICTag *
+IIC::secondaryChain(Addr tag, unsigned long chain_ptr,
+ int *_depth) const
+{
+ int depth = 0;
+ while (chain_ptr != tagNull) {
+ DPRINTF(IIC,"Searching secondary at %d for %x\n", chain_ptr,
+ tag<<tagShift);
+ if (tagStore[chain_ptr].tag == tag &&
+ (tagStore[chain_ptr].isValid())) {
+ *_depth = depth;
+ return &tagStore[chain_ptr];
+ }
+ depth++;
+ chain_ptr = tagStore[chain_ptr].chain_ptr;
+ }
+ *_depth = depth;
+ return NULL;
+}
+
+void
+IIC::decompressBlock(unsigned long index)
+{
+ IICTag *tag_ptr = &tagStore[index];
+ if (tag_ptr->isCompressed()) {
+ // decompress the data here.
+ }
+}
+
+void
+IIC::compressBlock(unsigned long index)
+{
+ IICTag *tag_ptr = &tagStore[index];
+ if (!tag_ptr->isCompressed()) {
+ // Compress the data here.
+ }
+}
+
+void
+IIC::invalidateBlk(Addr addr)
+{
+ IICTag* tag_ptr = findBlock(addr);
+ if (tag_ptr) {
+ for (int i = 0; i < tag_ptr->numData; ++i) {
+ dataReferenceCount[tag_ptr->data_ptr[i]]--;
+ if (dataReferenceCount[tag_ptr->data_ptr[i]] == 0) {
+ freeDataBlock(tag_ptr->data_ptr[i]);
+ }
+ }
+ repl->removeEntry(tag_ptr->re);
+ freeTag(tag_ptr);
+ }
+}
+
+void
+IIC::readData(IICTag *blk, uint8_t *data){
+// assert(cache->doData());
+ assert(blk->size <= trivialSize || blk->numData > 0);
+ int data_size = blk->size;
+ if (data_size > trivialSize) {
+ for (int i = 0; i < blk->numData; ++i){
+ memcpy(data+i*subSize,
+ &(dataBlks[blk->data_ptr[i]][0]),
+ (data_size>subSize)?subSize:data_size);
+ data_size -= subSize;
+ }
+ } else {
+ memcpy(data,blk->trivialData,data_size);
+ }
+}
+
+void
+IIC::writeData(IICTag *blk, uint8_t *write_data, int size,
+ PacketList & writebacks){
+// assert(cache->doData());
+ assert(size < blkSize || !blk->isCompressed());
+ DPRINTF(IIC, "Writing %d bytes to %x\n", size,
+ blk->tag<<tagShift);
+ // Find the number of subblocks needed, (round up)
+ int num_subs = (size + (subSize -1))/subSize;
+ if (size <= trivialSize) {
+ num_subs = 0;
+ }
+ assert(num_subs <= numSub);
+ if (num_subs > blk->numData) {
+ // need to allocate more data blocks
+ for (int i = blk->numData; i < num_subs; ++i){
+ blk->data_ptr[i] = getFreeDataBlock(writebacks);
+ dataReferenceCount[blk->data_ptr[i]] += 1;
+ }
+ } else if (num_subs < blk->numData){
+ // can free data blocks
+ for (int i=num_subs; i < blk->numData; ++i){
+ // decrement reference count and compare to zero
+ /**
+ * @todo
+ * Make this work with copying.
+ */
+ if (--dataReferenceCount[blk->data_ptr[i]] == 0) {
+ freeDataBlock(blk->data_ptr[i]);
+ }
+ }
+ }
+
+ blk->numData = num_subs;
+ blk->size = size;
+ assert(size <= trivialSize || blk->numData > 0);
+ if (size > trivialSize){
+ for (int i = 0; i < blk->numData; ++i){
+ memcpy(&dataBlks[blk->data_ptr[i]][0], write_data + i*subSize,
+ (size>subSize)?subSize:size);
+ size -= subSize;
+ }
+ } else {
+ memcpy(blk->trivialData,write_data,size);
+ }
+}
+
+
+/**
+ * @todo This code can break if the src is evicted to get a tag for the dest.
+ */
+void
+IIC::doCopy(Addr source, Addr dest, PacketList &writebacks)
+{
+//Copy unsuported now
+#if 0
+ IICTag *dest_tag = findBlock(dest);
+
+ if (dest_tag) {
+ for (int i = 0; i < dest_tag->numData; ++i) {
+ if (--dataReferenceCount[dest_tag->data_ptr[i]] == 0) {
+ freeDataBlock(dest_tag->data_ptr[i]);
+ }
+ }
+ // Reset replacement entry
+ } else {
+ dest_tag = getFreeTag(hash(dest), writebacks);
+ dest_tag->re = (void*) repl->add(dest_tag - tagStore);
+ dest_tag->set = hash(dest);
+ dest_tag->tag = extractTag(dest);
+ dest_tag->status = BlkValid | BlkWritable;
+ }
+ // Find the source tag here since it might move if we need to find a
+ // tag for the destination.
+ IICTag *src_tag = findBlock(source);
+ assert(src_tag);
+ assert(!cache->doData() || src_tag->size <= trivialSize
+ || src_tag->numData > 0);
+ // point dest to source data and inc counter
+ for (int i = 0; i < src_tag->numData; ++i) {
+ dest_tag->data_ptr[i] = src_tag->data_ptr[i];
+ ++dataReferenceCount[dest_tag->data_ptr[i]];
+ }
+
+ // Maintain fast access data.
+ memcpy(dest_tag->data, src_tag->data, blkSize);
+
+ dest_tag->xc = src_tag->xc;
+ dest_tag->size = src_tag->size;
+ dest_tag->numData = src_tag->numData;
+ if (src_tag->numData == 0) {
+ // Data is stored in the trivial data, just copy it.
+ memcpy(dest_tag->trivialData, src_tag->trivialData, src_tag->size);
+ }
+
+ dest_tag->status |= BlkDirty;
+ if (dest_tag->size < blkSize) {
+ dest_tag->status |= BlkCompressed;
+ } else {
+ dest_tag->status &= ~BlkCompressed;
+ }
+#endif
+}
+
+void
+IIC::fixCopy(Packet * &pkt, PacketList &writebacks)
+{
+#if 0
+ // if reference counter is greater than 1, do copy
+ // else do write
+ Addr blk_addr = blkAlign(pkt->getAddr);
+ IICTag* blk = findBlock(blk_addr);
+
+ if (blk->numData > 0 && dataReferenceCount[blk->data_ptr[0]] != 1) {
+ // copy the data
+ // Mark the block as referenced so it doesn't get replaced.
+ blk->status |= BlkReferenced;
+ for (int i = 0; i < blk->numData; ++i){
+ unsigned long new_data = getFreeDataBlock(writebacks);
+ // Need to refresh pointer
+ /**
+ * @todo Remove this refetch once we change IIC to pointer based
+ */
+ blk = findBlock(blk_addr);
+ assert(blk);
+ if (cache->doData()) {
+ memcpy(&(dataBlks[new_data][0]),
+ &(dataBlks[blk->data_ptr[i]][0]),
+ subSize);
+ }
+ dataReferenceCount[blk->data_ptr[i]]--;
+ dataReferenceCount[new_data]++;
+ blk->data_ptr[i] = new_data;
+ }
+ }
+#endif
+}
+
+void
+IIC::cleanupRefs()
+{
+ for (int i = 0; i < numTags; ++i) {
+ if (tagStore[i].isValid()) {
+ totalRefs += tagStore[i].refCount;
+ ++sampledRefs;
+ }
+ }
+}
diff --git a/src/mem/cache/tags/iic.hh b/src/mem/cache/tags/iic.hh
new file mode 100644
index 000000000..2357bdce3
--- /dev/null
+++ b/src/mem/cache/tags/iic.hh
@@ -0,0 +1,574 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of the Indirect Index Cache (IIC) tags store.
+ */
+
+#ifndef __IIC_HH__
+#define __IIC_HH__
+
+#include <list>
+#include <vector>
+
+#include "mem/cache/cache_blk.hh"
+#include "mem/cache/tags/repl/repl.hh"
+#include "mem/packet.hh"
+#include "base/statistics.hh"
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache; // Forward declaration
+
+/**
+ * IIC cache blk.
+ */
+class IICTag : public CacheBlk
+{
+ public:
+ /**
+ * Copy the contents of the given IICTag into this one.
+ * @param rhs The tag to copy.
+ * @return const reference to this tag.
+ */
+ const IICTag& operator=(const IICTag& rhs)
+ {
+ CacheBlk::operator=(rhs);
+ chain_ptr = rhs.chain_ptr;
+ re = rhs.re;
+ set = rhs.set;
+ trivialData = rhs.trivialData;
+ numData = rhs.numData;
+ data_ptr.clear();
+ for (int i = 0; i < rhs.numData; ++i) {
+ data_ptr.push_back(rhs.data_ptr[i]);
+ }
+ return *this;
+ }
+
+ /** Hash chain pointer into secondary store. */
+ unsigned long chain_ptr;
+ /** Data array pointers for each subblock. */
+ std::vector<unsigned long> data_ptr;
+ /** Replacement Entry pointer. */
+ void *re;
+ /**
+ * An array to store small compressed data. Conceputally the same size
+ * as the unsused data array pointers.
+ */
+ uint8_t *trivialData;
+ /**
+ * The number of allocated subblocks.
+ */
+ int numData;
+};
+
+/**
+ * A hash set for the IIC primary lookup table.
+ */
+class IICSet{
+ public:
+ /** The associativity of the primary table. */
+ int assoc;
+
+ /** The number of hash chains followed when finding the last block. */
+ int depth;
+ /** The current number of blocks on the chain. */
+ int size;
+
+ /** Tag pointer into the secondary tag storage. */
+ unsigned long chain_ptr;
+
+ /** The LRU list of the primary table. MRU is at 0 index. */
+ IICTag ** tags;
+
+ /**
+ * Find the addr in this set, return the chain pointer to the secondary if
+ * it isn't found.
+ * @param asid The address space ID.
+ * @param tag The address to find.
+ * @param chain_ptr The chain pointer to start the search of the secondary
+ * @return Pointer to the tag, NULL if not found.
+ */
+ IICTag* findTag( Addr tag, unsigned long &chain_ptr)
+ {
+ depth = 1;
+ for (int i = 0; i < assoc; ++i) {
+ if (tags[i]->tag == tag && tags[i]->isValid()) {
+ return tags[i];
+ }
+ }
+ chain_ptr = this->chain_ptr;
+ return 0;
+ }
+
+ /**
+ * Find an usused tag in this set.
+ * @return Pointer to the unused tag, NULL if none are free.
+ */
+ IICTag* findFree()
+ {
+ for (int i = 0; i < assoc; ++i) {
+ if (!tags[i]->isValid()) {
+ return tags[i];
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Move a tag to the head of the LRU list
+ * @param tag The tag to move.
+ */
+ void moveToHead(IICTag *tag);
+
+ /**
+ * Move a tag to the tail (LRU) of the LRU list
+ * @param tag The tag to move.
+ */
+ void moveToTail(IICTag *tag);
+};
+
+/**
+ * The IIC tag store. This is a hardware-realizable, fully-associative tag
+ * store that uses software replacement, e.g. Gen.
+ */
+class IIC : public BaseTags
+{
+ public:
+ /** Typedef of the block type used in this class. */
+ typedef IICTag BlkType;
+ /** Typedef for list of pointers to the local block type. */
+ typedef std::list<IICTag*> BlkList;
+ protected:
+ /** The number of set in the primary table. */
+ const int hashSets;
+ /** The block size in bytes. */
+ const int blkSize;
+ /** The associativity of the primary table. */
+ const int assoc;
+ /** The base hit latency. */
+ const int hitLatency;
+ /** The subblock size, used for compression. */
+ const int subSize;
+
+ /** The number of subblocks */
+ const int numSub;
+ /** The number of bytes used by data pointers */
+ const int trivialSize;
+
+ /** The amount to shift address to get the tag. */
+ const int tagShift;
+ /** The mask to get block offset bits. */
+ const unsigned blkMask;
+
+ /** The amount to shift to get the subblock number. */
+ const int subShift;
+ /** The mask to get the correct subblock number. */
+ const unsigned subMask;
+
+ /** The latency of a hash lookup. */
+ const int hashDelay;
+ /** The number of data blocks. */
+ const int numBlocks;
+ /** The total number of tags in primary and secondary. */
+ const int numTags;
+ /** The number of tags in the secondary tag store. */
+ const int numSecondary;
+
+ /** The Null tag pointer. */
+ const int tagNull;
+ /** The last tag in the primary table. */
+ const int primaryBound;
+
+ /** All of the tags */
+ IICTag *tagStore;
+ /**
+ * Pointer to the head of the secondary freelist (maintained with chain
+ * pointers.
+ */
+ unsigned long freelist;
+ /**
+ * The data block freelist.
+ */
+ std::list<unsigned long> blkFreelist;
+
+ /** The primary table. */
+ IICSet *sets;
+
+ /** The replacement policy. */
+ Repl *repl;
+
+ /** An array of data reference counters. */
+ int *dataReferenceCount;
+
+ /** The data blocks. */
+ uint8_t *dataStore;
+
+ /** Storage for the fast access data of each cache block. */
+ uint8_t **dataBlks;
+
+ /**
+ * Count of the current number of free secondary tags.
+ * Used for debugging.
+ */
+ int freeSecond;
+
+ // IIC Statistics
+ /**
+ * @addtogroup IICStatistics IIC Statistics
+ * @{
+ */
+
+ /** Hash hit depth of cache hits. */
+ Stats::Distribution<> hitHashDepth;
+ /** Hash depth for cache misses. */
+ Stats::Distribution<> missHashDepth;
+ /** Count of accesses to each hash set. */
+ Stats::Distribution<> setAccess;
+
+ /** The total hash depth for every miss. */
+ Stats::Scalar<> missDepthTotal;
+ /** The total hash depth for all hits. */
+ Stats::Scalar<> hitDepthTotal;
+ /** The number of hash misses. */
+ Stats::Scalar<> hashMiss;
+ /** The number of hash hits. */
+ Stats::Scalar<> hashHit;
+ /** @} */
+
+ public:
+ /**
+ * Collection of parameters for the IIC.
+ */
+ class Params {
+ public:
+ /** The size in bytes of the cache. */
+ int size;
+ /** The number of sets in the primary table. */
+ int numSets;
+ /** The block size in bytes. */
+ int blkSize;
+ /** The associativity of the primary table. */
+ int assoc;
+ /** The number of cycles for each hash lookup. */
+ int hashDelay;
+ /** The number of cycles to read the data. */
+ int hitLatency;
+ /** The replacement policy. */
+ Repl *rp;
+ /** The subblock size in bytes. */
+ int subblockSize;
+ };
+
+ /**
+ * Construct and initialize this tag store.
+ * @param params The IIC parameters.
+ * @todo
+ * Should make a way to have less tags in the primary than blks in the
+ * cache. Also should be able to specify number of secondary blks.
+ */
+ IIC(Params &params);
+
+ /**
+ * Destructor.
+ */
+ virtual ~IIC();
+
+ /**
+ * Register the statistics.
+ * @param name The name to prepend to the statistic descriptions.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set Not needed for the iic.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, int set) {
+ return (((Addr)tag << tagShift));
+ }
+
+ /**
+ * Return the block size.
+ * @return The block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size.
+ * @return The subblock size.
+ */
+ int getSubBlockSize()
+ {
+ return subSize;
+ }
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Generate the tag from the address.
+ * @param addr The address to a get a tag for.
+ * @param blk Ignored here.
+ * @return the tag.
+ */
+ Addr extractTag(Addr addr, IICTag *blk) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Generate the tag from the address.
+ * @param addr The address to a get a tag for.
+ * @return the tag.
+ */
+ Addr extractTag(Addr addr) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Return the set, always 0 for IIC.
+ * @return 0.
+ */
+ int extractSet(Addr addr) const
+ {
+ return 0;
+ }
+
+ /**
+ * Get the block offset of an address.
+ * @param addr The address to get the offset of.
+ * @return the block offset of the address.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & blkMask);
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The block address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)blkMask);
+ }
+
+ /**
+ * Check for the address in the tagstore.
+ * @param asid The address space ID.
+ * @param addr The address to find.
+ * @return true if it is found.
+ */
+ bool probe(Addr addr) const;
+
+ /**
+ * Swap the position of two tags.
+ * @param index1 The first tag location.
+ * @param index2 The second tag location.
+ */
+ void tagSwap(unsigned long index1, unsigned long index2);
+
+ /**
+ * Clear the reference bit of the tag and return its old value.
+ * @param index The pointer of the tag to manipulate.
+ * @return The previous state of the reference bit.
+ */
+ bool clearRef(unsigned long index)
+ {
+ bool tmp = tagStore[index].isReferenced();
+ tagStore[index].status &= ~BlkReferenced;
+ return tmp;
+ }
+
+ /**
+ * Decompress a block if it is compressed.
+ * @param index The tag store index for the block to uncompress.
+ */
+ void decompressBlock(unsigned long index);
+
+ /**
+ * Try and compress a block if it is not already compressed.
+ * @param index The tag store index for the block to compress.
+ */
+ void compressBlock(unsigned long index);
+
+ /**
+ * Invalidate the block containing the address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Find the block and update the replacement data. This call also returns
+ * the access latency as a side effect.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param lat The access latency.
+ * @return A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Addr addr, int &lat);
+
+ /**
+ * Find the block and update the replacement data. This call also returns
+ * the access latency as a side effect.
+ * @param pkt The req whose block to find
+ * @param lat The access latency.
+ * @return A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Find the block, do not update the replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return A pointer to the block found, if any.
+ */
+ IICTag* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ IICTag* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Read the data from the internal storage of the given cache block.
+ * @param blk The block to read the data from.
+ * @param data The buffer to read the data into.
+ * @return The cache block's data.
+ */
+ void readData(IICTag *blk, uint8_t *data);
+
+ /**
+ * Write the data into the internal storage of the given cache block.
+ * @param blk The block to write to.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(IICTag *blk, uint8_t *data, int size,
+ PacketList & writebacks);
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks);
+
+ /**
+ * If a block is currently marked copy on write, copy it before writing.
+ * @param pkt The write request.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks);
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+private:
+ /**
+ * Return the hash of the address.
+ * @param addr The address to hash.
+ * @return the hash of the address.
+ */
+ unsigned hash(Addr addr) const;
+
+ /**
+ * Search for a block in the secondary tag store. Returns the number of
+ * hash lookups as a side effect.
+ * @param asid The address space ID.
+ * @param tag The tag to match.
+ * @param chain_ptr The first entry to search.
+ * @param depth The number of hash lookups made while searching.
+ * @return A pointer to the block if found.
+ */
+ IICTag *secondaryChain(Addr tag, unsigned long chain_ptr,
+ int *depth) const;
+
+ /**
+ * Free the resources associated with the next replacement block.
+ * @param writebacks A list of any writebacks to perform.
+ */
+ void freeReplacementBlock(PacketList & writebacks);
+
+ /**
+ * Return the pointer to a free data block.
+ * @param writebacks A list of any writebacks to perform.
+ * @return A pointer to a free data block.
+ */
+ unsigned long getFreeDataBlock(PacketList & writebacks);
+
+ /**
+ * Get a free tag in the given hash set.
+ * @param set The hash set to search.
+ * @param writebacks A list of any writebacks to perform.
+ * @return a pointer to a free tag.
+ */
+ IICTag* getFreeTag(int set, PacketList & writebacks);
+
+ /**
+ * Free the resources associated with the given tag.
+ * @param tag_ptr The tag to free.
+ */
+ void freeTag(IICTag *tag_ptr);
+
+ /**
+ * Mark the given data block as being available.
+ * @param data_ptr The data block to free.
+ */
+ void freeDataBlock(unsigned long data_ptr);
+};
+#endif // __IIC_HH__
+
diff --git a/src/mem/cache/tags/lru.cc b/src/mem/cache/tags/lru.cc
new file mode 100644
index 000000000..976bbeff2
--- /dev/null
+++ b/src/mem/cache/tags/lru.cc
@@ -0,0 +1,307 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Definitions of LRU tag store.
+ */
+
+#include <string>
+
+#include "mem/cache/base_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/lru.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+LRUBlk*
+CacheSet::findBlk(Addr tag) const
+{
+ for (int i = 0; i < assoc; ++i) {
+ if (blks[i]->tag == tag && blks[i]->isValid()) {
+ return blks[i];
+ }
+ }
+ return 0;
+}
+
+
+void
+CacheSet::moveToHead(LRUBlk *blk)
+{
+ // nothing to do if blk is already head
+ if (blks[0] == blk)
+ return;
+
+ // write 'next' block into blks[i], moving up from MRU toward LRU
+ // until we overwrite the block we moved to head.
+
+ // start by setting up to write 'blk' into blks[0]
+ int i = 0;
+ LRUBlk *next = blk;
+
+ do {
+ assert(i < assoc);
+ // swap blks[i] and next
+ LRUBlk *tmp = blks[i];
+ blks[i] = next;
+ next = tmp;
+ ++i;
+ } while (next != blk);
+}
+
+
+// create and initialize a LRU/MRU cache structure
+LRU::LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency) :
+ numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency)
+{
+ // Check parameters
+ if (blkSize < 4 || !isPowerOf2(blkSize)) {
+ fatal("Block size must be at least 4 and a power of 2");
+ }
+ if (numSets <= 0 || !isPowerOf2(numSets)) {
+ fatal("# of sets must be non-zero and a power of 2");
+ }
+ if (assoc <= 0) {
+ fatal("associativity must be greater than zero");
+ }
+ if (hitLatency <= 0) {
+ fatal("access latency must be greater than zero");
+ }
+
+ LRUBlk *blk;
+ int i, j, blkIndex;
+
+ blkMask = blkSize - 1;
+ setShift = floorLog2(blkSize);
+ setMask = numSets - 1;
+ tagShift = setShift + floorLog2(numSets);
+ warmedUp = false;
+ /** @todo Make warmup percentage a parameter. */
+ warmupBound = numSets * assoc;
+
+ sets = new CacheSet[numSets];
+ blks = new LRUBlk[numSets * assoc];
+ // allocate data storage in one big chunk
+ dataBlks = new uint8_t[numSets*assoc*blkSize];
+
+ blkIndex = 0; // index into blks array
+ for (i = 0; i < numSets; ++i) {
+ sets[i].assoc = assoc;
+
+ sets[i].blks = new LRUBlk*[assoc];
+
+ // link in the data blocks
+ for (j = 0; j < assoc; ++j) {
+ // locate next cache block
+ blk = &blks[blkIndex];
+ blk->data = &dataBlks[blkSize*blkIndex];
+ ++blkIndex;
+
+ // invalidate new cache block
+ blk->status = 0;
+
+ //EGH Fix Me : do we need to initialize blk?
+
+ // Setting the tag to j is just to prevent long chains in the hash
+ // table; won't matter because the block is invalid
+ blk->tag = j;
+ blk->whenReady = 0;
+ blk->isTouched = false;
+ blk->size = blkSize;
+ sets[i].blks[j]=blk;
+ blk->set = i;
+ }
+ }
+}
+
+LRU::~LRU()
+{
+ delete [] dataBlks;
+ delete [] blks;
+ delete [] sets;
+}
+
+// probe cache for presence of given block.
+bool
+LRU::probe(Addr addr) const
+{
+ // return(findBlock(Read, addr, asid) != 0);
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ LRUBlk *blk = sets[myset].findBlk(tag);
+
+ return (blk != NULL); // true if in cache
+}
+
+LRUBlk*
+LRU::findBlock(Addr addr, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(tag);
+ lat = hitLatency;
+ if (blk != NULL) {
+ // move this block to head of the MRU list
+ sets[set].moveToHead(blk);
+ if (blk->whenReady > curTick
+ && blk->whenReady - curTick > hitLatency) {
+ lat = blk->whenReady - curTick;
+ }
+ blk->refCount += 1;
+ }
+
+ return blk;
+}
+
+LRUBlk*
+LRU::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(tag);
+ lat = hitLatency;
+ if (blk != NULL) {
+ // move this block to head of the MRU list
+ sets[set].moveToHead(blk);
+ if (blk->whenReady > curTick
+ && blk->whenReady - curTick > hitLatency) {
+ lat = blk->whenReady - curTick;
+ }
+ blk->refCount += 1;
+ }
+
+ return blk;
+}
+
+LRUBlk*
+LRU::findBlock(Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ LRUBlk *blk = sets[set].findBlk(tag);
+ return blk;
+}
+
+LRUBlk*
+LRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+ // grab a replacement candidate
+ LRUBlk *blk = sets[set].blks[assoc-1];
+ sets[set].moveToHead(blk);
+ if (blk->isValid()) {
+ replacements[0]++;
+ totalRefs += blk->refCount;
+ ++sampledRefs;
+ blk->refCount = 0;
+ } else if (!blk->isTouched) {
+ tagsInUse++;
+ blk->isTouched = true;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+ }
+
+ return blk;
+}
+
+void
+LRU::invalidateBlk(Addr addr)
+{
+ LRUBlk *blk = findBlock(addr);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+void
+LRU::doCopy(Addr source, Addr dest, PacketList &writebacks)
+{
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ LRUBlk *source_blk = findBlock(source);
+ assert(source_blk);
+ LRUBlk *dest_blk = findBlock(dest);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Request *search = new Request(dest,1,0);
+ Packet * pkt = new Packet(search, Packet::ReadReq, -1);
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+/* pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->req->asid,
+ dest_blk->xc,
+ blkSize,
+ dest_blk->data,
+ dest_blk->size);
+*/
+ Request *writebackReq = new Request(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ blkSize, 0);
+ Packet *writeback = new Packet(writebackReq, Packet::Writeback, -1);
+ writeback->allocate();
+ memcpy(writeback->getPtr<uint8_t>(),dest_blk->data, blkSize);
+ writebacks.push_back(writeback);
+ }
+ dest_blk->tag = extractTag(dest);
+ delete search;
+ delete pkt;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+}
+
+void
+LRU::cleanupRefs()
+{
+ for (int i = 0; i < numSets*assoc; ++i) {
+ if (blks[i].isValid()) {
+ totalRefs += blks[i].refCount;
+ ++sampledRefs;
+ }
+ }
+}
diff --git a/src/mem/cache/tags/lru.hh b/src/mem/cache/tags/lru.hh
new file mode 100644
index 000000000..a3a56a0e6
--- /dev/null
+++ b/src/mem/cache/tags/lru.hh
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declaration of a LRU tag store.
+ */
+
+#ifndef __LRU_HH__
+#define __LRU_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh" // base class
+#include "mem/packet.hh" // for inlined functions
+#include <assert.h>
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache;
+
+/**
+ * LRU cache block.
+ */
+class LRUBlk : public CacheBlk {
+ public:
+ /** Has this block been touched? Used to aid calculation of warmup time. */
+ bool isTouched;
+};
+
+/**
+ * An associative set of cache blocks.
+ */
+class CacheSet
+{
+ public:
+ /** The associativity of this set. */
+ int assoc;
+
+ /** Cache blocks in this set, maintained in LRU order 0 = MRU. */
+ LRUBlk **blks;
+
+ /**
+ * Find a block matching the tag in this set.
+ * @param asid The address space ID.
+ * @param tag The Tag to find.
+ * @return Pointer to the block if found.
+ */
+ LRUBlk* findBlk(Addr tag) const;
+
+ /**
+ * Move the given block to the head of the list.
+ * @param blk The block to move.
+ */
+ void moveToHead(LRUBlk *blk);
+};
+
+/**
+ * A LRU cache tag store.
+ */
+class LRU : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this tag store. */
+ typedef LRUBlk BlkType;
+ /** Typedef for a list of pointers to the local block class. */
+ typedef std::list<LRUBlk*> BlkList;
+ protected:
+ /** The number of sets in the cache. */
+ const int numSets;
+ /** The number of bytes in a block. */
+ const int blkSize;
+ /** The associativity of the cache. */
+ const int assoc;
+ /** The hit latency. */
+ const int hitLatency;
+
+ /** The cache sets. */
+ CacheSet *sets;
+
+ /** The cache blocks. */
+ LRUBlk *blks;
+ /** The data blocks, 1 per cache block. */
+ uint8_t *dataBlks;
+
+ /** The amount to shift the address to get the set. */
+ int setShift;
+ /** The amount to shift the address to get the tag. */
+ int tagShift;
+ /** Mask out all bits that aren't part of the set index. */
+ unsigned setMask;
+ /** Mask out all bits that aren't part of the block offset. */
+ unsigned blkMask;
+
+public:
+ /**
+ * Construct and initialize this tag store.
+ * @param _numSets The number of sets in the cache.
+ * @param _blkSize The number of bytes in a block.
+ * @param _assoc The associativity of the cache.
+ * @param _hit_latency The latency in cycles for a hit.
+ */
+ LRU(int _numSets, int _blkSize, int _assoc, int _hit_latency);
+
+ /**
+ * Destructor
+ */
+ virtual ~LRU();
+
+ /**
+ * Return the block size.
+ * @return the block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size. In the case of LRU it is always the block
+ * size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Search for the address in the cache.
+ * @param asid The address space ID.
+ * @param addr The address to find.
+ * @return True if the address is in the cache.
+ */
+ bool probe(Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param pkt The request whose block to find.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ LRUBlk* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ LRUBlk* findBlock(Addr addr, int &lat);
+
+ /**
+ * Finds the given address in the cache, do not update replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block if found.
+ */
+ LRUBlk* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ LRUBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, LRUBlk *blk) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Calculate the set index from the address.
+ * @param addr The address to get the set from.
+ * @return The set index of the address.
+ */
+ int extractSet(Addr addr) const
+ {
+ return ((addr >> setShift) & setMask);
+ }
+
+ /**
+ * Get the block offset from an address.
+ * @param addr The address to get the offset of.
+ * @return The block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & blkMask);
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The block address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)blkMask);
+ }
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set The set of the block.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, unsigned set) const
+ {
+ return ((tag << tagShift) | ((Addr)set << setShift));
+ }
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Read the data out of the internal storage of the given cache block.
+ * @param blk The cache block to read.
+ * @param data The buffer to read the data into.
+ * @return The cache block's data.
+ */
+ void readData(LRUBlk *blk, uint8_t *data)
+ {
+ memcpy(data, blk->data, blk->size);
+ }
+
+ /**
+ * Write data into the internal storage of the given cache block. Since in
+ * LRU does not store data differently this just needs to update the size.
+ * @param blk The cache block to write.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(LRUBlk *blk, uint8_t *data, int size,
+ PacketList & writebacks)
+ {
+ assert(size <= blkSize);
+ blk->size = size;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+};
+
+#endif
diff --git a/src/mem/cache/tags/repl/gen.cc b/src/mem/cache/tags/repl/gen.cc
new file mode 100644
index 000000000..ec1c2aaf3
--- /dev/null
+++ b/src/mem/cache/tags/repl/gen.cc
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Definitions of the Generational replacement policy.
+ */
+
+#include <string>
+
+#include "base/misc.hh"
+#include "mem/cache/tags/iic.hh"
+#include "mem/cache/tags/repl/gen.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+
+using namespace std;
+
+GenRepl::GenRepl(const string &_name,
+ int _num_pools,
+ int _fresh_res,
+ int _pool_res) // fix this, should be set by cache
+ : Repl(_name)
+{
+ num_pools = _num_pools;
+ fresh_res = _fresh_res;
+ pool_res = _pool_res;
+ num_entries = 0;
+ num_pool_entries = 0;
+ misses = 0;
+ pools = new GenPool[num_pools+1];
+}
+
+GenRepl::~GenRepl()
+{
+ delete [] pools;
+}
+
+unsigned long
+GenRepl::getRepl()
+{
+ unsigned long tmp;
+ GenReplEntry *re;
+ int i;
+ int num_seen = 0;
+ if (!(num_pool_entries>0)) {
+ fatal("No blks available to replace");
+ }
+ num_entries--;
+ num_pool_entries--;
+ for (i = 0; i < num_pools; i++) {
+ while ((re = pools[i].pop())) {
+ num_seen++;
+ // Remove invalidated entries
+ if (!re->valid) {
+ delete re;
+ continue;
+ }
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ }
+ else {
+ tmp = re->tag_ptr;
+ delete re;
+
+ repl_pool.sample(i);
+
+ return tmp;
+ }
+ }
+ }
+ fatal("No replacement found");
+ return 0xffffffff;
+}
+
+unsigned long *
+GenRepl::getNRepl(int n)
+{
+ unsigned long *tmp;
+ GenReplEntry *re;
+ int i;
+ if (!(num_pool_entries>(n-1))) {
+ fatal("Not enough blks available to replace");
+ }
+ num_entries -= n;
+ num_pool_entries -= n;
+ tmp = new unsigned long[n]; /* array of cache_blk pointers */
+ int blk_index = 0;
+ for (i = 0; i < num_pools && blk_index < n; i++) {
+ while (blk_index < n && (re = pools[i].pop())) {
+ // Remove invalidated entries
+ if (!re->valid) {
+ delete re;
+ continue;
+ }
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ }
+ else {
+ tmp[blk_index] = re->tag_ptr;
+ blk_index++;
+ delete re;
+ repl_pool.sample(i);
+ }
+ }
+ }
+ if (blk_index >= n)
+ return tmp;
+ /* search the fresh pool */
+
+ fatal("No N replacements found");
+ return NULL;
+}
+
+void
+GenRepl::doAdvance(std::list<unsigned long> &demoted)
+{
+ int i;
+ int num_seen = 0;
+ GenReplEntry *re;
+ misses++;
+ for (i=0; i<num_pools; i++) {
+ while (misses-pools[i].oldest > pool_res && (re = pools[i].pop())!=NULL) {
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[(((i+1)== num_pools)? i :i+1)].push(re, misses);
+ /** @todo Not really demoted, but use it for now. */
+ demoted.push_back(re->tag_ptr);
+ advance_pool.sample(i);
+ }
+ else {
+ pools[(((i-1)<0)?i:i-1)].push(re, misses);
+ demoted.push_back(re->tag_ptr);
+ demote_pool.sample(i);
+ }
+ }
+ num_seen += pools[i].size;
+ }
+ while (misses-pools[num_pools].oldest > fresh_res
+ && (re = pools[num_pools].pop())!=NULL) {
+ num_pool_entries++;
+ if (iic->clearRef(re->tag_ptr)) {
+ pools[num_pools/2].push(re, misses);
+ /** @todo Not really demoted, but use it for now. */
+ demoted.push_back(re->tag_ptr);
+ advance_pool.sample(num_pools);
+ }
+ else {
+ pools[num_pools/2-1].push(re, misses);
+ demoted.push_back(re->tag_ptr);
+ demote_pool.sample(num_pools);
+ }
+ }
+}
+
+void*
+GenRepl::add(unsigned long tag_index)
+{
+ GenReplEntry *re = new GenReplEntry;
+ re->tag_ptr = tag_index;
+ re->valid = true;
+ pools[num_pools].push(re, misses);
+ num_entries++;
+ return (void*)re;
+}
+
+void
+GenRepl::regStats(const string name)
+{
+ using namespace Stats;
+
+ /** GEN statistics */
+ repl_pool
+ .init(0, 16, 1)
+ .name(name + ".repl_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+
+ advance_pool
+ .init(0, 16, 1)
+ .name(name + ".advance_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+
+ demote_pool
+ .init(0, 16, 1)
+ .name(name + ".demote_pool_dist")
+ .desc("Dist. of Repl. across pools")
+ .flags(pdf)
+ ;
+}
+
+int
+GenRepl::fixTag(void* _re, unsigned long old_index, unsigned long new_index)
+{
+ GenReplEntry *re = (GenReplEntry*)_re;
+ assert(re->valid);
+ if (re->tag_ptr == old_index) {
+ re->tag_ptr = new_index;
+ return 1;
+ }
+ fatal("Repl entry: tag ptrs do not match");
+ return 0;
+}
+
+bool
+GenRepl::findTagPtr(unsigned long index)
+{
+ for (int i = 0; i < num_pools + 1; ++i) {
+ list<GenReplEntry*>::const_iterator iter = pools[i].entries.begin();
+ list<GenReplEntry*>::const_iterator end = pools[i].entries.end();
+ for (; iter != end; ++iter) {
+ if ((*iter)->valid && (*iter)->tag_ptr == index) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(GenRepl)
+
+ Param<int> num_pools;
+ Param<int> fresh_res;
+ Param<int> pool_res;
+
+END_DECLARE_SIM_OBJECT_PARAMS(GenRepl)
+
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(GenRepl)
+
+ INIT_PARAM(num_pools, "capacity in bytes"),
+ INIT_PARAM(fresh_res, "associativity"),
+ INIT_PARAM(pool_res, "block size in bytes")
+
+END_INIT_SIM_OBJECT_PARAMS(GenRepl)
+
+
+CREATE_SIM_OBJECT(GenRepl)
+{
+ return new GenRepl(getInstanceName(), num_pools, fresh_res, pool_res);
+}
+
+REGISTER_SIM_OBJECT("GenRepl", GenRepl)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/tags/repl/gen.hh b/src/mem/cache/tags/repl/gen.hh
new file mode 100644
index 000000000..c1ceb3f4e
--- /dev/null
+++ b/src/mem/cache/tags/repl/gen.hh
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ */
+
+/**
+ * @file
+ * Declarations of generational replacement policy
+ */
+
+#ifndef ___GEN_HH__
+#define __GEN_HH__
+
+#include <list>
+
+#include "base/statistics.hh"
+#include "mem/cache/tags/repl/repl.hh"
+
+/**
+ * Generational Replacement entry.
+ */
+class GenReplEntry
+{
+ public:
+ /** Valid flag, used to quickly invalidate bogus entries. */
+ bool valid;
+ /** The difference between this entry and the previous in the pool. */
+ int delta;
+ /** Pointer to the corresponding tag in the IIC. */
+ unsigned long tag_ptr;
+};
+
+/**
+ * Generational replacement pool
+ */
+class GenPool
+{
+ public:
+ /** The time the last entry was added. */
+ Tick newest;
+ /** The time the oldest entry was added. */
+ Tick oldest;
+ /** List of the replacement entries in this pool. */
+ std::list<GenReplEntry*> entries;
+
+ /** The number of entries in this pool. */
+ int size;
+
+ /**
+ * Simple constructor.
+ */
+ GenPool() {
+ newest = 0;
+ oldest = 0;
+ size = 0;
+ }
+
+ /**
+ * Add an entry to this pool.
+ * @param re The entry to add.
+ * @param now The current time.
+ */
+ void push(GenReplEntry *re, Tick now) {
+ ++size;
+ if (!entries.empty()) {
+ re->delta = now - newest;
+ newest = now;
+ } else {
+ re->delta = 0;
+ newest = oldest = now;
+ }
+ entries.push_back(re);
+ }
+
+ /**
+ * Remove an entry from the pool.
+ * @return The entry at the front of the list.
+ */
+ GenReplEntry* pop() {
+ GenReplEntry *tmp = NULL;
+ if (!entries.empty()) {
+ --size;
+ tmp = entries.front();
+ entries.pop_front();
+ oldest += tmp->delta;
+ }
+ return tmp;
+ }
+
+ /**
+ * Return the entry at the front of the list.
+ * @return the entry at the front of the list.
+ */
+ GenReplEntry* top() {
+ return entries.front();
+ }
+
+ /**
+ * Destructor.
+ */
+ ~GenPool() {
+ while (!entries.empty()) {
+ GenReplEntry *tmp = entries.front();
+ entries.pop_front();
+ delete tmp;
+ }
+ }
+};
+
+/**
+ * Generational replacement policy for use with the IIC.
+ * @todo update to use STL and for efficiency
+ */
+class GenRepl : public Repl
+{
+ public:
+ /** The array of pools. */
+ GenPool *pools;
+ /** The number of pools. */
+ int num_pools;
+ /** The amount of time to stay in the fresh pool. */
+ int fresh_res;
+ /** The amount of time to stay in the normal pools. */
+ int pool_res;
+ /** The maximum number of entries */
+ int num_entries;
+ /** The number of entries currently in the pools. */
+ int num_pool_entries;
+ /** The number of misses. Used as the internal time. */
+ Tick misses;
+
+ // Statistics
+
+ /**
+ * @addtogroup CacheStatistics
+ * @{
+ */
+ /** The number of replacements from each pool. */
+ Stats::Distribution<> repl_pool;
+ /** The number of advances out of each pool. */
+ Stats::Distribution<> advance_pool;
+ /** The number of demotions from each pool. */
+ Stats::Distribution<> demote_pool;
+ /**
+ * @}
+ */
+
+ /**
+ * Constructs and initializes this replacement policy.
+ * @param name The name of the policy.
+ * @param num_pools The number of pools to use.
+ * @param fresh_res The amount of time to wait in the fresh pool.
+ * @param pool_res The amount of time to wait in the normal pools.
+ */
+ GenRepl(const std::string &name, int num_pools,
+ int fresh_res, int pool_res);
+
+ /**
+ * Destructor.
+ */
+ ~GenRepl();
+
+ /**
+ * Returns the tag pointer of the cache block to replace.
+ * @return The tag to replace.
+ */
+ virtual unsigned long getRepl();
+
+ /**
+ * Return an array of N tag pointers to replace.
+ * @param n The number of tag pointer to return.
+ * @return An array of tag pointers to replace.
+ */
+ virtual unsigned long *getNRepl(int n);
+
+ /**
+ * Update replacement data
+ */
+ virtual void doAdvance(std::list<unsigned long> &demoted);
+
+ /**
+ * Add a tag to the replacement policy and return a pointer to the
+ * replacement entry.
+ * @param tag_index The tag to add.
+ * @return The replacement entry.
+ */
+ virtual void* add(unsigned long tag_index);
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to statistic descriptions.
+ */
+ virtual void regStats(const std::string name);
+
+ /**
+ * Update the tag pointer to when the tag moves.
+ * @param re The replacement entry of the tag.
+ * @param old_index The old tag pointer.
+ * @param new_index The new tag pointer.
+ * @return 1 if successful, 0 otherwise.
+ */
+ virtual int fixTag(void *re, unsigned long old_index,
+ unsigned long new_index);
+
+ /**
+ * Remove this entry from the replacement policy.
+ * @param re The replacement entry to remove
+ */
+ virtual void removeEntry(void *re)
+ {
+ ((GenReplEntry*)re)->valid = false;
+ }
+
+ protected:
+ /**
+ * Debug function to verify that there is only one repl entry per tag.
+ * @param index The tag index to check.
+ */
+ bool findTagPtr(unsigned long index);
+};
+
+#endif /* __GEN_HH__ */
diff --git a/src/mem/cache/tags/repl/repl.cc b/src/mem/cache/tags/repl/repl.cc
new file mode 100644
index 000000000..ce781eb9f
--- /dev/null
+++ b/src/mem/cache/tags/repl/repl.cc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Nathan Binkert
+ */
+
+/**
+ * Definitions of the base replacement class.
+ */
+
+#include "sim/param.hh"
+#include "mem/cache/tags/repl/repl.hh"
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+DEFINE_SIM_OBJECT_CLASS_NAME("Repl", Repl)
+
+#endif //DOXYGEN_SHOULD_SKIP_THIS
diff --git a/src/mem/cache/tags/repl/repl.hh b/src/mem/cache/tags/repl/repl.hh
new file mode 100644
index 000000000..7c289a5c1
--- /dev/null
+++ b/src/mem/cache/tags/repl/repl.hh
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Erik Hallnor
+ * Steve Reinhardt
+ * Nathan Binkert
+ */
+
+/**
+ * @file
+ * Declaration of a base replacement policy class.
+ */
+
+#ifndef __REPL_HH__
+#define __REPL_HH__
+
+#include <string>
+#include <list>
+
+#include "cpu/smt.hh"
+#include "sim/host.hh"
+#include "sim/sim_object.hh"
+
+
+class IIC;
+
+/**
+ * A pure virtual base class that defines the interface of a replacement
+ * policy.
+ */
+class Repl : public SimObject
+{
+ public:
+ /** Pointer to the IIC using this policy. */
+ IIC *iic;
+
+ /**
+ * Construct and initialize this polixy.
+ * @param name The instance name of this policy.
+ */
+ Repl (const std::string &name)
+ : SimObject(name)
+ {
+ iic = NULL;
+ }
+
+ /**
+ * Set the back pointer to the IIC.
+ * @param iic_ptr Pointer to the IIC.
+ */
+ void setIIC(IIC *iic_ptr)
+ {
+ iic = iic_ptr;
+ }
+
+ /**
+ * Returns the tag pointer of the cache block to replace.
+ * @return The tag to replace.
+ */
+ virtual unsigned long getRepl() = 0;
+
+ /**
+ * Return an array of N tag pointers to replace.
+ * @param n The number of tag pointer to return.
+ * @return An array of tag pointers to replace.
+ */
+ virtual unsigned long *getNRepl(int n) = 0;
+
+ /**
+ * Update replacement data
+ */
+ virtual void doAdvance(std::list<unsigned long> &demoted) = 0;
+
+ /**
+ * Add a tag to the replacement policy and return a pointer to the
+ * replacement entry.
+ * @param tag_index The tag to add.
+ * @return The replacement entry.
+ */
+ virtual void* add(unsigned long tag_index) = 0;
+
+ /**
+ * Register statistics.
+ * @param name The name to prepend to statistic descriptions.
+ */
+ virtual void regStats(const std::string name) = 0;
+
+ /**
+ * Update the tag pointer to when the tag moves.
+ * @param re The replacement entry of the tag.
+ * @param old_index The old tag pointer.
+ * @param new_index The new tag pointer.
+ * @return 1 if successful, 0 otherwise.
+ */
+ virtual int fixTag(void *re, unsigned long old_index,
+ unsigned long new_index) = 0;
+
+ /**
+ * Remove this entry from the replacement policy.
+ * @param re The replacement entry to remove
+ */
+ virtual void removeEntry(void *re) = 0;
+};
+
+#endif /* SMT_REPL_HH */
diff --git a/src/mem/cache/tags/split.cc b/src/mem/cache/tags/split.cc
new file mode 100644
index 000000000..690eea22e
--- /dev/null
+++ b/src/mem/cache/tags/split.cc
@@ -0,0 +1,478 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Definitions of split cache tag store.
+ */
+
+#include <string>
+#include <iostream>
+#include <fstream>
+
+#include "base/cprintf.hh"
+#include "base/intmath.hh"
+#include "base/output.hh"
+#include "base/trace.hh"
+#include "mem/cache/base_cache.hh"
+#include "mem/cache/tags/split.hh"
+#include "mem/cache/tags/split_lifo.hh"
+#include "mem/cache/tags/split_lru.hh"
+
+
+using namespace std;
+using namespace TheISA;
+
+// create and initialize a partitioned cache structure
+Split::Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
+ bool _lifo, bool _two_queue, int _hit_latency) :
+ numSets(_numSets), blkSize(_blkSize), lifo(_lifo), hitLatency(_hit_latency)
+{
+ DPRINTF(Split, "new split cache!!\n");
+
+ DPRINTF(Split, "lru has %d numSets, %d blkSize, %d assoc, and %d hit_latency\n",
+ numSets, blkSize, LRU1_assoc, hitLatency);
+
+ lru = new SplitLRU(_numSets, _blkSize, LRU1_assoc, _hit_latency, 1);
+
+ if (total_ways - LRU1_assoc == 0) {
+ lifo_net = NULL;
+ lru_net = NULL;
+ } else {
+ if (lifo) {
+ DPRINTF(Split, "Other partition is a LIFO with size %d in bytes. it gets %d ways\n",
+ (total_ways - LRU1_assoc)*_numSets*_blkSize, (total_ways - LRU1_assoc));
+ lifo_net = new SplitLIFO(_blkSize, (total_ways - LRU1_assoc)*_numSets*_blkSize,
+ (total_ways - LRU1_assoc), _hit_latency, _two_queue, 2);
+ lru_net = NULL;
+ }
+ else {
+ DPRINTF(Split, "other LRU gets %d ways\n", total_ways - LRU1_assoc);
+ lru_net = new SplitLRU(_numSets, _blkSize, total_ways - LRU1_assoc, _hit_latency, 2);
+ lifo_net = NULL;
+ }
+ }
+
+ blkMask = blkSize - 1;
+
+ if (!isPowerOf2(total_ways))
+ warn("total cache ways/columns %d should be power of 2",
+ total_ways);
+
+ warmedUp = false;
+ /** @todo Make warmup percentage a parameter. */
+ warmupBound = numSets * total_ways;
+
+}
+
+Split::~Split()
+{
+ delete lru;
+ if (lifo)
+ delete lifo_net;
+ else
+ delete lru_net;
+}
+
+void
+Split::regStats(const string &name)
+{
+ using namespace Stats;
+
+ BaseTags::regStats(name);
+
+ usedEvictDist.init(0,3000,40);
+ unusedEvictDist.init(0,3000,40);
+ useByCPUCycleDist.init(0,35,1);
+
+ nic_repl
+ .name(name + ".nic_repl")
+ .desc("number of replacements in the nic partition")
+ .precision(0)
+ ;
+
+ cpu_repl
+ .name(name + ".cpu_repl")
+ .desc("number of replacements in the cpu partition")
+ .precision(0)
+ ;
+
+ lru->regStats(name + ".lru");
+
+ if (lifo && lifo_net) {
+ lifo_net->regStats(name + ".lifo_net");
+ } else if (lru_net) {
+ lru_net->regStats(name + ".lru_net");
+ }
+
+ nicUsedWhenEvicted
+ .name(name + ".nicUsedWhenEvicted")
+ .desc("number of NIC blks that were used before evicted")
+ ;
+
+ nicUsedTotLatency
+ .name(name + ".nicUsedTotLatency")
+ .desc("total cycles before eviction of used NIC blks")
+ ;
+
+ nicUsedTotEvicted
+ .name(name + ".nicUsedTotEvicted")
+ .desc("total number of used NIC blks evicted")
+ ;
+
+ nicUsedAvgLatency
+ .name(name + ".nicUsedAvgLatency")
+ .desc("avg number of cycles a used NIC blk is in cache")
+ .precision(0)
+ ;
+ nicUsedAvgLatency = nicUsedTotLatency / nicUsedTotEvicted;
+
+ usedEvictDist
+ .name(name + ".usedEvictDist")
+ .desc("distribution of used NIC blk eviction times")
+ .flags(pdf | cdf)
+ ;
+
+ nicUnusedWhenEvicted
+ .name(name + ".nicUnusedWhenEvicted")
+ .desc("number of NIC blks that were unused when evicted")
+ ;
+
+ nicUnusedTotLatency
+ .name(name + ".nicUnusedTotLatency")
+ .desc("total cycles before eviction of unused NIC blks")
+ ;
+
+ nicUnusedTotEvicted
+ .name(name + ".nicUnusedTotEvicted")
+ .desc("total number of unused NIC blks evicted")
+ ;
+
+ nicUnusedAvgLatency
+ .name(name + ".nicUnusedAvgLatency")
+ .desc("avg number of cycles an unused NIC blk is in cache")
+ .precision(0)
+ ;
+ nicUnusedAvgLatency = nicUnusedTotLatency / nicUnusedTotEvicted;
+
+ unusedEvictDist
+ .name(name + ".unusedEvictDist")
+ .desc("distribution of unused NIC blk eviction times")
+ .flags(pdf | cdf)
+ ;
+
+ nicUseByCPUCycleTotal
+ .name(name + ".nicUseByCPUCycleTotal")
+ .desc("total latency of NIC blks til usage time")
+ ;
+
+ nicBlksUsedByCPU
+ .name(name + ".nicBlksUsedByCPU")
+ .desc("total number of NIC blks used")
+ ;
+
+ nicAvgUsageByCPULatency
+ .name(name + ".nicAvgUsageByCPULatency")
+ .desc("average number of cycles before a NIC blk that is used gets used")
+ .precision(0)
+ ;
+ nicAvgUsageByCPULatency = nicUseByCPUCycleTotal / nicBlksUsedByCPU;
+
+ useByCPUCycleDist
+ .name(name + ".useByCPUCycleDist")
+ .desc("the distribution of cycle time in cache before NIC blk is used")
+ .flags(pdf | cdf)
+ ;
+
+ cpuUsedBlks
+ .name(name + ".cpuUsedBlks")
+ .desc("number of cpu blks that were used before evicted")
+ ;
+
+ cpuUnusedBlks
+ .name(name + ".cpuUnusedBlks")
+ .desc("number of cpu blks that were unused before evicted")
+ ;
+
+ nicAvgLatency
+ .name(name + ".nicAvgLatency")
+ .desc("avg number of cycles a NIC blk is in cache before evicted")
+ .precision(0)
+ ;
+ nicAvgLatency = (nicUnusedTotLatency + nicUsedTotLatency) /
+ (nicUnusedTotEvicted + nicUsedTotEvicted);
+
+ NR_CP_hits
+ .name(name + ".NR_CP_hits")
+ .desc("NIC requests hitting in CPU Partition")
+ ;
+
+ NR_NP_hits
+ .name(name + ".NR_NP_hits")
+ .desc("NIC requests hitting in NIC Partition")
+ ;
+
+ CR_CP_hits
+ .name(name + ".CR_CP_hits")
+ .desc("CPU requests hitting in CPU partition")
+ ;
+
+ CR_NP_hits
+ .name(name + ".CR_NP_hits")
+ .desc("CPU requests hitting in NIC partition")
+ ;
+
+}
+
+// probe cache for presence of given block.
+bool
+Split::probe(Addr addr) const
+{
+ bool success = lru->probe(addr);
+ if (!success) {
+ if (lifo && lifo_net)
+ success = lifo_net->probe(addr);
+ else if (lru_net)
+ success = lru_net->probe(addr);
+ }
+
+ return success;
+}
+
+SplitBlk*
+Split::findBlock(Packet * &pkt, int &lat)
+{
+
+ Addr aligned = blkAlign(pkt->getAddr());
+
+ if (memHash.count(aligned)) {
+ memHash[aligned]++;
+ } else if (pkt->nic_pkt()) {
+ memHash[aligned] = 1;
+ }
+
+ SplitBlk *blk = lru->findBlock(pkt->getAddr(), lat);
+ if (blk) {
+ if (pkt->nic_pkt()) {
+ NR_CP_hits++;
+ } else {
+ CR_CP_hits++;
+ }
+ } else {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(pkt->getAddr(), lat);
+
+ } else if (lru_net) {
+ blk = lru_net->findBlock(pkt->getAddr(), lat);
+ }
+ if (blk) {
+ if (pkt->nic_pkt()) {
+ NR_NP_hits++;
+ } else {
+ CR_NP_hits++;
+ }
+ }
+ }
+
+ if (blk) {
+ Tick latency = curTick - blk->ts;
+ if (blk->isNIC) {
+ if (!blk->isUsed && !pkt->nic_pkt()) {
+ useByCPUCycleDist.sample(latency);
+ nicUseByCPUCycleTotal += latency;
+ nicBlksUsedByCPU++;
+ }
+ }
+ blk->isUsed = true;
+
+ if (pkt->nic_pkt()) {
+ DPRINTF(Split, "found block in partition %d\n", blk->part);
+ }
+ }
+ return blk;
+}
+
+SplitBlk*
+Split::findBlock(Addr addr, int &lat)
+{
+ SplitBlk *blk = lru->findBlock(addr, lat);
+ if (!blk) {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(addr, lat);
+ } else if (lru_net) {
+ blk = lru_net->findBlock(addr, lat);
+ }
+ }
+
+ return blk;
+}
+
+SplitBlk*
+Split::findBlock(Addr addr) const
+{
+ SplitBlk *blk = lru->findBlock(addr);
+ if (!blk) {
+ if (lifo && lifo_net) {
+ blk = lifo_net->findBlock(addr);
+ } else if (lru_net) {
+ blk = lru_net->findBlock(addr);
+ }
+ }
+
+ return blk;
+}
+
+SplitBlk*
+Split::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ SplitBlk *blk;
+
+ if (pkt->nic_pkt()) {
+ DPRINTF(Split, "finding a replacement for nic_req\n");
+ nic_repl++;
+ if (lifo && lifo_net)
+ blk = lifo_net->findReplacement(pkt, writebacks,
+ compress_blocks);
+ else if (lru_net)
+ blk = lru_net->findReplacement(pkt, writebacks,
+ compress_blocks);
+ // in this case, this is an LRU only cache, it's non partitioned
+ else
+ blk = lru->findReplacement(pkt, writebacks, compress_blocks);
+ } else {
+ DPRINTF(Split, "finding replacement for cpu_req\n");
+ blk = lru->findReplacement(pkt, writebacks,
+ compress_blocks);
+ cpu_repl++;
+ }
+
+ Tick latency = curTick - blk->ts;
+ if (blk->isNIC) {
+ if (blk->isUsed) {
+ nicUsedWhenEvicted++;
+ usedEvictDist.sample(latency);
+ nicUsedTotLatency += latency;
+ nicUsedTotEvicted++;
+ } else {
+ nicUnusedWhenEvicted++;
+ unusedEvictDist.sample(latency);
+ nicUnusedTotLatency += latency;
+ nicUnusedTotEvicted++;
+ }
+ } else {
+ if (blk->isUsed) {
+ cpuUsedBlks++;
+ } else {
+ cpuUnusedBlks++;
+ }
+ }
+
+ // blk attributes for the new blk coming IN
+ blk->ts = curTick;
+ blk->isNIC = (pkt->nic_pkt()) ? true : false;
+
+ return blk;
+}
+
+void
+Split::invalidateBlk(Addr addr)
+{
+ SplitBlk *blk = lru->findBlock(addr);
+ if (!blk) {
+ if (lifo && lifo_net)
+ blk = lifo_net->findBlock(addr);
+ else if (lru_net)
+ blk = lru_net->findBlock(addr);
+
+ if (!blk)
+ return;
+ }
+
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+}
+
+void
+Split::doCopy(Addr source, Addr dest, PacketList &writebacks)
+{
+ if (lru->probe( source))
+ lru->doCopy(source, dest, writebacks);
+ else {
+ if (lifo && lifo_net)
+ lifo_net->doCopy(source, dest, writebacks);
+ else if (lru_net)
+ lru_net->doCopy(source, dest, writebacks);
+ }
+}
+
+void
+Split::cleanupRefs()
+{
+ lru->cleanupRefs();
+ if (lifo && lifo_net)
+ lifo_net->cleanupRefs();
+ else if (lru_net)
+ lru_net->cleanupRefs();
+
+ ofstream memPrint(simout.resolve("memory_footprint.txt").c_str(),
+ ios::trunc);
+
+ // this shouldn't be here but it happens at the end, which is what i want
+ memIter end = memHash.end();
+ for (memIter iter = memHash.begin(); iter != end; ++iter) {
+ ccprintf(memPrint, "%8x\t%d\n", (*iter).first, (*iter).second);
+ }
+}
+
+Addr
+Split::regenerateBlkAddr(Addr tag, int set) const
+{
+ if (lifo_net)
+ return lifo_net->regenerateBlkAddr(tag, set);
+ else
+ return lru->regenerateBlkAddr(tag, set);
+}
+
+Addr
+Split::extractTag(Addr addr, SplitBlk *blk) const
+{
+ if (blk->part == 2) {
+ if (lifo_net)
+ return lifo_net->extractTag(addr);
+ else if (lru_net)
+ return lru_net->extractTag(addr);
+ else
+ panic("this shouldn't happen");
+ } else
+ return lru->extractTag(addr);
+}
+
diff --git a/src/mem/cache/tags/split.hh b/src/mem/cache/tags/split.hh
new file mode 100644
index 000000000..f0091e971
--- /dev/null
+++ b/src/mem/cache/tags/split.hh
@@ -0,0 +1,335 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Declaration of a split/partitioned tag store.
+ */
+
+#ifndef __SPLIT_HH__
+#define __SPLIT_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh" // base class
+#include "mem/cache/tags/split_blk.hh"
+#include "mem/packet.hh" // for inlined functions
+#include <assert.h>
+#include "mem/cache/tags/base_tags.hh"
+#include "base/hashmap.hh"
+
+class BaseCache;
+class SplitLRU;
+class SplitLIFO;
+
+/**
+ * A cache tag store.
+ */
+class Split : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this tag store. */
+ typedef SplitBlk BlkType;
+ /** Typedef for a list of pointers to the local block class. */
+ typedef std::list<SplitBlk*> BlkList;
+ protected:
+ /** The number of sets in the cache. */
+ const int numSets;
+ /** The number of bytes in a block. */
+ const int blkSize;
+ /** Whether the 2nd partition (for the nic) is LIFO or not */
+ const bool lifo;
+ /** The hit latency. */
+ const int hitLatency;
+
+ Addr blkMask;
+
+ /** Number of NIC pktuests that hit in the NIC partition */
+ Stats::Scalar<> NR_NP_hits;
+ /** Number of NIC pktuests that hit in the CPU partition */
+ Stats::Scalar<> NR_CP_hits;
+ /** Number of CPU pktuests that hit in the NIC partition */
+ Stats::Scalar<> CR_NP_hits;
+ /** Number of CPU pktuests that hit in the CPU partition */
+ Stats::Scalar<> CR_CP_hits;
+ /** The number of nic replacements (i.e. misses) */
+ Stats::Scalar<> nic_repl;
+ /** The number of cpu replacements (i.e. misses) */
+ Stats::Scalar<> cpu_repl;
+
+ //For latency studies
+ /** the number of NIC blks that were used before evicted */
+ Stats::Scalar<> nicUsedWhenEvicted;
+ /** the total latency of used NIC blocks in the cache */
+ Stats::Scalar<> nicUsedTotLatency;
+ /** the total number of used NIC blocks evicted */
+ Stats::Scalar<> nicUsedTotEvicted;
+ /** the average number of cycles a used NIC blk is in the cache */
+ Stats::Formula nicUsedAvgLatency;
+ /** the Distribution of used NIC blk eviction times */
+ Stats::Distribution<> usedEvictDist;
+
+ /** the number of NIC blks that were unused before evicted */
+ Stats::Scalar<> nicUnusedWhenEvicted;
+ /** the total latency of unused NIC blks in the cache */
+ Stats::Scalar<> nicUnusedTotLatency;
+ /** the total number of unused NIC blocks evicted */
+ Stats::Scalar<> nicUnusedTotEvicted;
+ /** the average number of cycles an unused NIC blk is in the cache */
+ Stats::Formula nicUnusedAvgLatency;
+ /** the Distribution of unused NIC blk eviction times */
+ Stats::Distribution<> unusedEvictDist;
+
+ /** The total latency of NIC blocks to 1st usage time by CPU */
+ Stats::Scalar<> nicUseByCPUCycleTotal;
+ /** The total number of NIC blocks used */
+ Stats::Scalar<> nicBlksUsedByCPU;
+ /** the average number of cycles before a NIC blk that is used gets used by CPU */
+ Stats::Formula nicAvgUsageByCPULatency;
+ /** the Distribution of cycles time before a NIC blk is used by CPU*/
+ Stats::Distribution<> useByCPUCycleDist;
+
+ /** the number of CPU blks that were used before evicted */
+ Stats::Scalar<> cpuUsedBlks;
+ /** the number of CPU blks that were unused before evicted */
+ Stats::Scalar<> cpuUnusedBlks;
+
+ /** the avg number of cycles before a NIC blk is evicted */
+ Stats::Formula nicAvgLatency;
+
+ typedef m5::hash_map<Addr, int, m5::hash<Addr> > hash_t;
+ typedef hash_t::const_iterator memIter;
+ hash_t memHash;
+
+
+ private:
+ SplitLRU *lru;
+ SplitLRU *lru_net;
+ SplitLIFO *lifo_net;
+
+ public:
+ /**
+ * Construct and initialize this tag store.
+ * @param _numSets The number of sets in the cache.
+ * @param _blkSize The number of bytes in a block.
+ * @param _assoc The associativity of the cache.
+ * @param _hit_latency The latency in cycles for a hit.
+ */
+ Split(int _numSets, int _blkSize, int total_ways, int LRU1_assoc,
+ bool _lifo, bool _two_queue, int _hit_latency);
+
+ /**
+ * Destructor
+ */
+ virtual ~Split();
+
+ /**
+ * Register the stats for this object
+ * @param name The name to prepend to the stats name.
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Return the block size.
+ * @return the block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size. In the case of Split it is always the block
+ * size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Search for the address in the cache.
+ * @param asid The address space ID.
+ * @param addr The address to find.
+ * @return True if the address is in the cache.
+ */
+ bool probe(Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param pkt The memory request whose block to find
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Finds the given address in the cache, do not update replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk The block to find the partition it's in
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) const;
+
+ /**
+ * Calculate the set index from the address.
+ * @param addr The address to get the set from.
+ * @return The set index of the address.
+ */
+ int extractSet(Addr addr) const
+ {
+ panic("should never call this!\n");
+ }
+
+ /**
+ * Get the block offset from an address.
+ * @param addr The address to get the offset of.
+ * @return The block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & blkMask);
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The block address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr) (blkMask));
+ }
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set The set of the block.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, int set) const;
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Read the data out of the internal storage of the given cache block.
+ * @param blk The cache block to read.
+ * @param data The buffer to read the data into.
+ * @return The cache block's data.
+ */
+ void readData(SplitBlk *blk, uint8_t *data)
+ {
+ memcpy(data, blk->data, blk->size);
+ }
+
+ /**
+ * Write data into the internal storage of the given cache block. Since in
+ * Split does not store data differently this just needs to update the size.
+ * @param blk The cache block to write.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(SplitBlk *blk, uint8_t *data, int size,
+ PacketList & writebacks)
+ {
+ assert(size <= blkSize);
+ blk->size = size;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+};
+
+#endif
diff --git a/src/mem/cache/tags/split_blk.hh b/src/mem/cache/tags/split_blk.hh
new file mode 100644
index 000000000..64d903579
--- /dev/null
+++ b/src/mem/cache/tags/split_blk.hh
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Declaration of partitioned tag store cache block class.
+ */
+
+#ifndef __SPLIT_BLK_HH__
+#define __SPLIT_BLK_HH__
+
+#include "mem/cache/cache_blk.hh" // base class
+
+/**
+ * Split cache block.
+ */
+class SplitBlk : public CacheBlk {
+ public:
+ /** Has this block been touched? Used to aid calculation of warmup time. */
+ bool isTouched;
+ /** Has this block been used after being brought in? (for LIFO partition) */
+ bool isUsed;
+ /** is this blk a NIC block? (i.e. pktuested by the NIC) */
+ bool isNIC;
+ /** timestamp of the arrival of this block into the cache */
+ Tick ts;
+ /** the previous block in the LIFO partition (brought in before than me) */
+ SplitBlk *prev;
+ /** the next block in the LIFO partition (brought in later than me) */
+ SplitBlk *next;
+ /** which partition this block is in */
+ int part;
+
+ SplitBlk()
+ : isTouched(false), isUsed(false), isNIC(false), ts(0), prev(NULL), next(NULL),
+ part(0)
+ {}
+};
+
+#endif
+
diff --git a/src/mem/cache/tags/split_lifo.cc b/src/mem/cache/tags/split_lifo.cc
new file mode 100644
index 000000000..6fcbf3597
--- /dev/null
+++ b/src/mem/cache/tags/split_lifo.cc
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Definitions of LIFO tag store usable in a partitioned cache.
+ */
+
+#include <string>
+
+#include "mem/cache/base_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/split_lifo.hh"
+#include "sim/root.hh"
+#include "base/trace.hh"
+
+using namespace std;
+
+SplitBlk*
+LIFOSet::findBlk(Addr tag) const
+{
+ for (SplitBlk *blk = firstIn; blk != NULL; blk = blk->next) {
+ if (blk->tag == tag && blk->isValid()) {
+ return blk;
+ }
+ }
+ return NULL;
+}
+
+void
+LIFOSet::moveToLastIn(SplitBlk *blk)
+{
+ if (blk == lastIn)
+ return;
+
+ if (blk == firstIn) {
+ blk->next->prev = NULL;
+ } else {
+ blk->prev->next = blk->next;
+ blk->next->prev = blk->prev;
+ }
+ blk->next = NULL;
+ blk->prev = lastIn;
+ lastIn->next = blk;
+
+ lastIn = blk;
+}
+
+void
+LIFOSet::moveToFirstIn(SplitBlk *blk)
+{
+ if (blk == firstIn)
+ return;
+
+ if (blk == lastIn) {
+ blk->prev->next = NULL;
+ } else {
+ blk->next->prev = blk->prev;
+ blk->prev->next = blk->next;
+ }
+
+ blk->prev = NULL;
+ blk->next = firstIn;
+ firstIn->prev = blk;
+
+ firstIn = blk;
+}
+
+// create and initialize a LIFO cache structure
+SplitLIFO::SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool two_Queue, int _part) :
+ blkSize(_blkSize), size(_size), numBlks(_size/_blkSize), numSets((_size/_ways)/_blkSize), ways(_ways),
+ hitLatency(_hit_latency), twoQueue(two_Queue), part(_part)
+{
+ if (!isPowerOf2(blkSize))
+ fatal("cache block size (in bytes) must be a power of 2");
+ if (!(hitLatency > 0))
+ fatal("access latency in cycles must be at least on cycle");
+ if (_ways == 0)
+ fatal("if instantiating a splitLIFO, needs non-zero size!");
+
+
+ SplitBlk *blk;
+ int i, j, blkIndex;
+
+ setShift = floorLog2(blkSize);
+ blkMask = blkSize - 1;
+ setMask = numSets - 1;
+ tagShift = setShift + floorLog2(numSets);
+
+ warmedUp = false;
+ /** @todo Make warmup percentage a parameter. */
+ warmupBound = size/blkSize;
+
+ // allocate data blocks
+ blks = new SplitBlk[numBlks];
+ sets = new LIFOSet[numSets];
+ dataBlks = new uint8_t[size];
+
+/*
+ // these start off point to same blk
+ top = &(blks[0]);
+ head = top;
+*/
+
+ blkIndex = 0;
+ for (i=0; i < numSets; ++i) {
+ sets[i].ways = ways;
+ sets[i].lastIn = &blks[blkIndex];
+ sets[i].firstIn = &blks[blkIndex + ways - 1];
+
+ /* 3 cases: if there is 1 way, if there are 2 ways, or if there are 3+.
+ in the case of 1 way, last in and first out point to the same blocks,
+ and the next and prev pointers need to be assigned specially. and so on
+ */
+ /* deal with the first way */
+ blk = &blks[blkIndex];
+ blk->prev = &blks[blkIndex + 1];
+ blk->next = NULL;
+ blk->data = &dataBlks[blkSize*blkIndex];
+ blk->size = blkSize;
+ blk->part = part;
+ blk->set = i;
+ ++blkIndex;
+
+ /* if there are "middle" ways, do them here */
+ if (ways > 2) {
+ for (j=1; j < ways-1; ++j) {
+ blk = &blks[blkIndex];
+ blk->data = &dataBlks[blkSize*blkIndex];
+ blk->prev = &blks[blkIndex+1];
+ blk->next = &blks[blkIndex-1];
+ blk->data = &(dataBlks[blkSize*blkIndex]);
+ blk->size = blkSize;
+ blk->part = part;
+ blk->set = i;
+ ++blkIndex;
+ }
+ }
+
+ /* do the final way here, depending on whether the final way is the only
+ way or not
+ */
+ if (ways > 1) {
+ blk = &blks[blkIndex];
+ blk->prev = NULL;
+ blk->next = &blks[blkIndex - 1];
+ blk->data = &dataBlks[blkSize*blkIndex];
+ blk->size = blkSize;
+ blk->part = part;
+ blk->set = i;
+ ++blkIndex;
+ } else {
+ blk->prev = NULL;
+ }
+ }
+ assert(blkIndex == numBlks);
+}
+
+SplitLIFO::~SplitLIFO()
+{
+ delete [] blks;
+ delete [] sets;
+ delete [] dataBlks;
+}
+
+void
+SplitLIFO::regStats(const std::string &name)
+{
+ BaseTags::regStats(name);
+
+ hits
+ .name(name + ".hits")
+ .desc("number of hits on this partition")
+ .precision(0)
+ ;
+
+ misses
+ .name(name + ".misses")
+ .desc("number of misses in this partition")
+ .precision(0)
+ ;
+
+ invalidations
+ .name(name + ".invalidations")
+ .desc("number of invalidations in this partition")
+ .precision(0)
+ ;
+}
+
+// probe cache for presence of given block.
+bool
+SplitLIFO::probe(Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ SplitBlk* blk = sets[myset].findBlk(tag);
+ return (blk != NULL);
+}
+
+SplitBlk*
+SplitLIFO::findBlock(Addr addr, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+
+ lat = hitLatency;
+
+ if (blk) {
+ DPRINTF(Split, "Found LIFO blk %#x in set %d, with tag %#x\n",
+ addr, set, tag);
+ hits++;
+
+ if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency)
+ lat = blk->whenReady - curTick;
+ blk->refCount +=1;
+
+ if (twoQueue) {
+ blk->isUsed = true;
+ sets[set].moveToFirstIn(blk);
+ } else {
+ sets[set].moveToLastIn(blk);
+ }
+ }
+
+ return blk;
+}
+
+SplitBlk*
+SplitLIFO::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+
+ if (blk) {
+ DPRINTF(Split, "Found LIFO blk %#x in set %d, with tag %#x\n",
+ addr, set, tag);
+ hits++;
+
+ if (twoQueue) {
+ blk->isUsed = true;
+ sets[set].moveToFirstIn(blk);
+ } else {
+ sets[set].moveToLastIn(blk);
+ }
+ }
+ lat = hitLatency;
+
+ return blk;
+}
+
+SplitBlk*
+SplitLIFO::findBlock(Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+
+ return blk;
+}
+
+SplitBlk*
+SplitLIFO::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+
+ SplitBlk *firstIn = sets[set].firstIn;
+ SplitBlk *lastIn = sets[set].lastIn;
+
+ SplitBlk *blk;
+ if (twoQueue && firstIn->isUsed) {
+ blk = firstIn;
+ blk->isUsed = false;
+ sets[set].moveToLastIn(blk);
+ } else {
+ int withValue = sets[set].withValue;
+ if (withValue == ways) {
+ blk = lastIn;
+ } else {
+ blk = &(sets[set].firstIn[ways - ++withValue]);
+ }
+ }
+
+ DPRINTF(Split, "just assigned %#x addr into LIFO, replacing %#x status %#x\n",
+ pkt->getAddr(), regenerateBlkAddr(blk->tag, set), blk->status);
+ if (blk->isValid()) {
+ replacements[0]++;
+ totalRefs += blk->refCount;
+ ++sampledRefs;
+ blk->refCount = 0;
+ } else {
+ tagsInUse++;
+ blk->isTouched = true;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+ }
+
+ misses++;
+
+ return blk;
+}
+
+void
+SplitLIFO::invalidateBlk(Addr addr)
+{
+ SplitBlk *blk = findBlock(addr);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ invalidations++;
+ }
+}
+
+void
+SplitLIFO::doCopy(Addr source, Addr dest, PacketList &writebacks)
+{
+//Copy Unsuported for now
+#if 0
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ SplitBlk *source_blk = findBlock(source);
+ assert(source_blk);
+ SplitBlk *dest_blk = findBlock(dest);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Packet * pkt = new Packet();
+ pkt->paddr = dest;
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+ pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->xc,
+ blkSize,
+ (cache->doData())?dest_blk->data:0,
+ dest_blk->size);
+ writebacks.push_back(pkt);
+ }
+ dest_blk->tag = extractTag(dest);
+ /**
+ * @todo Do we need to pass in the execution context, or can we
+ * assume its the same?
+ */
+ assert(source_blk->xc);
+ dest_blk->xc = source_blk->xc;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ if (cache->doData()) {
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+ }
+#endif
+}
+
+void
+SplitLIFO::cleanupRefs()
+{
+ for (int i = 0; i < numBlks; ++i) {
+ if (blks[i].isValid()) {
+ totalRefs += blks[i].refCount;
+ ++sampledRefs;
+ }
+ }
+}
diff --git a/src/mem/cache/tags/split_lifo.hh b/src/mem/cache/tags/split_lifo.hh
new file mode 100644
index 000000000..355a66162
--- /dev/null
+++ b/src/mem/cache/tags/split_lifo.hh
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Declaration of a LIFO tag store usable in a partitioned cache.
+ */
+
+#ifndef __SPLIT_LIFO_HH__
+#define __SPLIT_LIFO_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh" // base class
+#include "mem/cache/tags/split_blk.hh"
+#include "mem/packet.hh" // for inlined functions
+#include "base/hashmap.hh"
+#include <assert.h>
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache;
+
+/**
+ * A LIFO set of cache blks
+ */
+class LIFOSet {
+ public:
+ /** the number of blocks in this set */
+ int ways;
+
+ /** Cache blocks in this set, maintained in LIFO order where
+ 0 = Last in (head) */
+ SplitBlk *lastIn;
+ SplitBlk *firstIn;
+
+ /** has the initial "filling" of this set finished? i.e., have you had
+ * 'ways' number of compulsory misses in this set yet? if withValue == ways,
+ * then yes. withValue is meant to be the number of blocks in the set that have
+ * gone through their first compulsory miss.
+ */
+ int withValue;
+
+ /**
+ * Find a block matching the tag in this set.
+ * @param asid The address space ID.
+ * @param tag the Tag you are looking for
+ * @return Pointer to the block, if found, NULL otherwise
+ */
+ SplitBlk* findBlk(Addr tag) const;
+
+ void moveToLastIn(SplitBlk *blk);
+ void moveToFirstIn(SplitBlk *blk);
+
+ LIFOSet()
+ : ways(-1), lastIn(NULL), firstIn(NULL), withValue(0)
+ {}
+};
+
+/**
+ * A LIFO cache tag store.
+ */
+class SplitLIFO : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this tag store. */
+ typedef SplitBlk BlkType;
+ /** Typedef for a list of pointers to the local block class. */
+ typedef std::list<SplitBlk*> BlkList;
+ protected:
+ /** The number of bytes in a block. */
+ const int blkSize;
+ /** the size of the cache in bytes */
+ const int size;
+ /** the number of blocks in the cache */
+ const int numBlks;
+ /** the number of sets in the cache */
+ const int numSets;
+ /** the number of ways in the cache */
+ const int ways;
+ /** The hit latency. */
+ const int hitLatency;
+ /** whether this is a "2 queue" replacement @sa moveToLastIn @sa moveToFirstIn */
+ const bool twoQueue;
+ /** indicator for which partition this is */
+ const int part;
+
+ /** The cache blocks. */
+ SplitBlk *blks;
+ /** The Cache sets */
+ LIFOSet *sets;
+ /** The data blocks, 1 per cache block. */
+ uint8_t *dataBlks;
+
+ /** The amount to shift the address to get the set. */
+ int setShift;
+ /** The amount to shift the address to get the tag. */
+ int tagShift;
+ /** Mask out all bits that aren't part of the set index. */
+ unsigned setMask;
+ /** Mask out all bits that aren't part of the block offset. */
+ unsigned blkMask;
+
+
+ /** the number of hit in this partition */
+ Stats::Scalar<> hits;
+ /** the number of blocks brought into this partition (i.e. misses) */
+ Stats::Scalar<> misses;
+ /** the number of invalidations in this partition */
+ Stats::Scalar<> invalidations;
+
+public:
+ /**
+ * Construct and initialize this tag store.
+ * @param _numSets The number of sets in the cache.
+ * @param _blkSize The number of bytes in a block.
+ * @param _assoc The associativity of the cache.
+ * @param _hit_latency The latency in cycles for a hit.
+ */
+ SplitLIFO(int _blkSize, int _size, int _ways, int _hit_latency, bool twoQueue, int _part);
+
+ /**
+ * Destructor
+ */
+ virtual ~SplitLIFO();
+
+ /**
+ * Register the statistics for this object
+ * @param name The name to precede the stat
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Return the block size.
+ * @return the block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size. In the case of LIFO it is always the block
+ * size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Search for the address in the cache.
+ * @param asid The address space ID.
+ * @param addr The address to find.
+ * @return True if the address is in the cache.
+ */
+ bool probe( Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param pkt The req whose block to find
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Finds the given address in the cache, do not update replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Calculate the set index from the address.
+ * @param addr The address to get the set from.
+ * @return The set index of the address.
+ */
+ int extractSet(Addr addr) const
+ {
+ return ((addr >> setShift) & setMask);
+ }
+
+ /**
+ * Get the block offset from an address.
+ * @param addr The address to get the offset of.
+ * @return The block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & blkMask);
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The block address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)blkMask);
+ }
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set The set of the block.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, unsigned set) const
+ {
+ return ((tag << tagShift) | ((Addr)set << setShift));
+ }
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Read the data out of the internal storage of the given cache block.
+ * @param blk The cache block to read.
+ * @param data The buffer to read the data into.
+ * @return The cache block's data.
+ */
+ void readData(SplitBlk *blk, uint8_t *data)
+ {
+ memcpy(data, blk->data, blk->size);
+ }
+
+ /**
+ * Write data into the internal storage of the given cache block. Since in
+ * LIFO does not store data differently this just needs to update the size.
+ * @param blk The cache block to write.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(SplitBlk *blk, uint8_t *data, int size,
+ PacketList & writebacks)
+ {
+ assert(size <= blkSize);
+ blk->size = size;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+};
+
+#endif
diff --git a/src/mem/cache/tags/split_lru.cc b/src/mem/cache/tags/split_lru.cc
new file mode 100644
index 000000000..4381923bd
--- /dev/null
+++ b/src/mem/cache/tags/split_lru.cc
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Definitions of LRU tag store for a partitioned cache.
+ */
+
+#include <string>
+
+#include "mem/cache/base_cache.hh"
+#include "base/intmath.hh"
+#include "mem/cache/tags/split_lru.hh"
+#include "sim/root.hh"
+
+using namespace std;
+
+SplitBlk*
+SplitCacheSet::findBlk(Addr tag) const
+{
+ for (int i = 0; i < assoc; ++i) {
+ if (blks[i]->tag == tag && blks[i]->isValid()) {
+ return blks[i];
+ }
+ }
+ return 0;
+}
+
+
+void
+SplitCacheSet::moveToHead(SplitBlk *blk)
+{
+ // nothing to do if blk is already head
+ if (blks[0] == blk)
+ return;
+
+ // write 'next' block into blks[i], moving up from MRU toward LRU
+ // until we overwrite the block we moved to head.
+
+ // start by setting up to write 'blk' into blks[0]
+ int i = 0;
+ SplitBlk *next = blk;
+
+ do {
+ assert(i < assoc);
+ // swap blks[i] and next
+ SplitBlk *tmp = blks[i];
+ blks[i] = next;
+ next = tmp;
+ ++i;
+ } while (next != blk);
+}
+
+
+// create and initialize a LRU/MRU cache structure
+SplitLRU::SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part) :
+ numSets(_numSets), blkSize(_blkSize), assoc(_assoc), hitLatency(_hit_latency), part(_part)
+{
+ // Check parameters
+ if (blkSize < 4 || !isPowerOf2(blkSize)) {
+ fatal("Block size must be at least 4 and a power of 2");
+ }
+ if (numSets <= 0 || !isPowerOf2(numSets)) {
+ fatal("# of sets must be non-zero and a power of 2");
+ }
+ if (assoc <= 0) {
+ fatal("associativity must be greater than zero");
+ }
+ if (hitLatency <= 0) {
+ fatal("access latency must be greater than zero");
+ }
+
+ SplitBlk *blk;
+ int i, j, blkIndex;
+
+ blkMask = blkSize - 1;
+ setShift = floorLog2(blkSize);
+ setMask = numSets - 1;
+ tagShift = setShift + floorLog2(numSets);
+ warmedUp = false;
+ /** @todo Make warmup percentage a parameter. */
+ warmupBound = numSets * assoc;
+
+ sets = new SplitCacheSet[numSets];
+ blks = new SplitBlk[numSets * assoc];
+ // allocate data storage in one big chunk
+ dataBlks = new uint8_t[numSets*assoc*blkSize];
+
+ blkIndex = 0; // index into blks array
+ for (i = 0; i < numSets; ++i) {
+ sets[i].assoc = assoc;
+
+ sets[i].blks = new SplitBlk*[assoc];
+
+ // link in the data blocks
+ for (j = 0; j < assoc; ++j) {
+ // locate next cache block
+ blk = &blks[blkIndex];
+ blk->data = &dataBlks[blkSize*blkIndex];
+ ++blkIndex;
+
+ // invalidate new cache block
+ blk->status = 0;
+
+ //EGH Fix Me : do we need to initialize blk?
+
+ // Setting the tag to j is just to prevent long chains in the hash
+ // table; won't matter because the block is invalid
+ blk->tag = j;
+ blk->whenReady = 0;
+ blk->isTouched = false;
+ blk->size = blkSize;
+ sets[i].blks[j]=blk;
+ blk->set = i;
+ blk->part = part;
+ }
+ }
+}
+
+SplitLRU::~SplitLRU()
+{
+ delete [] dataBlks;
+ delete [] blks;
+ delete [] sets;
+}
+
+void
+SplitLRU::regStats(const std::string &name)
+{
+ BaseTags::regStats(name);
+
+ hits
+ .name(name + ".hits")
+ .desc("number of hits on this partition")
+ .precision(0)
+ ;
+
+ misses
+ .name(name + ".misses")
+ .desc("number of misses in this partition")
+ .precision(0)
+ ;
+}
+
+// probe cache for presence of given block.
+bool
+SplitLRU::probe(Addr addr) const
+{
+ // return(findBlock(Read, addr, asid) != 0);
+ Addr tag = extractTag(addr);
+ unsigned myset = extractSet(addr);
+
+ SplitBlk *blk = sets[myset].findBlk(tag);
+
+ return (blk != NULL); // true if in cache
+}
+
+SplitBlk*
+SplitLRU::findBlock(Addr addr, int &lat)
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+ lat = hitLatency;
+ if (blk != NULL) {
+ // move this block to head of the MRU list
+ sets[set].moveToHead(blk);
+ if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency){
+ lat = blk->whenReady - curTick;
+ }
+ blk->refCount += 1;
+ hits++;
+ }
+
+ return blk;
+}
+
+SplitBlk*
+SplitLRU::findBlock(Packet * &pkt, int &lat)
+{
+ Addr addr = pkt->getAddr();
+
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+ lat = hitLatency;
+ if (blk != NULL) {
+ // move this block to head of the MRU list
+ sets[set].moveToHead(blk);
+ if (blk->whenReady > curTick && blk->whenReady - curTick > hitLatency){
+ lat = blk->whenReady - curTick;
+ }
+ blk->refCount += 1;
+ hits++;
+ }
+
+ return blk;
+}
+
+SplitBlk*
+SplitLRU::findBlock(Addr addr) const
+{
+ Addr tag = extractTag(addr);
+ unsigned set = extractSet(addr);
+ SplitBlk *blk = sets[set].findBlk(tag);
+ return blk;
+}
+
+SplitBlk*
+SplitLRU::findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks)
+{
+ unsigned set = extractSet(pkt->getAddr());
+ // grab a replacement candidate
+ SplitBlk *blk = sets[set].blks[assoc-1];
+ sets[set].moveToHead(blk);
+ if (blk->isValid()) {
+ replacements[0]++;
+ totalRefs += blk->refCount;
+ ++sampledRefs;
+ blk->refCount = 0;
+ } else if (!blk->isTouched) {
+ tagsInUse++;
+ blk->isTouched = true;
+ if (!warmedUp && tagsInUse.value() >= warmupBound) {
+ warmedUp = true;
+ warmupCycle = curTick;
+ }
+ }
+
+ misses++;
+
+ return blk;
+}
+
+void
+SplitLRU::invalidateBlk(Addr addr)
+{
+ SplitBlk *blk = findBlock(addr);
+ if (blk) {
+ blk->status = 0;
+ blk->isTouched = false;
+ tagsInUse--;
+ }
+}
+
+void
+SplitLRU::doCopy(Addr source, Addr dest, PacketList &writebacks)
+{
+//Copy not supported for now
+#if 0
+ assert(source == blkAlign(source));
+ assert(dest == blkAlign(dest));
+ SplitBlk *source_blk = findBlock(source);
+ assert(source_blk);
+ SplitBlk *dest_blk = findBlock(dest);
+ if (dest_blk == NULL) {
+ // Need to do a replacement
+ Packet * pkt = new Packet();
+ pkt->paddr = dest;
+ BlkList dummy_list;
+ dest_blk = findReplacement(pkt, writebacks, dummy_list);
+ if (dest_blk->isValid() && dest_blk->isModified()) {
+ // Need to writeback data.
+ pkt = buildWritebackReq(regenerateBlkAddr(dest_blk->tag,
+ dest_blk->set),
+ dest_blk->xc,
+ blkSize,
+ (cache->doData())?dest_blk->data:0,
+ dest_blk->size);
+ writebacks.push_back(pkt);
+ }
+ dest_blk->tag = extractTag(dest);
+ /**
+ * @todo Do we need to pass in the execution context, or can we
+ * assume its the same?
+ */
+ assert(source_blk->xc);
+ dest_blk->xc = source_blk->xc;
+ }
+ /**
+ * @todo Can't assume the status once we have coherence on copies.
+ */
+
+ // Set this block as readable, writeable, and dirty.
+ dest_blk->status = 7;
+ if (cache->doData()) {
+ memcpy(dest_blk->data, source_blk->data, blkSize);
+ }
+#endif
+}
+
+void
+SplitLRU::cleanupRefs()
+{
+ for (int i = 0; i < numSets*assoc; ++i) {
+ if (blks[i].isValid()) {
+ totalRefs += blks[i].refCount;
+ ++sampledRefs;
+ }
+ }
+}
diff --git a/src/mem/cache/tags/split_lru.hh b/src/mem/cache/tags/split_lru.hh
new file mode 100644
index 000000000..72aebac9c
--- /dev/null
+++ b/src/mem/cache/tags/split_lru.hh
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/**
+ * @file
+ * Declaration of a LRU tag store for a partitioned cache.
+ */
+
+#ifndef __SPLIT_LRU_HH__
+#define __SPLIT_LRU_HH__
+
+#include <list>
+
+#include "mem/cache/cache_blk.hh" // base class
+#include "mem/cache/tags/split_blk.hh"
+#include "mem/packet.hh" // for inlined functions
+#include <assert.h>
+#include "mem/cache/tags/base_tags.hh"
+
+class BaseCache;
+
+/**
+ * An associative set of cache blocks.
+ */
+
+class SplitCacheSet
+{
+ public:
+ /** The associativity of this set. */
+ int assoc;
+
+ /** Cache blocks in this set, maintained in LRU order 0 = MRU. */
+ SplitBlk **blks;
+
+ /**
+ * Find a block matching the tag in this set.
+ * @param asid The address space ID.
+ * @param tag The Tag to find.
+ * @return Pointer to the block if found.
+ */
+ SplitBlk* findBlk(Addr tag) const;
+
+ /**
+ * Move the given block to the head of the list.
+ * @param blk The block to move.
+ */
+ void moveToHead(SplitBlk *blk);
+};
+
+/**
+ * A LRU cache tag store.
+ */
+class SplitLRU : public BaseTags
+{
+ public:
+ /** Typedef the block type used in this tag store. */
+ typedef SplitBlk BlkType;
+ /** Typedef for a list of pointers to the local block class. */
+ typedef std::list<SplitBlk*> BlkList;
+ protected:
+ /** The number of sets in the cache. */
+ const int numSets;
+ /** The number of bytes in a block. */
+ const int blkSize;
+ /** The associativity of the cache. */
+ const int assoc;
+ /** The hit latency. */
+ const int hitLatency;
+ /** indicator for which partition this is */
+ const int part;
+
+ /** The cache sets. */
+ SplitCacheSet *sets;
+
+ /** The cache blocks. */
+ SplitBlk *blks;
+ /** The data blocks, 1 per cache block. */
+ uint8_t *dataBlks;
+
+ /** The amount to shift the address to get the set. */
+ int setShift;
+ /** The amount to shift the address to get the tag. */
+ int tagShift;
+ /** Mask out all bits that aren't part of the set index. */
+ unsigned setMask;
+ /** Mask out all bits that aren't part of the block offset. */
+ unsigned blkMask;
+
+ /** number of hits in this partition */
+ Stats::Scalar<> hits;
+ /** number of blocks brought into this partition (i.e. misses) */
+ Stats::Scalar<> misses;
+
+public:
+ /**
+ * Construct and initialize this tag store.
+ * @param _numSets The number of sets in the cache.
+ * @param _blkSize The number of bytes in a block.
+ * @param _assoc The associativity of the cache.
+ * @param _hit_latency The latency in cycles for a hit.
+ */
+ SplitLRU(int _numSets, int _blkSize, int _assoc, int _hit_latency, int _part);
+
+ /**
+ * Destructor
+ */
+ virtual ~SplitLRU();
+
+ /**
+ * Register the statistics for this object
+ * @param name The name to precede the stat
+ */
+ void regStats(const std::string &name);
+
+ /**
+ * Return the block size.
+ * @return the block size.
+ */
+ int getBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Return the subblock size. In the case of LRU it is always the block
+ * size.
+ * @return The block size.
+ */
+ int getSubBlockSize()
+ {
+ return blkSize;
+ }
+
+ /**
+ * Search for the address in the cache.
+ * @param asid The address space ID.
+ * @param addr The address to find.
+ * @return True if the address is in the cache.
+ */
+ bool probe(Addr addr) const;
+
+ /**
+ * Invalidate the block containing the given address.
+ * @param asid The address space ID.
+ * @param addr The address to invalidate.
+ */
+ void invalidateBlk(Addr addr);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr, int &lat);
+
+ /**
+ * Finds the given address in the cache and update replacement data.
+ * Returns the access latency as a side effect.
+ * @param pkt The req whose block to find.
+ * @param lat The access latency.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Packet * &pkt, int &lat);
+
+ /**
+ * Finds the given address in the cache, do not update replacement data.
+ * @param addr The address to find.
+ * @param asid The address space ID.
+ * @return Pointer to the cache block if found.
+ */
+ SplitBlk* findBlock(Addr addr) const;
+
+ /**
+ * Find a replacement block for the address provided.
+ * @param pkt The request to a find a replacement candidate for.
+ * @param writebacks List for any writebacks to be performed.
+ * @param compress_blocks List of blocks to compress, for adaptive comp.
+ * @return The block to place the replacement in.
+ */
+ SplitBlk* findReplacement(Packet * &pkt, PacketList &writebacks,
+ BlkList &compress_blocks);
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Generate the tag from the given address.
+ * @param addr The address to get the tag from.
+ * @param blk Ignored.
+ * @return The tag of the address.
+ */
+ Addr extractTag(Addr addr, SplitBlk *blk) const
+ {
+ return (addr >> tagShift);
+ }
+
+ /**
+ * Calculate the set index from the address.
+ * @param addr The address to get the set from.
+ * @return The set index of the address.
+ */
+ int extractSet(Addr addr) const
+ {
+ return ((addr >> setShift) & setMask);
+ }
+
+ /**
+ * Get the block offset from an address.
+ * @param addr The address to get the offset of.
+ * @return The block offset.
+ */
+ int extractBlkOffset(Addr addr) const
+ {
+ return (addr & blkMask);
+ }
+
+ /**
+ * Align an address to the block size.
+ * @param addr the address to align.
+ * @return The block address.
+ */
+ Addr blkAlign(Addr addr) const
+ {
+ return (addr & ~(Addr)blkMask);
+ }
+
+ /**
+ * Regenerate the block address from the tag.
+ * @param tag The tag of the block.
+ * @param set The set of the block.
+ * @return The block address.
+ */
+ Addr regenerateBlkAddr(Addr tag, unsigned set) const
+ {
+ return ((tag << tagShift) | ((Addr)set << setShift));
+ }
+
+ /**
+ * Return the hit latency.
+ * @return the hit latency.
+ */
+ int getHitLatency() const
+ {
+ return hitLatency;
+ }
+
+ /**
+ * Read the data out of the internal storage of the given cache block.
+ * @param blk The cache block to read.
+ * @param data The buffer to read the data into.
+ * @return The cache block's data.
+ */
+ void readData(SplitBlk *blk, uint8_t *data)
+ {
+ memcpy(data, blk->data, blk->size);
+ }
+
+ /**
+ * Write data into the internal storage of the given cache block. Since in
+ * LRU does not store data differently this just needs to update the size.
+ * @param blk The cache block to write.
+ * @param data The data to write.
+ * @param size The number of bytes to write.
+ * @param writebacks A list for any writebacks to be performed. May be
+ * needed when writing to a compressed block.
+ */
+ void writeData(SplitBlk *blk, uint8_t *data, int size,
+ PacketList & writebacks)
+ {
+ assert(size <= blkSize);
+ blk->size = size;
+ }
+
+ /**
+ * Perform a block aligned copy from the source address to the destination.
+ * @param source The block-aligned source address.
+ * @param dest The block-aligned destination address.
+ * @param asid The address space DI.
+ * @param writebacks List for any generated writeback pktuests.
+ */
+ void doCopy(Addr source, Addr dest, PacketList &writebacks);
+
+ /**
+ * No impl.
+ */
+ void fixCopy(Packet * &pkt, PacketList &writebacks)
+ {
+ }
+
+ /**
+ * Called at end of simulation to complete average block reference stats.
+ */
+ virtual void cleanupRefs();
+};
+
+#endif
diff --git a/src/mem/config/cache.hh b/src/mem/config/cache.hh
new file mode 100644
index 000000000..24da04021
--- /dev/null
+++ b/src/mem/config/cache.hh
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/**
+ * @file
+ * Central location to configure which cache types we want to build
+ * into the simulator. In the future, this should probably be
+ * autogenerated by some sort of configuration script.
+ */
+#define USE_CACHE_LRU 1
+#define USE_CACHE_FALRU 1
+// #define USE_CACHE_SPLIT 1
+// #define USE_CACHE_SPLIT_LIFO 1
+#define USE_CACHE_IIC 1
+
diff --git a/src/mem/config/prefetch.hh b/src/mem/config/prefetch.hh
new file mode 100644
index 000000000..d24db79da
--- /dev/null
+++ b/src/mem/config/prefetch.hh
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Central location to configure which prefetch types we want to build
+ * into the simulator. In the future, this should probably be
+ * autogenerated by some sort of configuration script.
+ */
+#define USE_TAGGED 1 //Be sure not to turn this off, it is also used for no
+ //prefetching case unless you always want to use a
+ //different prefetcher
+//#define USE_STRIDED 1
+//#define USE_GHB 1
diff --git a/src/mem/dram.cc b/src/mem/dram.cc
new file mode 100644
index 000000000..d7b955975
--- /dev/null
+++ b/src/mem/dram.cc
@@ -0,0 +1,2746 @@
+/*
+ * Copyright (c) 2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Ron Dreslinski
+ */
+
+/*
+ Copyright (c) 2000 Computer Engineering and Communication Networks Lab (TIK)
+ Swiss Federal Institute of Technology (ETH) Zurich, Switzerland
+
+ All rights reserved.
+ Permission is hereby granted, without written agreement and without
+ license or royalty fees, to use, copy, modify, and distribute this
+ software and its documentation for any purpose, provided that the above
+ copyright notice and the following two paragraphs appear in all copies
+ of this software.
+
+ IN NO EVENT SHALL THE TIK OR THE ETH ZURICH BE LIABLE TO ANY PARTY
+ FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
+ THE TIK OR THE ETH ZURICH HAVE BEEN ADVISED OF THE POSSIBILITY OF
+ SUCH DAMAGE.
+
+ THE TIK AND THE ETH ZURICH SPECIFICALLY DISCLAIM ANY WARRANTIES,
+ INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
+ PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND TIK AND THE ETH ZURICH
+ HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
+ ENHANCEMENTS, OR MODIFICATIONS.
+*/
+
+/* authors: Andreas Romer 4/99 - 7/99
+ Matthias Gries 4/99 - 2/01
+
+
+References: http://www.tik.ee.ethz.ch/
+======================================
+-> Publications http://www.tik.ee.ethz.ch/db/tik/publications/form_search_publications.php3
+
+
+Matthias Gries: A Survey of Synchronous RAM Architectures.
+TIK Report Nr. 71, Computer Engineering and Networks Lab (TIK),
+Swiss Federal Institute of Technology (ETH) Zurich, April, 1999
+
+-> DRAM survey
+
+
+Matthias Gries, Andreas Romer: Performance Evaluation of Recent
+DRAM Architectures for Embedded Systems.
+TIK Report Nr. 82, Computer Engineering and Networks Lab (TIK),
+Swiss Federal Institute of Technology (ETH) Zurich, November, 1999.
+
+-> description of the DRAM and controller models for SimpleScalar in the appendix
+(note that the current software version additionally supports overlapping in
+ closed-page mode with slightly modified timing)
+
+
+Matthias Gries: The Impact of Recent DRAM Architectures on Embedded Systems Performance.
+Euromicro2000, Symposium on Digital Systems Design, IEEE Computer, Maastricht, Netherlands,
+Vol. 1, pages 282-289, September, 2000.
+
+-> performance study with SimpleScalar
+
+
+Matthias Gries: Modeling a Memory Subsystem with Petri Nets: a Case Study.
+A. Yakovlev, L. Gomes, and L. Lavagno (Eds), Hardware Design and Petri Nets,
+Kluwer Academic, pages 291-310, March, 2000.
+
+-> SDRAM + controller performance model as a high-level Petri net
+*/
+
+/**
+ * @file
+ * Definition of a DRAM like main memory.
+ */
+
+
+#include "mem/dram.hh"
+#include "sim/builder.hh"
+
+#include <string>
+
+extern int maxThreadsPerCPU;
+
+/* SDRAM system: PC100/PC133 2-2-2 DIMM timing according to
+ PC SDRAM Specification, Rev. 1.7, Intel Corp, Nov. 1999.
+
+ 64 bit DIMM consists of four 16x organized 256 Mbit SDRAMs, 128 MByte of main memory in total.*/
+/* the settings above must be changed if another memory is used */
+/* DRDRAM system: 16 bit channel, four chips (single RIMM), 128 MByte of main memory in total.
+ Timing: Rambus Inc, Direct RDRAM, preliminary information, 256/288Mbit: 40-800 timing */
+
+
+#define DR_STACK_BASE 0x8000000 /* total size of memory: 128 Mbyte */
+#define DR_BANK_SIZE 0x100000 /* size of a bank : 1 Mbyte */
+#define DR_ROW_SIZE 0x800 /* size of a row : 2 Kbyte */
+#define DR_NUM_BANKS (DR_STACK_BASE/DR_BANK_SIZE) /* number of banks : 128 */
+#define DR_NUM_ROWS (DR_BANK_SIZE/DR_ROW_SIZE) /* number of rows per bank: 512 */
+#define DR_DATA_BASE 0x4000000 /* Size of textsegment : 64 Mbyte */
+#define DR_NUM_BYTE_MEM 16 /* data packet capacity: 16 byte */
+#define DR_NUM_DEVS 4 /* number of devices along channel */
+#define DR_BANK_SAMP 16 /* 16 banks are together in one group in each device: bank 15 and 16 have no shared SAMPs */
+#define DR_T_PACKET 4 /* number of cycles (in 400 MHz) the memory needs to deliver a data packet */
+#define DR_T_RCD 7 /* RAS to CAS delay */
+#define DR_T_CAC 8 /* read access delay: number of cylces from read to data (trailing to leading edge of packet!) */
+#define DR_T_CWD 6 /* Write delay: number of cylces from write to write data (trailing to leading edge of packet!) */
+#define DR_T_RP 8 /* row precharge delay */
+#define DR_T_RTR 8 /* retire delay*/
+#define DR_T_RDP 4 /* min delay from read to precharge in cycles */
+#define DR_T_PP 8 /* precharge to precharge time to any bank in the same device */
+#define DR_T_RAS 20 /* minimal row active time */
+/*the settings above need to be changed if the memory is altered*/
+#define DR_DYNAMIC_SIZE (DR_STACK_BASE - DR_DATA_BASE) /* size of the heap and stack at most: 64 Mbyte */
+// #define DR_NUM_BANKS (DR_STACK_BASE/DR_BANK_SIZE) /* number of banks : 128 */
+// #define DR_NUM_ROWS (DR_BANK_SIZE/DR_ROW_SIZE) /* number of rows per bank: 512 */
+#define DR_T_OWR (DR_T_CWD + DR_T_PACKET - DR_T_RTR) /* overlap after write retire */
+#define DR_T_HELP (DR_T_CAC+DR_T_PACKET-DR_T_RDP+DR_T_PACKET) /* used for read after read with precharge */
+/*delays until data is ready/written to the memory for the DRDRAM*/
+#define DR_T_READ_READ_SROW (DR_T_CAC + DR_T_PACKET) /* RAR, row hit, current bank */
+#define DR_T_READ_WRITE_SROW (DR_T_CAC + DR_T_PACKET) /* RAW, row hit, current bank */
+#define DR_T_WRITE_READ_SROW (DR_T_CWD + DR_T_PACKET) /* WAR, row hit, current bank */
+#define DR_T_WRITE_WRITE_SROW (DR_T_CWD + DR_T_PACKET) /* WAW, row hit, current bank */
+#define DR_T_READ_READ_SBANK (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAR, row miss, current bank */
+#define DR_T_READ_WRITE_SBANK (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, current bank */
+#define DR_T_WRITE_READ_SBANK (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, current bank */
+#define DR_T_WRITE_WRITE_SBANK (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, current bank */
+#define DR_T_READ_READ_OBANK (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAR, row miss, another bank */
+#define DR_T_READ_WRITE_OBANK (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, another bank */
+#define DR_T_WRITE_READ_OBANK (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, another bank */
+#define DR_T_WRITE_WRITE_OBANK (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAR, row miss, another bank */
+/* best-case latencies (due to overlap / row hits in another bank) */
+#define DR_BEST_T_READ_READ_SROW 0 /* RAR, row hit, current bank */
+#define DR_BEST_T_READ_WRITE_SROW (DR_T_CAC+DR_T_PACKET-DR_T_OWR) /* RAW, row hit, current bank */
+#define DR_BEST_T_WRITE_READ_SROW 0 /* WAR, row hit, current bank */
+#define DR_BEST_T_WRITE_WRITE_SROW (DR_T_CWD+DR_T_PACKET-DR_T_OWR) /* WAR, row hit, current bank */
+#define DR_BEST_T_READ_READ_SBANK (DR_T_RCD + DR_T_CAC) /* RAR, row miss, current bank */
+#define DR_BEST_T_READ_WRITE_SBANK (DR_T_RP-DR_T_OWR+DR_T_RCD+DR_T_CAC+DR_T_PACKET) /* RAW, row miss, current bank */
+#define DR_BEST_T_WRITE_READ_SBANK (DR_T_RCD+DR_T_CWD) /* WAR, row miss, current bank */
+#define DR_BEST_T_WRITE_WRITE_SBANK (DR_T_RP-DR_T_OWR+DR_T_RCD+DR_T_CWD+DR_T_PACKET) /* WAW, row miss, current bank */
+#define DR_BEST_T_READ_READ_OBANK 0 /* RAR, row miss/hit, another bank */
+#define DR_BEST_T_READ_WRITE_OBANK (DR_T_PACKET+DR_T_CAC-DR_T_OWR) /* RAW, row miss/hit, another bank */
+#define DR_BEST_T_WRITE_READ_OBANK 0 /* WAR, row miss/hit, another bank */
+#define DR_BEST_T_WRITE_WRITE_OBANK 0 /* WAW, row miss/hit, another bank */
+#define DR_BEST_T_READ_WRITE_ODEV (DR_T_CAC-DR_T_CWD) /* RAW, row miss/hit, another device */
+
+
+#define MIN(a,b) ((a<b) ? a : b)
+#define SD_ROW_SIZE 0x1000 /* size of a row : 4 Kbyte */
+
+
+
+DRAMMemory::DRAMMemory(Params *p)
+ : PhysicalMemory(p), cpu_ratio(p->cpu_ratio), bus_width(p->bus_width),
+ mem_type(p->mem_type), mem_actpolicy(p->mem_actpolicy),
+ memctrladdr_type(p->memctrladdr_type), act_lat(p->act_lat),
+ cas_lat(p->cas_lat), war_lat(p->war_lat),
+ pre_lat(p->pre_lat), dpl_lat(p->dpl_lat),
+ trc_lat(p->trc_lat), num_banks(p->num_banks),
+ num_cpus(p->num_cpus), last_dev(DR_NUM_DEVS+1),
+ lastCmdIsRead(true), precharge(0), same_row_read_access(0), srr_after_read(0),
+ srr_after_write(0), same_row_write_access(0), srw_after_read(0),
+ srw_after_write(0), same_bank_read_access(0), sbr_after_read(0),
+ sbr_after_write(0), same_bank_write_access(0), sbw_after_read(0),
+ sbw_after_write(0), other_bank_read_access_hit(0), obr_after_read_hit(0),
+ obr_after_write_hit(0), other_bank_write_access_hit(0),
+ obw_after_read_hit(0), obw_after_write_hit(0), obr_after_read_miss(0),
+ obr_after_write_miss(0),
+ obw_after_read_miss(0), obw_after_write_miss(0), total_access(0),
+ adjacent_access(0), adjacent_read(0), adjacent_write(0),
+ command_overlapping(0), best_case(0), in_between_case(0), worst_case(0),
+ full_overlapping(0), partial_overlapping(0), mem_access_details(false),
+ memctrlpipe_enable(false), time_last_access(0)
+{
+ warn("This DRAM module has not been tested with the new memory system at all!");
+ bank_size = (params()->addrRange.size() + 1) / num_banks;
+ num_rows = bank_size / SD_ROW_SIZE; /* 0x1000 size of row 4Kbtye */
+ active_row = new int[num_banks];
+ last_bank = num_banks+1;
+ last_row = num_rows;
+ busy_until = new Tick[num_banks];
+ memset(busy_until,0,sizeof(Tick)*num_banks); /* initiliaze */
+
+}
+
+void
+DRAMMemory::regStats()
+{
+ using namespace Stats;
+
+ accesses
+ .init(maxThreadsPerCPU)
+ .name(name() + ".accesses")
+ .desc("total number of accesses")
+ .flags(total)
+ ;
+
+ bytesRequested
+ .init(maxThreadsPerCPU)
+ .name(name() + ".bytes_requested")
+ .desc("total number of bytes requested")
+ .flags(total)
+ ;
+
+ bytesSent
+ .init(maxThreadsPerCPU)
+ .name(name() + ".bytes_sent")
+ .desc("total number of bytes sent")
+ .flags(total)
+ ;
+
+ compressedAccesses
+ .init(maxThreadsPerCPU)
+ .name(name() + ".compressed_responses")
+ .desc("total number of accesses that are compressed")
+ .flags(total)
+ ;
+
+ // stats for power modelling
+ cycles_nCKE
+ .init(1)
+ .name(name() + ".cycles_nCKE")
+ .desc("cycles when CKE is low")
+ .flags(total)
+ ;
+
+ cycles_all_precharge_CKE
+ .init(1)
+ .name(name() + ".cycles_all_precharge_CKE")
+ .desc("cycles when all banks precharged")
+ .flags(total)
+ ;
+
+ cycles_all_precharge_nCKE
+ .init(1)
+ .name(name() + ".cycles_all_precharge_nCKE")
+ .desc("cycles when all banks precharged and CKE is low")
+ .flags(total)
+ ;
+
+ cycles_bank_active_nCKE
+ .init(1)
+ .name(name() + ".cycles_bank_active_nCKE")
+ .desc("cycles when banks active and CKE low")
+ .flags(total)
+ ;
+
+ // we derive this from other stats later
+ // so DR TODO for now this counter is unused
+ cycles_avg_ACT
+ .init(1)
+ .name(name() + ".cycles_avg_ACT")
+ .desc("avg cycles between ACT commands")
+ .flags(total)
+ ;
+
+ cycles_read_out
+ .init(1)
+ .name(name() + ".cycles_read_out")
+ .desc("cycles outputting read data")
+ .flags(total)
+ ;
+
+ cycles_write_in
+ .init(1)
+ .name(name() + ".cycles_write_in")
+ .desc("cycles inputting write data")
+ .flags(total)
+ ;
+
+ cycles_between_misses
+ .init(1)
+ .name(name() + ".cycles_between_misses")
+ .desc("cycles between open page misses")
+ .flags(total)
+ ;
+
+ other_bank_read_access_miss
+ .init(1)
+ .name(name() + ".other_bank_read_access_miss")
+ .desc("read miss count")
+ .flags(total)
+ ;
+
+ other_bank_write_access_miss
+ .init(1)
+ .name(name() + ".other_bank_write_access_miss")
+ .desc("write miss count")
+ .flags(total)
+ ;
+
+ // DR TODO for now, only output stats which are involved in power equations
+ total_latency
+ .name(name() + ".total_latency")
+ .desc("total DRAM latency")
+ ;
+
+ total_arb_latency
+ .name(name() + ".total_arb_latency")
+ .desc("total arbitration latency")
+ ;
+
+ avg_latency
+ .name(name() + ".avg_latency")
+ .desc("average DRAM latency")
+ ;
+
+ avg_arb_latency
+ .name(name() + ".avg_arb_latency")
+ .desc("average arbitration DRAM latency")
+ ;
+
+ bank_access_profile
+ .init(num_banks,num_cpus)
+ .name(name() + "[cpu][bank]")
+ .desc("DRAM bank access profile")
+ ;
+
+ total_icache_req
+ .name(name() + ".total_icache_req")
+ .desc("total number of requests from icache")
+ ;
+
+ avg_latency = total_latency / accesses;
+ avg_arb_latency = total_arb_latency / accesses;
+}
+
+
+
+
+// DR DEBUG: assume we have a 500 MHz CPU and 100 MHz RAM
+// static float cpu_ratio = 5; // ratio between CPU speed and memory bus speed
+// DR TODO: get this parameter from the simulation
+
+static char *mem_access_output=NULL;
+ /* latency of access [CPU cycles]*/
+Tick
+DRAMMemory::calculateLatency(Packet *pkt)
+{
+
+ bool cmdIsRead = pkt->isRead();
+
+ int lat=0, temp=0, current_bank=0;
+ int current_row=0, current_device=0;
+
+ int was_miss = 0; // determines if there was an active row miss this access
+
+ //md_addr_t physic_address; /* linear memory address to be accessed */
+ Addr physic_address; /* linear memory address to be accessed */
+
+ int num_blocks=0;
+ int corrected_overlap, /* overlap of consecutive accesses [CPU cycles] */
+ overlap=0; /* overlap of consecutive accesses [mem bus cycles] */
+ int adjacent=0; /* 1 indicates that current bank is adjacent to the last accessed one*/
+
+ int chunks = (pkt->getSize() + (bus_width - 1)) / bus_width; // burst length
+ assert(chunks >0);
+ physic_address = pkt->getAddr();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // DR added more stats for power modelling
+ // NOTE:
+ // for DRAM closed-page, automatic precharge after read or write,
+ // i.e. whenever idle
+
+
+ // count number of cycles where dram is not busy, use for CKE low signal
+ // calculate as percentage of all clock cycles
+ // if busy, do not add to idle count. Else add cycles since last access
+/* #define SD_NUM_BANKS (SD_STACK_BASE/SD_BANK_SIZE) */ /* number of banks */
+/* #define SD_NUM_ROWS (SD_BANK_SIZE/SD_ROW_SIZE) */ /* number of rows per bank */
+/*delays until data is ready/written to the memory for the SDRAM*/
+ int SD_T_READ_READ_SROW = cas_lat; /* RAR, row hit, current bank */
+ int SD_T_READ_WRITE_SROW = cas_lat; /* RAW, row hit, current bank */
+ int SD_T_WRITE_READ_SROW = war_lat-1; /* WAR, row hit, current bank */
+ int SD_T_WRITE_WRITE_SROW = 0; /* WAW, row hit, current bank */
+ int SD_T_READ_READ_SBANK = (pre_lat+act_lat+cas_lat); /* RAR, row miss, current bank */
+ int SD_T_READ_WRITE_SBANK = (pre_lat+act_lat+cas_lat+(dpl_lat-1)); /* RAW, row miss, current bank */
+ int SD_T_WRITE_READ_SBANK = (pre_lat+act_lat); /* WAR, row miss, current bank */
+ int SD_T_WRITE_WRITE_SBANK = (pre_lat+act_lat+(dpl_lat-1)); /* WAW, row miss, current bank */
+ int SD_T_READ_READ_OBANK = (pre_lat+act_lat+cas_lat); /* RAR, row miss, another bank */
+ int SD_T_READ_WRITE_OBANK = (pre_lat+act_lat+cas_lat); /* RAW, row miss, another bank */
+ int SD_T_WRITE_READ_OBANK = (pre_lat+act_lat); /* WAR, row miss, another bank */
+ int SD_T_WRITE_WRITE_OBANK = (pre_lat+act_lat); /* WAW, row miss, another bank */
+/* best-case latencies (due to overlap / row hits in another bank) */
+ int SD_BEST_T_READ_READ_SROW = 0; /* RAR, row hit, current bank */
+ int SD_BEST_T_READ_READ_SBANK = (act_lat+cas_lat); /* RAR, row miss, current bank */
+ int SD_BEST_T_WRITE_READ_SBANK = (act_lat); /* WAR, row miss, current bank */
+ int SD_BEST_T_READ_READ_OBANK = 0; /* RAR, row miss/hit, another bank */
+ int SD_BEST_T_READ_WRITE_OBANK = cas_lat; /* RAW, row miss/hit, another bank */
+ int SD_BEST_T_WRITE_READ_OBANK = (war_lat -1); /* WAR, row miss/hit, another bank */
+ int SD_BEST_T_WRITE_WRITE_OBANK = 0; /* WAW, row miss/hit, another bank */
+
+ Tick time_since_last_access = curTick-time_last_access;
+ Tick time_last_miss = 0; // used for keeping track of times between activations (page misses)
+ //int was_idle = (curTick > busy_until);
+ bool srow_flag = false;
+ int timing_correction = 0;
+
+ int was_idle = (curTick > busy_until[current_bank]);
+ cycles_nCKE[0] += was_idle ? MIN(curTick-busy_until[current_bank], time_since_last_access) : 0;
+
+ // bank is precharged
+ //active_row[current_bank] == DR_NUM_ROWS
+ int all_precharged = 1;
+ int bank_max = num_banks;
+ int row_max = num_rows;
+
+ if( (mem_type == "SDRAM") && (mem_actpolicy == "closed") ) {
+ // SDRAM does not use the active_row array in closed_page mode
+ // TODO: handle closed page operation
+
+ } else { // DRDRAM uses the active_row array
+ for( int i = 0; i < bank_max; i++ ) {
+ if( (active_row[current_bank] != row_max)) all_precharged = 0;
+ }
+ }
+
+ if(all_precharged) {
+ if(was_idle) {
+ cycles_all_precharge_nCKE[0] += MIN(curTick-busy_until[current_bank], time_since_last_access);
+ cycles_all_precharge_CKE[0] += MIN(0, busy_until[current_bank]-time_last_access);
+ }
+ else {
+ cycles_all_precharge_CKE[0] += time_since_last_access;
+ }
+ } else { // some bank is active
+ if(was_idle) {
+ cycles_bank_active_nCKE[0] += MIN(curTick-busy_until[current_bank], time_since_last_access);
+ }
+ else {
+ }
+ }
+
+ if( cmdIsRead ) {
+ cycles_read_out[0] += chunks;
+ } else {
+ cycles_write_in[0] += chunks;
+ }
+
+
+ time_last_access = curTick;
+ ////////////////////////////////////////////////////////////////////////////
+
+ if ((mem_type == "SDRAM") && (mem_actpolicy == "open"))
+ {
+ /* Split transaction on m5 makes it challenging to */
+ /* model the DRAM. A single cycle latency is assumed */
+ /* for dequeueing an address bus request. In response to */
+ /* that, the current DRAM implementation assumes that a */
+ /* seperate DRAM command generator / controller exists per */
+ /* bank and the dequeued addresses are queued to these */
+ /* controllers. We can view this as an ideal scenario for */
+ /* a shared DRAM command generator / controller with */
+ /* support for overlapping DRAM commands. */
+ /* Compare DRAM PRE,ACT,CAS etc. latencies, DRAM clock */
+ /* frequency and the number of banks to determine whether */
+ /* the ideal scenario with a shared DRAM command generator */
+ /* is equivalent to having multiple DRAM command generators */
+ /* per bank */
+ if ((memctrladdr_type != "interleaved"))/* i.e. mc_type is linear */
+ {
+ current_bank=physic_address/bank_size;
+ temp=physic_address-current_bank*bank_size;/*address in bank*/
+ current_row=temp/SD_ROW_SIZE;
+ }
+ else/* mc_type interleaved */
+ /* This memory controller maps the addresses differently
+ * depending on the row_size, every row is mapped to another
+ * bank. Thus, the text segment uses half of every bank, the heap
+ * the next quarter of each bank, and the stack the rest.
+ */
+
+ {
+ num_blocks = physic_address/SD_ROW_SIZE; /* row number */
+ current_bank=num_blocks%num_banks;
+ current_row=num_blocks/num_banks;
+ }
+
+ if (mem_access_details == true)
+ {
+ // DR TODO
+ //fprintf(mem_accessfd," %09u %4d %3d\n",physic_address,current_row,current_bank);
+ }
+ else
+ {
+ if (mem_access_output!=0)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ }
+ total_access++;
+
+ if (memctrlpipe_enable == true)
+ {
+ overlap=(int)(busy_until[current_bank] - curTick);
+ }
+ else overlap = 0;
+
+ if (cpu_ratio < 1.0)
+ {
+ corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
+ }
+ else
+ {
+ corrected_overlap = (int) (overlap/cpu_ratio);
+ }
+
+ /*fprintf(stderr,"%10.0f %10.0f %4d %4d ",(double)busy_until, (double)curTick, overlap, corrected_overlap); debugging*/
+
+ if (cmdIsRead == lastCmdIsRead)/*same command*/
+ {
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if (current_row == last_row)/*same row*/
+ {
+ /* Page Hit */
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ /*best case*/
+ if (corrected_overlap >= cas_lat)
+ {
+ lat=SD_BEST_T_READ_READ_SROW;
+ srow_flag = true;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = cas_lat-corrected_overlap;
+ srow_flag = true;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else
+ {
+ /*worst case*/
+ lat = SD_T_READ_READ_SROW;
+ srow_flag = true;
+ worst_case++;
+ }
+ same_row_read_access++;
+ srr_after_read++;
+ }
+ else/*write*/
+ {/*no option case*/
+ lat = SD_T_WRITE_WRITE_SROW;
+ srow_flag = true;
+ same_row_write_access++;
+ srw_after_write++;
+ worst_case++;
+ }
+ }
+ else /*other row in same bank*/
+ {
+ /* Page miss */
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ if (corrected_overlap >= pre_lat)/*best case*/
+ {
+ lat = SD_BEST_T_READ_READ_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_READ_READ_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_READ_READ_SBANK;
+ worst_case++;
+ }
+ same_bank_read_access++;
+ sbr_after_read++;
+ }
+ else/*write*/
+ {/*no option case*/
+ lat = SD_T_WRITE_WRITE_SBANK;
+ same_bank_write_access++;
+ sbw_after_write++;
+ worst_case++;
+ }
+ }
+ }
+ else /*other bank*/
+ {
+ if (cmdIsRead)
+ {
+ /* Page empty */
+ if (current_row == active_row[current_bank])/*row is still active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= pre_lat)/*best case*/
+ {
+ lat = SD_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_READ_READ_OBANK - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_READ_READ_OBANK;
+ in_between_case++;
+ }
+ other_bank_read_access_hit++;
+ obr_after_read_hit++;
+ }
+ else/*row is not active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= SD_T_READ_READ_OBANK )/*best case*/
+ {
+ lat = SD_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_READ_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_READ_READ_OBANK;
+ worst_case++;
+ }
+
+ // DR keep track of time between misses
+ was_miss = 1;
+
+ other_bank_read_access_miss[0]++;
+ obr_after_read_miss++;
+ }
+ }
+ else/*write*/
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ { /*best_case*/
+ lat = SD_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ other_bank_write_access_hit++;
+ obw_after_write_hit++;
+ }
+ else/*row is not active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >=SD_T_WRITE_WRITE_OBANK)/*best case*/
+ {
+ lat = SD_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_WRITE_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_WRITE_WRITE_OBANK;
+ worst_case++;
+ }
+
+ // DR keep track of time between misses
+ was_miss = 1;
+
+ other_bank_write_access_miss[0]++;
+ obw_after_write_miss++;
+
+ }
+ }
+ }
+ }
+ else /*lastCmdIsRead != cmdIsRead*/
+ {
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if (current_row == last_row)/*same row*/
+ {
+ /* Page Hit */
+ if (cmdIsRead)
+ {/*worst case*/
+ lat = SD_T_READ_WRITE_SROW;
+ srow_flag = true;
+ same_row_read_access++;
+ srr_after_write++;
+ worst_case++;
+ }
+ else/*write*/
+ {/*worst case*/
+ lat = SD_T_WRITE_READ_SROW;
+ srow_flag = true;
+ same_row_write_access++;
+ srw_after_read++;
+ worst_case++;
+ }
+ }
+ else /*other row in same bank*/
+ {
+ /* Page Miss */
+ if (cmdIsRead)
+ {/*worst case*/
+ lat = SD_T_READ_WRITE_SBANK;
+ same_bank_read_access++;
+ sbr_after_write++;
+ worst_case++;
+ }
+ else/*write*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (corrected_overlap >= pre_lat)/*best case*/
+ {
+ lat = SD_BEST_T_WRITE_READ_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_WRITE_READ_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_WRITE_READ_OBANK;
+ worst_case++;
+ }
+ same_bank_write_access++;
+ sbw_after_read++;
+ }
+ }
+ }
+ else /*other bank*/
+ {
+ /* Page empty */
+ if (cmdIsRead)
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ { /*best case*/
+ lat = SD_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ other_bank_read_access_hit++;
+ obr_after_write_hit++;
+ }
+ else/*row is not active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (pre_lat+act_lat))/*best case*/
+ {
+ lat = SD_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_READ_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_READ_WRITE_OBANK;
+ worst_case++;
+ }
+ // DR keep track of time between misses
+ was_miss = 1;
+
+ other_bank_read_access_miss[0]++;
+ obr_after_write_miss++;
+ }
+ }
+ else/*write*/
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ { /*best case*/
+ lat = SD_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ other_bank_write_access_hit++;
+ obw_after_read_hit++;
+ }
+ else/*row is not active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (corrected_overlap >= (SD_T_WRITE_READ_OBANK-SD_BEST_T_WRITE_READ_OBANK))/*best case*/
+ {/*best case*/
+ lat = SD_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = SD_T_WRITE_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = SD_T_WRITE_READ_OBANK;
+ worst_case++;
+ }
+
+ // DR keep track of time between misses
+ was_miss = 1;
+
+ other_bank_write_access_miss[0]++;
+ obw_after_read_miss++;
+ }
+ }
+ }
+ }
+ /*fprintf(stderr,"%4d %4d ",lat,active_row[current_bank]);debugging*/
+
+ lat += chunks; /* burst length added*/
+ if(srow_flag == false)
+ timing_correction = cpu_ratio*(trc_lat - pre_lat - act_lat - cas_lat - 1);
+
+
+ /*fprintf(stderr,"%4d ",lat);debugging*/
+
+ active_row[current_bank]=current_row; /* open-page (hit) register */
+ lastCmdIsRead = cmdIsRead;
+ last_bank = current_bank;
+ last_row = current_row;
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ /*fprintf(stderr,"%4d \n",lat);debugging*/
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ if (memctrlpipe_enable == true)
+ {
+ busy_until[current_bank]=curTick+lat+
+ timing_correction;
+ }
+ else
+ {
+ if (busy_until[current_bank] >= curTick)
+ {
+ busy_until[current_bank]+=(lat+
+ timing_correction);
+ total_arb_latency += (busy_until[current_bank]
+ - curTick - lat
+ - timing_correction);
+ lat=busy_until[current_bank] - curTick;
+ }
+ else busy_until[current_bank]=curTick+lat+
+ timing_correction;
+ }
+ }
+ else/*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] +=(lat+
+ timing_correction);
+ command_overlapping++;
+ lat+=overlap;
+ total_arb_latency += overlap;
+ }
+
+ // DR for power stats
+ if( was_miss ) {
+ cycles_between_misses[0] += (busy_until[current_bank] - time_last_miss);
+ time_last_miss = busy_until[current_bank];
+ }
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // bank_access_profile[_cpu_num][current_bank]++;
+
+ return lat;
+ }
+
+
+ /***********************************************************/
+ /******************** DRDRAM ***********************/
+ /***********************************************************/
+
+ else if ((mem_type == "DRDRAM") && (mem_actpolicy == "open"))/*DRDRAM*/ /*a closed bank has an activ_row number of DR_NUM_ROWS: highest +1*/
+ {
+ if ((memctrladdr_type != "interleaved"))/* i.e. mc_type is linear */
+ {
+ current_bank=physic_address/DR_BANK_SIZE;
+ temp=physic_address-current_bank*DR_BANK_SIZE;/*address in bank*/
+ current_row=temp/DR_ROW_SIZE;
+ current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
+ }
+
+ else/*mc_type interleaved*/
+ /* This memory controller maps the addresses differently
+ * depending on the row-size, every row is mapped to another
+ * bank. So the text segment uses half of every bank. The heap
+ * the next quarter of each bank and the stack the rest.
+ */
+
+ {
+ num_blocks = physic_address/DR_ROW_SIZE; /* row number */
+ current_bank=(num_blocks%DR_NUM_BANKS)*2; /*every 'second' bank will be used*/
+ /*banks above DR_NUM_BANKS are the uneven banks*/
+ current_bank = ((current_bank < DR_NUM_BANKS) ? current_bank:(current_bank - DR_NUM_BANKS+1));
+ current_row=num_blocks/DR_NUM_BANKS;
+ current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
+ }
+ if (abs(current_bank-last_bank)==1)/*access to an adjacent bank*/
+ {
+ if (!((current_bank%DR_BANK_SAMP == (DR_BANK_SAMP-1))&&(last_bank%DR_BANK_SAMP == 0))/*not 15/16 (current/last)*/
+ &&(!((last_bank%DR_BANK_SAMP == (DR_BANK_SAMP-1))&&(current_bank%DR_BANK_SAMP == 0))))/*not 16/15(current/last)*/
+ {
+ adjacent_access++;
+ adjacent=1;/*an adjacent bank is accessed*/
+ if (cmdIsRead)
+ adjacent_read++;
+ else
+ adjacent_write++;
+ }
+ }
+ precharge=0;/*at this moment no bank needs to be precharged*/
+ if (active_row[current_bank] == DR_NUM_ROWS)/*bank is precharged*/
+ {
+ if (prechargeBanksAround(current_bank)> 0)/*a bank next to the current is activated*/
+ {
+ if ((adjacent==1)&&(precharge==1))
+ {
+ /*since adjacent banks share SAMPs, this access would be the same as (in terms of latency)
+ *an access to another row in the same bank if only one adjacent bank was active*/
+ last_bank = current_bank;
+ last_row = current_row+1;
+ precharge=0;/*set to 0 for next memory access*/
+ }
+ }
+ }
+ if (mem_access_details == true)
+ {
+ //fprintf(mem_accessfd," %09u %4d %3d %15d\n",physic_address,current_row,current_bank,(int)adjacent_access);
+ }
+ else
+ {
+ if (mem_access_output!=NULL)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ }
+ total_access++;
+
+ if (memctrlpipe_enable == true)
+ {
+ overlap=(int)(busy_until[current_bank] - curTick);
+ }
+ else overlap=0;
+
+ if (cpu_ratio < 1.0)
+ {
+ corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
+ }
+ else
+ {
+ corrected_overlap = (int) (overlap/cpu_ratio);
+ }
+
+ /*fprintf(stderr,"%10.0f %10.0f %6d %6d %2d %2d ",(double)busy_until, (double)curTick, overlap, corrected_overlap,precharge,adjacent);debugging*/
+
+ if (cmdIsRead == lastCmdIsRead)/*same command*/
+ {
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if (current_row == last_row)/*same row*/
+ {
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ /*best case*/
+ if (corrected_overlap >= DR_T_READ_READ_SROW)
+ {
+ lat=DR_BEST_T_READ_READ_SROW;
+ srow_flag = true;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_READ_SROW-corrected_overlap;
+ srow_flag = true;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else
+ {
+ /*worst case*/
+ lat = DR_T_READ_READ_SROW;
+ srow_flag = true;
+ worst_case++;
+ }
+ same_row_read_access++;
+ srr_after_read++;
+ }
+ else/*write, always retire the previous data*/
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ /*best case*/
+ if (corrected_overlap >= DR_T_OWR)
+ {
+ lat=DR_BEST_T_WRITE_WRITE_SROW;
+ srow_flag = true;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_WRITE_SROW-corrected_overlap;
+ srow_flag = true;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else
+ {
+ /*worst case*/
+ lat = DR_T_WRITE_WRITE_SROW;
+ srow_flag = true;
+ worst_case++;
+ }
+ same_row_write_access++;
+ srw_after_write++;
+ }
+ }
+ else /*other row in same bank*/
+ {
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ if (corrected_overlap >= DR_T_HELP)/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_READ_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_READ_SBANK;
+ worst_case++;
+ }
+ same_bank_read_access++;
+ sbr_after_read++;
+ }
+ else/*write*/
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ if (corrected_overlap >= DR_T_OWR)/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_WRITE_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_WRITE_SBANK;
+ worst_case++;
+ }
+ same_bank_write_access++;
+ sbw_after_write++;
+ }
+ }
+ }
+ else /*other bank*/
+ {
+ if (cmdIsRead)
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_CAC+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ other_bank_read_access_hit++;
+ obr_after_read_hit++;
+ }
+ else/*row is not active or bank is precharged/not active*/
+ {
+ if (active_row[current_bank]!=DR_NUM_ROWS)/*row is not active, but bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*current_row == DR_NUM_ROWS:precharged or inactive*/
+ {
+ if(precharge == 0)/*no adjacent bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*one ore two adjacent banks are active*/
+ {
+ if (precharge == 1)
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET);
+ in_between_case++;
+ }
+ }
+ else /*precharge ==2: two rows must be precharged*/
+ {
+ if (adjacent == 1)/*these banks are adjacent*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_PP+2*DR_T_PACKET-DR_T_RDP+DR_T_CAC)/*best case*/
+ {
+ lat = DR_T_RDP+DR_T_RP+DR_T_RCD-DR_T_PACKET;
+ in_between_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_READ_OBANK;
+ worst_case++;
+ }
+ }
+ else/*adjacent == 0: two not adjacent banks need to be precharged*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_READ_READ_OBANK)/*best case*/
+ {
+ lat = DR_BEST_T_READ_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_READ_OBANK;
+ worst_case++;
+ }
+ }
+ }
+ }
+ }
+ other_bank_read_access_miss[0]++;
+ obr_after_read_miss++;
+ }
+ }
+ else/*write*/
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ other_bank_write_access_hit++;
+ obw_after_write_hit++;
+ }
+ else/*row is not active or bank is precharged/not active*/
+ {
+ if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*current_row == DR_NUM_ROWS:precharged or inactive*/
+ {
+ if(precharge == 0)/*no adjacent bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*one ore two adjacent banks are active*/
+ {
+ if (precharge == 1)/*last_bank is no adjacent*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET)-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET);
+ in_between_case++;
+ }
+ }
+ else /*precharge ==2: two rows have to be precharged*/
+ {
+ if (adjacent == 1)/*these banks are adjacent*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_OWR+DR_T_PP)/*best case*/
+ {
+ lat = DR_T_WRITE_WRITE_OBANK-DR_T_OWR-DR_T_PP;
+ in_between_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_WRITE_OBANK;
+ worst_case++;
+ }
+ }
+ else/*adjacent == 0: two not adjacent banks need to be precharged*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_WRITE_WRITE_OBANK)/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_WRITE_OBANK;
+ worst_case++;
+ }
+ }
+ }
+ }
+ }
+ other_bank_write_access_miss[0]++;
+ obw_after_write_miss++;
+ }
+ }
+ }
+ }
+ else /*lastCmdIsRead != cmdIsRead*/
+ {
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if (current_row == last_row)/*same row*/
+ {
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ /*best case*/
+ if (corrected_overlap >= DR_T_OWR)
+ {
+ lat=DR_BEST_T_READ_WRITE_SROW;
+ srow_flag = true;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_WRITE_SROW-corrected_overlap;
+ srow_flag = true;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else
+ {
+ /*worst case*/
+ lat = DR_T_READ_WRITE_SROW;
+ srow_flag = true;
+ worst_case++;
+ }
+ same_row_read_access++;
+ srr_after_write++;
+ }
+ else/*write*/
+ {
+ if (corrected_overlap > 0)/*overlapping*/
+ {
+ /*best case*/
+ if (corrected_overlap >= DR_T_WRITE_READ_SROW)
+ {
+ lat=DR_BEST_T_WRITE_READ_SROW;
+ srow_flag = true;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_READ_SROW-corrected_overlap;
+ srow_flag = true;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else
+ {
+ /*worst case*/
+ lat = DR_T_WRITE_READ_SROW;
+ srow_flag = true;
+ worst_case++;
+ }
+ same_row_write_access++;
+ srw_after_read++;
+ }
+ }
+ else /*other row in same bank*/
+ {
+ if (cmdIsRead)
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (corrected_overlap >= DR_T_OWR)/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_WRITE_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_WRITE_SBANK;
+ worst_case++;
+ }
+ same_bank_read_access++;
+ sbr_after_write++;
+ }
+ else/*write*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (corrected_overlap >= DR_T_HELP)/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_SBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_READ_SBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_READ_SBANK;
+ worst_case++;
+ }
+ same_bank_write_access++;
+ sbw_after_read++;
+ }
+ }
+ }
+ else /*other bank*/
+ {
+ if (cmdIsRead)
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(last_dev != current_device)
+ {
+ if(corrected_overlap >= DR_T_CWD+DR_T_PACKET)/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_ODEV;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else /* same device */
+ {
+ if(corrected_overlap >= DR_T_OWR)/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ }
+ else/*in between case, no overlap*/
+ {
+ lat = DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ other_bank_read_access_hit++;
+ obr_after_write_hit++;
+ }
+
+ else/*row is not active or bank is precharged/not active*/
+ {
+ if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (last_dev != current_device)
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_ODEV;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else /* same device */
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*current_row == DR_NUM_ROWS:precharged or inactive*/
+ {
+ if(precharge == 0)/*no adjacent bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(last_dev != current_device)
+ {
+ if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_ODEV;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else /* same device */
+ {
+ if(corrected_overlap >= (DR_T_RCD+DR_T_OWR))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RCD+DR_T_CAC+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*one or two adjacent banks are active*/
+ {
+ if (precharge == 1)/*an adjacent bank (!=last_bank) needs to be precharged*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(last_dev != current_device)
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_ODEV;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else /* same device */
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET)-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ }
+ else/*worst case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CAC+DR_T_PACKET);
+ in_between_case++;
+ }
+ }
+ else /*precharge ==2: two rows have to be precharged*/
+ {
+ if (adjacent == 1) /* the banks are adjacent */
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_OWR + DR_T_PP)/*best case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK-DR_T_OWR - DR_T_PP;
+ in_between_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK;
+ worst_case++;
+ }
+ }
+ else/*adjacent == 0: two not adjacent banks need to be precharged*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if (last_dev != current_device)
+ {
+ if(corrected_overlap >= (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_ODEV;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else /* same device */
+ {
+ if(corrected_overlap >= (DR_T_PP+DR_T_RP+DR_T_RCD+DR_T_OWR))/*best case*/
+ {
+ lat = DR_BEST_T_READ_WRITE_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_READ_WRITE_OBANK;
+ worst_case++;
+ }
+ }
+ }
+ }
+ }
+ other_bank_read_access_miss[0]++;
+ obr_after_write_miss++;
+ }
+ }
+ else/*write*/
+ {
+ if (current_row == active_row[current_bank])/*row is still active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_CWD+DR_T_PACKET)/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ other_bank_write_access_hit++;
+ obw_after_read_hit++;
+ }
+ else/*row is not active or bank is precharged/not active*/
+ {
+ if (active_row[current_bank] != DR_NUM_ROWS)/*row is not active,but bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*current_row == DR_NUM_ROWS:precharged or inactive*/
+ {
+ if(precharge == 0)/*no adjacent bank is active*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_RCD+DR_T_CWD+DR_T_PACKET;
+ in_between_case++;
+ }
+ }
+ else/*one or two adjacent banks are active*/
+ {
+ if (precharge == 1)/*an adjacent bank (!=last_bank) needs to be precharged first*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET))/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET)-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = (DR_T_RP+DR_T_RCD+DR_T_CWD+DR_T_PACKET);
+ in_between_case++;
+ }
+ }
+ else /*precharge ==2: two rows have to be precharged*/
+ {
+ if (adjacent == 1)/*these banks are adjacent*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_PP-DR_T_RDP+2*DR_T_PACKET+DR_T_CAC)/*best case*/
+ {
+ lat = DR_T_WRITE_READ_OBANK-(DR_T_PP-DR_T_RDP+2*DR_T_PACKET+DR_T_CAC);
+ in_between_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_READ_OBANK;
+ worst_case++;
+ }
+ }
+ else/*adjacent == 0: two not adjacent banks need to be precharged*/
+ {
+ if (corrected_overlap > 0 )/*overlapping*/
+ {
+ if(corrected_overlap >= DR_T_WRITE_READ_OBANK)/*best case*/
+ {
+ lat = DR_BEST_T_WRITE_READ_OBANK;
+ best_case++;
+ full_overlapping++;
+ }
+ else/*in between case*/
+ {
+ lat = DR_T_WRITE_READ_OBANK-corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ }
+ else/*worst case*/
+ {
+ lat = DR_T_WRITE_READ_OBANK;
+ worst_case++;
+ }
+ }
+ }
+ }
+ }
+ other_bank_write_access_miss[0]++;
+ obw_after_read_miss++;
+ }
+ }
+ }
+ }
+ /*fprintf(stderr,"%4d %4d ",lat,active_row[current_bank]);debugging*/
+
+ lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/
+
+ /*fprintf(stderr,"%4d ",lat);debugging*/
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ active_row[current_bank]=current_row;
+ lastCmdIsRead = cmdIsRead;
+ last_bank=current_bank;
+ last_row = current_row;
+ last_dev = current_device;
+
+ /*fprintf(stderr,"%4d \n",lat);debugging*/
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ if (memctrlpipe_enable == true)
+ {
+ busy_until[current_bank] =curTick+lat;
+ }
+ else
+ {
+ if (busy_until[current_bank] >= curTick)
+ {
+ busy_until[current_bank] +=lat;
+ lat=busy_until[current_bank] - curTick;
+ }
+ else busy_until[current_bank] = curTick+lat;
+ }
+ }
+ else/*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] +=lat;
+ command_overlapping++;
+ lat+=overlap;
+ }
+
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return lat;
+ }
+
+ /******************************************************************/
+
+ else if ((mem_type== "SDRAM") && (mem_actpolicy == "closed") && (memctrlpipe_enable == true))
+ /* SDRAM closed-page with overlap, 2/00 MG */
+ {
+ if ((memctrladdr_type != "interleaved"))/* i.e. mc_type is linear*/
+ {
+ // current_bank=physic_address/SD_BANK_SIZE;
+ current_bank=physic_address/bank_size;
+ }
+ else/*mc_type interleaved*/
+ /* This memory management unit maps the addresses different
+ * depending on the row_size, every row is mapped to another
+ * bank. So the text segment uses half of every bank. The heap
+ * the next quarter of each bank and the stack the rest.
+ */
+ {
+ num_blocks = physic_address/SD_ROW_SIZE; /* row number */
+ // current_bank=num_blocks%SD_NUM_BANKS;
+ current_bank=num_blocks%num_banks;
+ }
+
+ if (mem_access_details == true)
+ {
+ //fprintf(mem_accessfd," %09u %3d\n",physic_address,current_bank);
+ }
+ else
+ {
+ if (mem_access_output!=NULL)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ }
+ total_access++;
+
+ overlap=(int)(busy_until[current_bank] - curTick);
+
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if ((lastCmdIsRead == cmdIsRead) && (cmdIsRead))/* RAR */
+ {
+ lat = act_lat + cas_lat;
+ }
+ else if ((lastCmdIsRead == cmdIsRead) && (!cmdIsRead)) /* WAW */
+ {
+ lat = act_lat;
+ }
+ else if ((lastCmdIsRead != cmdIsRead) && (cmdIsRead)) /* RAW */
+ {
+ lat = act_lat + cas_lat;
+ }
+ else /* WAR */
+ {
+ lat = act_lat;
+ }
+ }
+ else /* other bank */
+ {
+ if (cpu_ratio < 1.0)
+ {
+ corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
+ }
+ else
+ {
+ corrected_overlap = (int) (overlap/cpu_ratio);
+ }
+
+ if ((lastCmdIsRead == cmdIsRead) && (cmdIsRead))/* RAR */
+ {
+ if (corrected_overlap > act_lat + cas_lat)
+ {
+ lat = 0;
+ best_case++;
+ full_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = act_lat + cas_lat - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = act_lat + cas_lat;
+ worst_case++;
+ }
+ }
+ else if ((lastCmdIsRead == cmdIsRead) && (!cmdIsRead)) /* WAW */
+ {
+ if (corrected_overlap > act_lat + pre_lat + (dpl_lat-1))
+ {
+ lat = - pre_lat - dpl_lat +1;
+ best_case++;
+ full_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = act_lat - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = act_lat;
+ worst_case++;
+ }
+ }
+ else if ((lastCmdIsRead != cmdIsRead) && (cmdIsRead)) /* RAW */
+ {
+ if (corrected_overlap > cas_lat + pre_lat + dpl_lat - 1 )
+ {
+ lat = act_lat - (pre_lat + dpl_lat - 1);
+ best_case++;
+ partial_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = act_lat + cas_lat - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = act_lat + cas_lat;
+ worst_case++;
+ }
+ }
+ else /* WAR */
+ {
+ if (corrected_overlap > act_lat - (dpl_lat-1))
+ {
+ lat = dpl_lat-1;
+ best_case++;
+ partial_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = act_lat - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = act_lat;
+ worst_case++;
+ }
+ }
+ }
+ lastCmdIsRead = cmdIsRead;
+ last_bank=current_bank;
+ last_row = current_row;
+
+ lat += chunks;
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ /*fprintf(stderr,"%4d \n",lat); debugging */
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ busy_until[current_bank] = curTick+lat;
+ }
+ else /*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] +=lat;
+ command_overlapping++;
+ total_arb_latency += overlap;
+ lat+=overlap;
+ }
+ if (!cmdIsRead)
+ {
+ temp = (int)(((dpl_lat-1) + pre_lat)*cpu_ratio);
+ busy_until[current_bank] += (((dpl_lat-1) + pre_lat)*cpu_ratio == temp)?temp:(temp+1);
+ }
+
+
+
+ /*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)curTick, overlap, lat);debug*/
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return lat;
+ }
+
+ /******************************************************************/
+
+ else if ((mem_type == "DRDRAM") && (mem_actpolicy == "closed") && (memctrlpipe_enable == true))
+ /* DRDRAM closed-page with overlap*/
+ {
+
+ if ((memctrladdr_type != "interleaved"))/*i.e. mc_type is linear*/
+ {
+ current_bank=physic_address/DR_BANK_SIZE;
+ current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
+ }
+ else/*mc_type interleaved*/
+ /* This memory management unit maps the addresses different
+ * depending on the row-size, every row is mapped to another
+ * bank. So the text segment uses half of every bank. The heap
+ * the next quarter of each bank and the stack the rest.
+ */
+ {
+ num_blocks = physic_address/DR_ROW_SIZE; /* row number */
+ current_bank=(num_blocks%DR_NUM_BANKS)*2; /*every 'second' bank will be used*/
+ /*banks above DR_NUM_BANKS are the uneven banks*/
+ current_bank = ((current_bank < DR_NUM_BANKS) ? current_bank:(current_bank - DR_NUM_BANKS+1));
+ current_device=current_bank/(DR_NUM_BANKS/DR_NUM_DEVS);
+ }
+
+
+ if (mem_access_details == true)
+ {
+ //fprintf(mem_accessfd," %09u %3d \n",physic_address,current_bank);
+ }
+ else
+ {
+ if (mem_access_output!=NULL)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ }
+ total_access++;
+
+ overlap=(int)(busy_until[current_bank] - curTick);
+
+ if (cpu_ratio < 1.0)
+ {
+ corrected_overlap = overlap*((int)(1/cpu_ratio)); /* floor */
+ }
+ else
+ {
+ corrected_overlap = (int) (overlap/cpu_ratio);
+ }
+
+ if (current_bank == last_bank)/*same bank*/
+ {
+ if ((lastCmdIsRead == cmdIsRead) && (cmdIsRead))/* RAR */
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
+ worst_case++;
+ }
+ else if ((lastCmdIsRead == cmdIsRead) && (!cmdIsRead)) /* WAW */
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
+ worst_case++;
+ }
+ else if ((lastCmdIsRead != cmdIsRead) && (cmdIsRead)) /* RAW */
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
+ worst_case++;
+ }
+ else /* WAR */
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ else /* other bank */
+ {
+ if ((lastCmdIsRead == cmdIsRead) && (cmdIsRead))/* RAR */
+ {
+ if (corrected_overlap > DR_T_RAS + DR_T_RP - 2 * DR_T_PACKET)
+ {
+ lat = - DR_T_RAS + DR_T_RCD + DR_T_PACKET + DR_T_CAC;
+ best_case++;
+ full_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ else if ((lastCmdIsRead == cmdIsRead) && (!cmdIsRead)) /* WAW */
+ {
+ if (corrected_overlap > DR_T_RCD + DR_T_RTR + DR_T_RP)
+ {
+ lat = - DR_T_CWD - 2 * DR_T_PACKET + DR_T_RTR;
+ best_case++;
+ full_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ else if ((lastCmdIsRead != cmdIsRead) && (cmdIsRead)) /* RAW */
+ {
+ if (current_device == last_dev) /* same device */
+ {
+ if (corrected_overlap > DR_T_RCD + DR_T_RP)
+ {
+ lat = DR_T_PACKET + DR_T_CAC - DR_T_RP;
+ best_case++;
+ partial_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ else /* other device */
+ {
+ if (corrected_overlap > DR_T_RCD + DR_T_RP + 2 * DR_T_PACKET)
+ {
+ lat = - DR_T_PACKET + DR_T_CAC - DR_T_RP;
+ best_case++;
+ partial_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ }
+ else /* WAR */
+ {
+ if (corrected_overlap > DR_T_RAS + DR_T_RP - 2 * DR_T_PACKET - (DR_T_CAC - DR_T_CWD))
+ {
+ lat = - DR_T_RAS + DR_T_RCD + DR_T_PACKET + DR_T_CAC;
+ best_case++;
+ full_overlapping++;
+ }
+ else if (corrected_overlap > 0)
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET - corrected_overlap;
+ in_between_case++;
+ partial_overlapping++;
+ }
+ else
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET;
+ worst_case++;
+ }
+ }
+ }
+
+ lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/
+
+ /*fprintf(stderr,"%4d ",lat);debugging*/
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ lastCmdIsRead=cmdIsRead;
+ last_bank=current_bank;
+ last_dev = current_device;
+
+ /*fprintf(stderr,"%4d \n",lat);debugging*/
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ busy_until[current_bank] = curTick+lat;
+ }
+ else/*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] +=lat;
+ command_overlapping++;
+ lat+=overlap;
+ }
+
+ /*fprintf(stderr,"%10.0f %10.0f %4d %4d \n",(double)busy_until, (double)curTick, overlap, lat);*/
+
+ if (cmdIsRead)
+ {
+ if (cpu_ratio < 1.0)
+ {
+ busy_until[current_bank] += abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
+ }
+ else
+ {
+ busy_until[current_bank] += (int) abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)*cpu_ratio); /* CPU clock cycles */
+ }
+ }
+ else /* !cmdIsRead */
+ {
+ if (cpu_ratio < 1.0)
+ {
+ busy_until[current_bank] += abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
+ }
+ else
+ {
+ busy_until[current_bank] += (int) abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)*cpu_ratio); /* CPU clock cycles */
+ }
+ }
+
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return lat;
+ }
+
+ /******************************************************************/
+
+ else if ((mem_type == "SDRAM") && (mem_actpolicy == "closed") && (memctrlpipe_enable == false))
+ /* SDRAM closed-page without overlap, 7/99 MG */
+ {
+ if (mem_access_output != NULL)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ assert(chunks >0);
+
+ if (cmdIsRead)
+ {
+ lat = act_lat + cas_lat;
+ }
+ else /* !cmdIsRead */
+ {
+ lat = act_lat;
+ }
+ total_access++;
+ lat += chunks;
+
+ overlap=(int)(busy_until[current_bank] - curTick);
+ lastCmdIsRead=cmdIsRead;
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ busy_until[current_bank] = curTick+lat;
+ }
+ else/*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] +=lat;
+ command_overlapping++;
+ lat+=overlap;
+ }
+ if (!cmdIsRead)
+ {
+ temp = (int)(((dpl_lat-1) + pre_lat)*cpu_ratio);
+ busy_until[current_bank] += (((dpl_lat-1) + pre_lat)*cpu_ratio == temp)?temp:(temp+1);
+ }
+
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return lat;
+ }
+
+ /******************************************************************/
+
+ else if ((mem_type == "DRDRAM") && (mem_actpolicy == "closed") && (memctrlpipe_enable == false))
+ /* DRDRAM closed-page without overlap */
+ {
+ if (cmdIsRead)
+ {
+ lat = DR_T_RCD + DR_T_CAC + DR_T_PACKET; /* DR_T_RP + */
+ }
+ else /* !cmdIsRead */
+ {
+ lat = DR_T_RCD + DR_T_CWD + DR_T_PACKET; /* DR_T_RP + */
+ }
+ total_access++;
+ overlap=(int)(busy_until[current_bank] - curTick);
+ lat += chunks * DR_T_PACKET; /*every 128 bit need DR_NUM_CYCLES*/
+
+ if (cpu_ratio < 1.0)
+ {
+ lat = (lat+((int)(1/cpu_ratio)-1))/(int)(1/cpu_ratio);
+ }
+ else
+ {
+ temp = (int)(lat*cpu_ratio);
+ lat = (lat*cpu_ratio == temp)?temp:(temp+1); /*round up*/
+ }
+
+ lastCmdIsRead=cmdIsRead;
+
+ if (overlap <= 0) /*memory interface is not busy*/
+ {
+ busy_until[current_bank] = curTick+lat;
+ }
+ else/*the memory request will be satisfied temp cycles after curTick*/
+ {
+ busy_until[current_bank] += lat;
+ command_overlapping++;
+ lat+=overlap;
+ }
+
+ if (cmdIsRead)
+ {
+ if (cpu_ratio < 1.0)
+ {
+ busy_until[current_bank] += abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
+ }
+ else
+ {
+ busy_until[current_bank] += (int) abs(((DR_T_RAS - (DR_T_RCD + DR_T_PACKET + DR_T_CAC)) + 1)*cpu_ratio); /* CPU clock cycles */
+ }
+ }
+ else /* !cmdIsRead */
+ {
+ if (cpu_ratio < 1.0)
+ {
+ busy_until[current_bank] += abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)/((int)(1/cpu_ratio))); /* CPU clock cycles */
+ }
+ else
+ {
+ busy_until[current_bank] += (int) abs((-DR_T_PACKET + DR_T_RTR + DR_T_RP - DR_T_CWD + 1)*cpu_ratio); /* CPU clock cycles */
+ }
+ }
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return lat;
+ }
+
+ /******************************************************************/
+
+ else /*STD*/
+ {
+ if (mem_access_output != NULL)
+ {
+ //fprintf(mem_accessfd,"\n");
+ }
+ assert(chunks >0);
+ // if((_cpu_num < num_cpus) && (_cpu_num >= 0))
+ // cout <<"cpu id = " << _cpu_num << "current_bank = " << current_bank << endl;
+ // bank_access_profile[_cpu_num][current_bank]++;
+ return(/* first chunk latency */act_lat +
+ (/* remainder chunk latency */cas_lat * (chunks - 1)));
+ }
+
+}
+
+/*end added by ar, MG*/
+
+/*begin added by ar, MG*/
+
+/* ================ helper functions ========================= */
+
+/****** DRDRAM specific: shared sense amplifiers ******/
+/* precharges the adjacent banks and returns the number of them (1 or 2)*/
+int /*number of precharged banks*/
+DRAMMemory::prechargeBanksAround(int bank)/*access to bank */
+{
+int temp;
+
+temp=bank%DR_BANK_SAMP;
+
+if (temp == 0) /*bank 0, 16,32 ....*/
+ {
+ if (active_row[bank+1]!=DR_NUM_ROWS)
+ {
+ precharge++;
+ active_row[bank+1]=DR_NUM_ROWS;
+ }
+ }
+else
+ {
+ if (temp==DR_BANK_SAMP-1)/*banks 15,31 ...*/
+ {
+ if (active_row[bank-1]!=DR_NUM_ROWS)
+ {
+ precharge++;
+ active_row[bank-1]=DR_NUM_ROWS;
+ }
+ }
+ else
+ {
+ if (active_row[bank-1]!=DR_NUM_ROWS)
+ {
+ precharge++;
+ active_row[bank-1]=DR_NUM_ROWS;
+ }
+ if (active_row[bank+1]!=DR_NUM_ROWS)
+ {
+ precharge++;
+ active_row[bank+1]=DR_NUM_ROWS;
+ }
+ }
+ }
+return precharge;
+}
+
+
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(DRAMMemory)
+
+ Param<std::string> file;
+ Param<Range<Addr> > range;
+ Param<Tick> latency;
+ /* additional params for dram protocol*/
+ Param<int> cpu_ratio;
+ Param<std::string> mem_type;
+ Param<std::string> mem_actpolicy;
+ Param<std::string> memctrladdr_type;
+ Param<int> bus_width;
+ Param<int> act_lat;
+ Param<int> cas_lat;
+ Param<int> war_lat;
+ Param<int> pre_lat;
+ Param<int> dpl_lat;
+ Param<int> trc_lat;
+ Param<int> num_banks;
+ Param<int> num_cpus;
+
+END_DECLARE_SIM_OBJECT_PARAMS(DRAMMemory)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(DRAMMemory)
+
+ INIT_PARAM_DFLT(file, "memory mapped file", ""),
+ INIT_PARAM(range, "Device Address Range"),
+ INIT_PARAM(latency, "Memory access latency"),
+
+ /* additional params for dram protocol*/
+ INIT_PARAM_DFLT(cpu_ratio,"ratio between CPU speed and memory bus speed",5),
+ INIT_PARAM_DFLT(mem_type,"type of DRAM","SDRAM"),
+ INIT_PARAM_DFLT(mem_actpolicy,"open / closed page policy","open"),
+ INIT_PARAM_DFLT(memctrladdr_type,"interleaved or direct mapping","interleaved"),
+ INIT_PARAM_DFLT(bus_width,"memory access bus width",16),
+ INIT_PARAM_DFLT(act_lat,"RAS to CAS delay",2),
+ INIT_PARAM_DFLT(cas_lat,"CAS delay",1),
+ INIT_PARAM_DFLT(war_lat,"write after read delay",2),
+ INIT_PARAM_DFLT(pre_lat,"precharge delay",2),
+ INIT_PARAM_DFLT(dpl_lat,"data in to precharge delay",2),
+ INIT_PARAM_DFLT(trc_lat,"row cycle delay",6),
+ INIT_PARAM_DFLT(num_banks,"Number of Banks",4),
+ INIT_PARAM_DFLT(num_cpus,"Number of CPUs connected to DRAM",4)
+
+END_INIT_SIM_OBJECT_PARAMS(DRAMMemory)
+
+CREATE_SIM_OBJECT(DRAMMemory)
+{
+ DRAMMemory::Params *p = new DRAMMemory::Params;
+ p->name = getInstanceName();
+ p->addrRange = range;
+ p->latency = latency;
+
+ /* additional params for dram */
+ p->cpu_ratio = cpu_ratio;
+ p->bus_width = bus_width;
+ p->mem_type = mem_type;
+ p->mem_actpolicy = mem_actpolicy;
+ p->memctrladdr_type = memctrladdr_type;
+ p->act_lat = act_lat;
+ p->cas_lat = cas_lat;
+ p->war_lat = war_lat;
+ p->pre_lat = pre_lat;
+ p->dpl_lat = dpl_lat;
+ p->trc_lat = trc_lat;
+ p->num_banks = num_banks;
+ p->num_cpus = num_cpus;
+
+ return new DRAMMemory(p);
+}
+
+REGISTER_SIM_OBJECT("DRAMMemory", DRAMMemory)
+
+#endif // DOXYGEN_SHOULD_SKIP_THIS
+
+
diff --git a/src/mem/dram.hh b/src/mem/dram.hh
new file mode 100644
index 000000000..32d117596
--- /dev/null
+++ b/src/mem/dram.hh
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2003-2004 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ */
+
+/**
+ * @file
+ * Derrive a class from PhysicalMemory that support DRAM like timing access.
+ */
+#ifndef __MEM_DRAM_HH__
+#define __MEM_DRAM_HH__
+
+#include "base/statistics.hh"
+#include "mem/physical.hh"
+
+class DRAMMemory : public PhysicalMemory
+{
+ protected:
+ /* added for dram support */
+ const int cpu_ratio; // ratio between CPU speed and memory bus speed
+ const int bus_width; // memory access bus width (in bytes)
+ /* memory access latency (<first_chunk> <inter_chunk>) */
+ const std::string mem_type;
+ const std::string mem_actpolicy;
+ const std::string memctrladdr_type;
+ const int act_lat;
+ const int cas_lat;
+ const int war_lat;
+ const int pre_lat;
+ const int dpl_lat;
+ const int trc_lat;
+ const int num_banks;
+ const int num_cpus;
+
+ int bank_size;
+ int num_rows;
+ int *active_row;
+ int last_bank;
+ int last_row;
+ Tick *busy_until;
+ int last_dev;
+ bool lastCmdIsRead;
+ int precharge;
+
+ /* memory access statistics */
+ int same_row_read_access;
+ int srr_after_read;
+ int srr_after_write;
+ int same_row_write_access;
+ int srw_after_read;
+ int srw_after_write;
+
+ int same_bank_read_access;
+ int sbr_after_read;
+ int sbr_after_write;
+ int same_bank_write_access;
+ int sbw_after_read;
+ int sbw_after_write;
+
+ int other_bank_read_access_hit;
+ int obr_after_read_hit;
+ int obr_after_write_hit;
+ int other_bank_write_access_hit;
+ int obw_after_read_hit;
+ int obw_after_write_hit;
+ // DR
+ // int other_bank_read_access_miss;
+ int obr_after_read_miss;
+ int obr_after_write_miss;
+ // DR
+ // int other_bank_write_access_miss;
+ int obw_after_read_miss;
+ int obw_after_write_miss;
+
+ int total_access;
+
+ int adjacent_access;
+ int adjacent_read;
+ int adjacent_write;
+ int command_overlapping;
+ int best_case;
+ int in_between_case;
+ int worst_case;
+ int full_overlapping;
+ int partial_overlapping;
+
+ int mem_access_details;
+ int memctrlpipe_enable;
+
+ Tick time_last_access;
+
+
+ Stats::Vector<> accesses;
+ Stats::Vector<> bytesRequested;
+ Stats::Vector<> bytesSent;
+ Stats::Vector<> compressedAccesses;
+
+ Stats::Vector<> cycles_nCKE;
+ Stats::Vector<> cycles_all_precharge_CKE;
+ Stats::Vector<> cycles_all_precharge_nCKE;
+ Stats::Vector<> cycles_bank_active_nCKE;
+ Stats::Vector<> cycles_avg_ACT;
+ Stats::Vector<> cycles_read_out;
+ Stats::Vector<> cycles_write_in;
+ Stats::Vector<> cycles_between_misses;
+ Stats::Vector<> other_bank_read_access_miss;
+ Stats::Vector<> other_bank_write_access_miss;
+ Stats::Scalar<> total_latency;
+ Stats::Scalar<> total_icache_req;
+ Stats::Scalar<> total_arb_latency;
+ Stats::Formula avg_latency;
+ Stats::Formula avg_arb_latency;
+ Stats::Vector2d<> bank_access_profile;
+
+
+ protected:
+ Tick calculateLatency(Packet *pkt);
+ int prechargeBanksAround(int bank);
+
+ public:
+ struct Params : public PhysicalMemory::Params
+ {
+ /* additional params for dram protocol*/
+ int cpu_ratio;
+ int bus_width;
+
+ std::string mem_type; /* DRDRAM, SDRAM */
+ std::string mem_actpolicy; /* closed, open */
+ std::string memctrladdr_type; /* interleaved, anythingelse */
+
+ int act_lat;
+ int cas_lat;
+ int war_lat;
+ int pre_lat;
+ int dpl_lat;
+ int trc_lat;
+ int num_banks;
+ int num_cpus;
+
+ };
+ virtual void regStats();
+ DRAMMemory(Params *p);
+};
+
+#endif// __MEM_DRAM_HH__
+
diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc
new file mode 100644
index 000000000..d4d3fd283
--- /dev/null
+++ b/src/mem/mem_object.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+#include "mem/mem_object.hh"
+#include "sim/param.hh"
+
+MemObject::MemObject(const std::string &name)
+ : SimObject(name)
+{
+}
+
+DEFINE_SIM_OBJECT_CLASS_NAME("MemObject", MemObject)
diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh
new file mode 100644
index 000000000..d12eeffe0
--- /dev/null
+++ b/src/mem/mem_object.hh
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Base Memory Object declaration.
+ */
+
+#ifndef __MEM_MEM_OBJECT_HH__
+#define __MEM_MEM_OBJECT_HH__
+
+#include "sim/sim_object.hh"
+#include "mem/port.hh"
+
+/**
+ * The base MemoryObject class, allows for an accesor function to a
+ * simobj that returns the Port.
+ */
+class MemObject : public SimObject
+{
+ public:
+ MemObject(const std::string &name);
+
+ public:
+ /** Additional function to return the Port of a memory object. */
+ virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
+};
+
+#endif //__MEM_MEM_OBJECT_HH__
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
new file mode 100644
index 000000000..91298df8c
--- /dev/null
+++ b/src/mem/packet.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ * Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Definition of the Packet Class, a packet is a transaction occuring
+ * between a single level of the memory heirarchy (ie L1->L2).
+ */
+#include "base/misc.hh"
+#include "mem/packet.hh"
+
+static const std::string ReadReqString("ReadReq");
+static const std::string WriteReqString("WriteReq");
+static const std::string WriteReqNoAckString("WriteReqNoAck");
+static const std::string ReadRespString("ReadResp");
+static const std::string WriteRespString("WriteResp");
+static const std::string OtherCmdString("<other>");
+
+const std::string &
+Packet::cmdString() const
+{
+ switch (cmd) {
+ case ReadReq: return ReadReqString;
+ case WriteReq: return WriteReqString;
+ case WriteReqNoAck: return WriteReqNoAckString;
+ case ReadResp: return ReadRespString;
+ case WriteResp: return WriteRespString;
+ default: return OtherCmdString;
+ }
+}
+
+const std::string &
+Packet::cmdIdxToString(Packet::Command idx)
+{
+ switch (idx) {
+ case ReadReq: return ReadReqString;
+ case WriteReq: return WriteReqString;
+ case WriteReqNoAck: return WriteReqNoAckString;
+ case ReadResp: return ReadRespString;
+ case WriteResp: return WriteRespString;
+ default: return OtherCmdString;
+ }
+}
+
+/** delete the data pointed to in the data pointer. Ok to call to matter how
+ * data was allocted. */
+void
+Packet::deleteData()
+{
+ assert(staticData || dynamicData);
+ if (staticData)
+ return;
+
+ if (arrayData)
+ delete [] data;
+ else
+ delete data;
+}
+
+/** If there isn't data in the packet, allocate some. */
+void
+Packet::allocate()
+{
+ if (data)
+ return;
+ assert(!staticData);
+ dynamicData = true;
+ arrayData = true;
+ data = new uint8_t[getSize()];
+}
+
+/** Do the packet modify the same addresses. */
+bool
+Packet::intersect(Packet *p)
+{
+ Addr s1 = getAddr();
+ Addr e1 = getAddr() + getSize();
+ Addr s2 = p->getAddr();
+ Addr e2 = p->getAddr() + p->getSize();
+
+ if (s1 >= s2 && s1 < e2)
+ return true;
+ if (e1 >= s2 && e1 < e2)
+ return true;
+ return false;
+}
+
+bool
+fixPacket(Packet *func, Packet *timing)
+{
+ panic("Need to implement!");
+}
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
new file mode 100644
index 000000000..c7d28010c
--- /dev/null
+++ b/src/mem/packet.hh
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Steve Reinhardt
+ * Ali Saidi
+ */
+
+/**
+ * @file
+ * Declaration of the Packet class.
+ */
+
+#ifndef __MEM_PACKET_HH__
+#define __MEM_PACKET_HH__
+
+#include "mem/request.hh"
+#include "sim/host.hh"
+#include "sim/root.hh"
+#include <list>
+#include <cassert>
+
+struct Packet;
+typedef Packet* PacketPtr;
+typedef uint8_t* PacketDataPtr;
+typedef std::list<PacketPtr> PacketList;
+
+//Coherence Flags
+#define NACKED_LINE 1 << 0
+#define SATISFIED 1 << 1
+#define SHARED_LINE 1 << 2
+#define CACHE_LINE_FILL 1 << 3
+#define COMPRESSED 1 << 4
+#define NO_ALLOCATE 1 << 5
+#define SNOOP_COMMIT 1 << 6
+
+//For statistics we need max number of commands, hard code it at
+//20 for now. @todo fix later
+#define NUM_MEM_CMDS 1 << 9
+
+/**
+ * A Packet is used to encapsulate a transfer between two objects in
+ * the memory system (e.g., the L1 and L2 cache). (In contrast, a
+ * single Request travels all the way from the requester to the
+ * ultimate destination and back, possibly being conveyed by several
+ * different Packets along the way.)
+ */
+class Packet
+{
+ public:
+ /** Temporary FLAGS field until cache gets working, this should be in coherence/sender state. */
+ uint64_t flags;
+
+ private:
+ /** A pointer to the data being transfered. It can be differnt
+ * sizes at each level of the heirarchy so it belongs in the
+ * packet, not request. This may or may not be populated when a
+ * responder recieves the packet. If not populated it memory
+ * should be allocated.
+ */
+ PacketDataPtr data;
+
+ /** Is the data pointer set to a value that shouldn't be freed
+ * when the packet is destroyed? */
+ bool staticData;
+ /** The data pointer points to a value that should be freed when
+ * the packet is destroyed. */
+ bool dynamicData;
+ /** the data pointer points to an array (thus delete [] ) needs to
+ * be called on it rather than simply delete.*/
+ bool arrayData;
+
+
+ /** The address of the request. This address could be virtual or
+ * physical, depending on the system configuration. */
+ Addr addr;
+
+ /** The size of the request or transfer. */
+ int size;
+
+ /** Device address (e.g., bus ID) of the source of the
+ * transaction. The source is not responsible for setting this
+ * field; it is set implicitly by the interconnect when the
+ * packet * is first sent. */
+ short src;
+
+ /** Device address (e.g., bus ID) of the destination of the
+ * transaction. The special value Broadcast indicates that the
+ * packet should be routed based on its address. This field is
+ * initialized in the constructor and is thus always valid
+ * (unlike * addr, size, and src). */
+ short dest;
+
+ /** Are the 'addr' and 'size' fields valid? */
+ bool addrSizeValid;
+ /** Is the 'src' field valid? */
+ bool srcValid;
+
+
+ public:
+
+ /** Used to calculate latencies for each packet.*/
+ Tick time;
+
+ /** The special destination address indicating that the packet
+ * should be routed based on its address. */
+ static const short Broadcast = -1;
+
+ /** A pointer to the original request. */
+ RequestPtr req;
+
+ /** A virtual base opaque structure used to hold coherence-related
+ * state. A specific subclass would be derived from this to
+ * carry state specific to a particular coherence protocol. */
+ class CoherenceState {
+ public:
+ virtual ~CoherenceState() {}
+ };
+
+ /** This packet's coherence state. Caches should use
+ * dynamic_cast<> to cast to the state appropriate for the
+ * system's coherence protocol. */
+ CoherenceState *coherence;
+
+ /** A virtual base opaque structure used to hold state associated
+ * with the packet but specific to the sending device (e.g., an
+ * MSHR). A pointer to this state is returned in the packet's
+ * response so that the sender can quickly look up the state
+ * needed to process it. A specific subclass would be derived
+ * from this to carry state specific to a particular sending
+ * device. */
+ class SenderState {
+ public:
+ virtual ~SenderState() {}
+ };
+
+ /** This packet's sender state. Devices should use dynamic_cast<>
+ * to cast to the state appropriate to the sender. */
+ SenderState *senderState;
+
+ private:
+ /** List of command attributes. */
+ enum CommandAttribute
+ {
+ IsRead = 1 << 0,
+ IsWrite = 1 << 1,
+ IsPrefetch = 1 << 2,
+ IsInvalidate = 1 << 3,
+ IsRequest = 1 << 4,
+ IsResponse = 1 << 5,
+ NeedsResponse = 1 << 6,
+ IsSWPrefetch = 1 << 7,
+ IsHWPrefetch = 1 << 8
+ };
+
+ public:
+ /** List of all commands associated with a packet. */
+ enum Command
+ {
+ InvalidCmd = 0,
+ ReadReq = IsRead | IsRequest | NeedsResponse,
+ WriteReq = IsWrite | IsRequest | NeedsResponse,
+ WriteReqNoAck = IsWrite | IsRequest,
+ ReadResp = IsRead | IsResponse | NeedsResponse,
+ WriteResp = IsWrite | IsResponse | NeedsResponse,
+ Writeback = IsWrite | IsRequest,
+ SoftPFReq = IsRead | IsRequest | IsSWPrefetch | NeedsResponse,
+ HardPFReq = IsRead | IsRequest | IsHWPrefetch | NeedsResponse,
+ SoftPFResp = IsRead | IsResponse | IsSWPrefetch | NeedsResponse,
+ HardPFResp = IsRead | IsResponse | IsHWPrefetch | NeedsResponse,
+ InvalidateReq = IsInvalidate | IsRequest,
+ WriteInvalidateReq = IsWrite | IsInvalidate | IsRequest,
+ UpgradeReq = IsInvalidate | IsRequest | NeedsResponse,
+ UpgradeResp = IsInvalidate | IsResponse | NeedsResponse,
+ ReadExReq = IsRead | IsInvalidate | IsRequest | NeedsResponse,
+ ReadExResp = IsRead | IsInvalidate | IsResponse | NeedsResponse
+ };
+
+ /** Return the string name of the cmd field (for debugging and
+ * tracing). */
+ const std::string &cmdString() const;
+
+ /** Reutrn the string to a cmd given by idx. */
+ const std::string &cmdIdxToString(Command idx);
+
+ /** Return the index of this command. */
+ inline int cmdToIndex() const { return (int) cmd; }
+
+ /** The command field of the packet. */
+ Command cmd;
+
+ bool isRead() { return (cmd & IsRead) != 0; }
+ bool isWrite() { return (cmd & IsWrite) != 0; }
+ bool isRequest() { return (cmd & IsRequest) != 0; }
+ bool isResponse() { return (cmd & IsResponse) != 0; }
+ bool needsResponse() { return (cmd & NeedsResponse) != 0; }
+ bool isInvalidate() { return (cmd & IsInvalidate) != 0; }
+
+ bool isCacheFill() { return (flags & CACHE_LINE_FILL) != 0; }
+ bool isNoAllocate() { return (flags & NO_ALLOCATE) != 0; }
+ bool isCompressed() { return (flags & COMPRESSED) != 0; }
+
+ bool nic_pkt() { assert("Unimplemented\n" && 0); return false; }
+
+ /** Possible results of a packet's request. */
+ enum Result
+ {
+ Success,
+ BadAddress,
+ Nacked,
+ Unknown
+ };
+
+ /** The result of this packet's request. */
+ Result result;
+
+ /** Accessor function that returns the source index of the packet. */
+ short getSrc() const { assert(srcValid); return src; }
+ void setSrc(short _src) { src = _src; srcValid = true; }
+
+ /** Accessor function that returns the destination index of
+ the packet. */
+ short getDest() const { return dest; }
+ void setDest(short _dest) { dest = _dest; }
+
+ Addr getAddr() const { assert(addrSizeValid); return addr; }
+ int getSize() const { assert(addrSizeValid); return size; }
+ Addr getOffset(int blkSize) const { return addr & (Addr)(blkSize - 1); }
+
+ void addrOverride(Addr newAddr) { assert(addrSizeValid); addr = newAddr; }
+ void cmdOverride(Command newCmd) { cmd = newCmd; }
+
+ /** Constructor. Note that a Request object must be constructed
+ * first, but the Requests's physical address and size fields
+ * need not be valid. The command and destination addresses
+ * must be supplied. */
+ Packet(Request *_req, Command _cmd, short _dest)
+ : data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ addr(_req->paddr), size(_req->size), dest(_dest),
+ addrSizeValid(_req->validPaddr),
+ srcValid(false),
+ req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
+ result(Unknown)
+ {
+ flags = 0;
+ time = curTick;
+ }
+
+ /** Alternate constructor if you are trying to create a packet with
+ * a request that is for a whole block, not the address from the req.
+ * this allows for overriding the size/addr of the req.*/
+ Packet(Request *_req, Command _cmd, short _dest, int _blkSize)
+ : data(NULL), staticData(false), dynamicData(false), arrayData(false),
+ addr(_req->paddr & ~(_blkSize - 1)), size(_blkSize),
+ dest(_dest),
+ addrSizeValid(_req->validPaddr), srcValid(false),
+ req(_req), coherence(NULL), senderState(NULL), cmd(_cmd),
+ result(Unknown)
+ {
+ flags = 0;
+ time = curTick;
+ }
+
+ /** Destructor. */
+ ~Packet()
+ { deleteData(); }
+
+ /** Reinitialize packet address and size from the associated
+ * Request object, and reset other fields that may have been
+ * modified by a previous transaction. Typically called when a
+ * statically allocated Request/Packet pair is reused for
+ * multiple transactions. */
+ void reinitFromRequest() {
+ assert(req->validPaddr);
+ addr = req->paddr;
+ size = req->size;
+ time = req->time;
+ addrSizeValid = true;
+ result = Unknown;
+ if (dynamicData) {
+ deleteData();
+ dynamicData = false;
+ arrayData = false;
+ }
+ }
+
+ /** Take a request packet and modify it in place to be suitable
+ * for returning as a response to that request. Used for timing
+ * accesses only. For atomic and functional accesses, the
+ * request packet is always implicitly passed back *without*
+ * modifying the command or destination fields, so this function
+ * should not be called. */
+ void makeTimingResponse() {
+ assert(needsResponse());
+ assert(isRequest());
+ int icmd = (int)cmd;
+ icmd &= ~(IsRequest);
+ icmd |= IsResponse;
+ cmd = (Command)icmd;
+ dest = src;
+ srcValid = false;
+ }
+
+ /** Take a request packet that has been returned as NACKED and modify it so
+ * that it can be sent out again. Only packets that need a response can be
+ * NACKED, so verify that that is true. */
+ void reinitNacked() {
+ assert(needsResponse() && result == Nacked);
+ dest = Broadcast;
+ result = Unknown;
+ }
+
+
+ /** Set the data pointer to the following value that should not be freed. */
+ template <typename T>
+ void dataStatic(T *p);
+
+ /** Set the data pointer to a value that should have delete [] called on it.
+ */
+ template <typename T>
+ void dataDynamicArray(T *p);
+
+ /** set the data pointer to a value that should have delete called on it. */
+ template <typename T>
+ void dataDynamic(T *p);
+
+ /** return the value of what is pointed to in the packet. */
+ template <typename T>
+ T get();
+
+ /** get a pointer to the data ptr. */
+ template <typename T>
+ T* getPtr();
+
+ /** set the value in the data pointer to v. */
+ template <typename T>
+ void set(T v);
+
+ /** delete the data pointed to in the data pointer. Ok to call to matter how
+ * data was allocted. */
+ void deleteData();
+
+ /** If there isn't data in the packet, allocate some. */
+ void allocate();
+
+ /** Do the packet modify the same addresses. */
+ bool intersect(Packet *p);
+};
+
+bool fixPacket(Packet *func, Packet *timing);
+#endif //__MEM_PACKET_HH
diff --git a/src/mem/page_table.cc b/src/mem/page_table.cc
new file mode 100644
index 000000000..2b460306f
--- /dev/null
+++ b/src/mem/page_table.cc
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ * Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Definitions of page table.
+ */
+#include <string>
+#include <map>
+#include <fstream>
+
+#include "arch/faults.hh"
+#include "base/bitfield.hh"
+#include "base/intmath.hh"
+#include "base/trace.hh"
+#include "mem/page_table.hh"
+#include "sim/builder.hh"
+#include "sim/sim_object.hh"
+#include "sim/system.hh"
+
+using namespace std;
+using namespace TheISA;
+
+PageTable::PageTable(System *_system, Addr _pageSize)
+ : pageSize(_pageSize), offsetMask(mask(floorLog2(_pageSize))),
+ system(_system)
+{
+ assert(isPowerOf2(pageSize));
+ pTableCache[0].vaddr = 0;
+ pTableCache[1].vaddr = 0;
+ pTableCache[2].vaddr = 0;
+}
+
+PageTable::~PageTable()
+{
+}
+
+Fault
+PageTable::page_check(Addr addr, int64_t size) const
+{
+ if (size < sizeof(uint64_t)) {
+ if (!isPowerOf2(size)) {
+ panic("Invalid request size!\n");
+ return genMachineCheckFault();
+ }
+
+ if ((size - 1) & addr)
+ return genAlignmentFault();
+ }
+ else {
+ if ((addr & (VMPageSize - 1)) + size > VMPageSize) {
+ panic("Invalid request size!\n");
+ return genMachineCheckFault();
+ }
+
+ if ((sizeof(uint64_t) - 1) & addr)
+ return genAlignmentFault();
+ }
+
+ return NoFault;
+}
+
+
+
+
+void
+PageTable::allocate(Addr vaddr, int64_t size)
+{
+ // starting address must be page aligned
+ assert(pageOffset(vaddr) == 0);
+
+ for (; size > 0; size -= pageSize, vaddr += pageSize) {
+ m5::hash_map<Addr,Addr>::iterator iter = pTable.find(vaddr);
+
+ if (iter != pTable.end()) {
+ // already mapped
+ fatal("PageTable::allocate: address 0x%x already mapped", vaddr);
+ }
+
+ pTable[vaddr] = system->new_page();
+ pTableCache[2].paddr = pTableCache[1].paddr;
+ pTableCache[2].vaddr = pTableCache[1].vaddr;
+ pTableCache[1].paddr = pTableCache[0].paddr;
+ pTableCache[1].vaddr = pTableCache[0].vaddr;
+ pTableCache[0].paddr = pTable[vaddr];
+ pTableCache[0].vaddr = vaddr;
+ }
+}
+
+
+
+bool
+PageTable::translate(Addr vaddr, Addr &paddr)
+{
+ Addr page_addr = pageAlign(vaddr);
+ paddr = 0;
+
+ if (pTableCache[0].vaddr == vaddr) {
+ paddr = pTableCache[0].paddr;
+ return true;
+ }
+ if (pTableCache[1].vaddr == vaddr) {
+ paddr = pTableCache[1].paddr;
+ return true;
+ }
+ if (pTableCache[2].vaddr == vaddr) {
+ paddr = pTableCache[2].paddr;
+ return true;
+ }
+
+ m5::hash_map<Addr,Addr>::iterator iter = pTable.find(page_addr);
+
+ if (iter == pTable.end()) {
+ return false;
+ }
+
+ paddr = iter->second + pageOffset(vaddr);
+ return true;
+}
+
+
+Fault
+PageTable::translate(RequestPtr &req)
+{
+ Addr paddr;
+ assert(pageAlign(req->getVaddr() + req->getSize() - 1)
+ == pageAlign(req->getVaddr()));
+ if (!translate(req->getVaddr(), paddr)) {
+ return genPageTableFault(req->getVaddr());
+ }
+ req->setPaddr(paddr);
+ return page_check(req->getPaddr(), req->getSize());
+}
diff --git a/src/mem/page_table.hh b/src/mem/page_table.hh
new file mode 100644
index 000000000..fce063280
--- /dev/null
+++ b/src/mem/page_table.hh
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Declaration of a non-full system Page Table.
+ */
+
+#ifndef __PAGE_TABLE__
+#define __PAGE_TABLE__
+
+#include <string>
+
+#include "sim/faults.hh"
+#include "arch/isa_traits.hh"
+#include "base/hashmap.hh"
+#include "base/trace.hh"
+#include "mem/request.hh"
+#include "mem/packet.hh"
+#include "sim/sim_object.hh"
+
+class System;
+
+/**
+ * Page Table Declaration.
+ */
+class PageTable
+{
+ protected:
+ m5::hash_map<Addr,Addr> pTable;
+
+ struct cacheElement {
+ Addr paddr;
+ Addr vaddr;
+ } ;
+
+ struct cacheElement pTableCache[3];
+
+ const Addr pageSize;
+ const Addr offsetMask;
+
+ System *system;
+
+ public:
+
+ PageTable(System *_system, Addr _pageSize = TheISA::VMPageSize);
+
+ ~PageTable();
+
+ Addr pageAlign(Addr a) { return (a & ~offsetMask); }
+ Addr pageOffset(Addr a) { return (a & offsetMask); }
+
+ Fault page_check(Addr addr, int64_t size) const;
+
+ void allocate(Addr vaddr, int64_t size);
+
+ /**
+ * Translate function
+ * @param vaddr The virtual address.
+ * @return Physical address from translation.
+ */
+ bool translate(Addr vaddr, Addr &paddr);
+
+ /**
+ * Perform a translation on the memory request, fills in paddr
+ * field of mem_req.
+ * @param req The memory request.
+ */
+ Fault translate(RequestPtr &req);
+
+};
+
+#endif
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
new file mode 100644
index 000000000..8fea733ec
--- /dev/null
+++ b/src/mem/physical.cc
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ */
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include <iostream>
+#include <string>
+
+
+#include "base/misc.hh"
+#include "config/full_system.hh"
+#include "mem/packet_impl.hh"
+#include "mem/physical.hh"
+#include "sim/host.hh"
+#include "sim/builder.hh"
+#include "sim/eventq.hh"
+#include "arch/isa_traits.hh"
+
+
+using namespace std;
+using namespace TheISA;
+
+
+PhysicalMemory::PhysicalMemory(Params *p)
+ : MemObject(p->name), pmemAddr(NULL), port(NULL), lat(p->latency), _params(p)
+{
+ if (params()->addrRange.size() % TheISA::PageBytes != 0)
+ panic("Memory Size not divisible by page size\n");
+
+ int map_flags = MAP_ANON | MAP_PRIVATE;
+ pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
+ map_flags, -1, 0);
+
+ if (pmemAddr == (void *)MAP_FAILED) {
+ perror("mmap");
+ fatal("Could not mmap!\n");
+ }
+
+ pagePtr = 0;
+}
+
+void
+PhysicalMemory::init()
+{
+ if (!port)
+ panic("PhysicalMemory not connected to anything!");
+ port->sendStatusChange(Port::RangeChange);
+}
+
+PhysicalMemory::~PhysicalMemory()
+{
+ if (pmemAddr)
+ munmap(pmemAddr, params()->addrRange.size());
+ //Remove memPorts?
+}
+
+Addr
+PhysicalMemory::new_page()
+{
+ Addr return_addr = pagePtr << LogVMPageSize;
+ return_addr += params()->addrRange.start;
+
+ ++pagePtr;
+ return return_addr;
+}
+
+int
+PhysicalMemory::deviceBlockSize()
+{
+ //Can accept anysize request
+ return 0;
+}
+
+Tick
+PhysicalMemory::calculateLatency(Packet *pkt)
+{
+ return lat;
+}
+
+void
+PhysicalMemory::doFunctionalAccess(Packet *pkt)
+{
+ assert(pkt->getAddr() + pkt->getSize() < params()->addrRange.size());
+
+ switch (pkt->cmd) {
+ case Packet::ReadReq:
+ memcpy(pkt->getPtr<uint8_t>(),
+ pmemAddr + pkt->getAddr() - params()->addrRange.start,
+ pkt->getSize());
+ break;
+ case Packet::WriteReq:
+ memcpy(pmemAddr + pkt->getAddr() - params()->addrRange.start,
+ pkt->getPtr<uint8_t>(),
+ pkt->getSize());
+ // temporary hack: will need to add real LL/SC implementation
+ // for cacheless systems later.
+ if (pkt->req->getFlags() & LOCKED) {
+ pkt->req->setScResult(1);
+ }
+ break;
+ default:
+ panic("unimplemented");
+ }
+
+ pkt->result = Packet::Success;
+}
+
+Port *
+PhysicalMemory::getPort(const std::string &if_name, int idx)
+{
+ if (if_name == "port" && idx == -1) {
+ if (port != NULL)
+ panic("PhysicalMemory::getPort: additional port requested to memory!");
+ port = new MemoryPort(name() + "-port", this);
+ return port;
+ } else if (if_name == "functional") {
+ /* special port for functional writes at startup. */
+ return new MemoryPort(name() + "-funcport", this);
+ } else {
+ panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
+ }
+}
+
+void
+PhysicalMemory::recvStatusChange(Port::Status status)
+{
+}
+
+PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
+ PhysicalMemory *_memory)
+ : SimpleTimingPort(_name), memory(_memory)
+{ }
+
+void
+PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
+{
+ memory->recvStatusChange(status);
+}
+
+void
+PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+{
+ memory->getAddressRanges(resp, snoop);
+}
+
+void
+PhysicalMemory::getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+{
+ snoop.clear();
+ resp.clear();
+ resp.push_back(RangeSize(params()->addrRange.start,
+ params()->addrRange.size()));
+}
+
+int
+PhysicalMemory::MemoryPort::deviceBlockSize()
+{
+ return memory->deviceBlockSize();
+}
+
+Tick
+PhysicalMemory::MemoryPort::recvAtomic(Packet *pkt)
+{
+ memory->doFunctionalAccess(pkt);
+ return memory->calculateLatency(pkt);
+}
+
+void
+PhysicalMemory::MemoryPort::recvFunctional(Packet *pkt)
+{
+ // Default implementation of SimpleTimingPort::recvFunctional()
+ // calls recvAtomic() and throws away the latency; we can save a
+ // little here by just not calculating the latency.
+ memory->doFunctionalAccess(pkt);
+}
+
+unsigned int
+PhysicalMemory::drain(Event *de)
+{
+ int count = port->drain(de);
+ if (count)
+ changeState(Draining);
+ else
+ changeState(Drained);
+ return count;
+}
+
+void
+PhysicalMemory::serialize(ostream &os)
+{
+ gzFile compressedMem;
+ string filename = name() + ".physmem";
+
+ SERIALIZE_SCALAR(filename);
+
+ // write memory file
+ string thefile = Checkpoint::dir() + "/" + filename.c_str();
+ int fd = creat(thefile.c_str(), 0664);
+ if (fd < 0) {
+ perror("creat");
+ fatal("Can't open physical memory checkpoint file '%s'\n", filename);
+ }
+
+ compressedMem = gzdopen(fd, "wb");
+ if (compressedMem == NULL)
+ fatal("Insufficient memory to allocate compression state for %s\n",
+ filename);
+
+ if (gzwrite(compressedMem, pmemAddr, params()->addrRange.size()) != params()->addrRange.size()) {
+ fatal("Write failed on physical memory checkpoint file '%s'\n",
+ filename);
+ }
+
+ if (gzclose(compressedMem))
+ fatal("Close failed on physical memory checkpoint file '%s'\n",
+ filename);
+}
+
+void
+PhysicalMemory::unserialize(Checkpoint *cp, const string &section)
+{
+ gzFile compressedMem;
+ long *tempPage;
+ long *pmem_current;
+ uint64_t curSize;
+ uint32_t bytesRead;
+ const int chunkSize = 16384;
+
+
+ string filename;
+
+ UNSERIALIZE_SCALAR(filename);
+
+ filename = cp->cptDir + "/" + filename;
+
+ // mmap memoryfile
+ int fd = open(filename.c_str(), O_RDONLY);
+ if (fd < 0) {
+ perror("open");
+ fatal("Can't open physical memory checkpoint file '%s'", filename);
+ }
+
+ compressedMem = gzdopen(fd, "rb");
+ if (compressedMem == NULL)
+ fatal("Insufficient memory to allocate compression state for %s\n",
+ filename);
+
+ // unmap file that was mmaped in the constructor
+ // This is done here to make sure that gzip and open don't muck with our
+ // nice large space of memory before we reallocate it
+ munmap(pmemAddr, params()->addrRange.size());
+
+ pmemAddr = (uint8_t *)mmap(NULL, params()->addrRange.size(), PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+
+ if (pmemAddr == (void *)MAP_FAILED) {
+ perror("mmap");
+ fatal("Could not mmap physical memory!\n");
+ }
+
+ curSize = 0;
+ tempPage = (long*)malloc(chunkSize);
+ if (tempPage == NULL)
+ fatal("Unable to malloc memory to read file %s\n", filename);
+
+ /* Only copy bytes that are non-zero, so we don't give the VM system hell */
+ while (curSize < params()->addrRange.size()) {
+ bytesRead = gzread(compressedMem, tempPage, chunkSize);
+ if (bytesRead != chunkSize && bytesRead != params()->addrRange.size() - curSize)
+ fatal("Read failed on physical memory checkpoint file '%s'"
+ " got %d bytes, expected %d or %d bytes\n",
+ filename, bytesRead, chunkSize, params()->addrRange.size()-curSize);
+
+ assert(bytesRead % sizeof(long) == 0);
+
+ for (int x = 0; x < bytesRead/sizeof(long); x++)
+ {
+ if (*(tempPage+x) != 0) {
+ pmem_current = (long*)(pmemAddr + curSize + x * sizeof(long));
+ *pmem_current = *(tempPage+x);
+ }
+ }
+ curSize += bytesRead;
+ }
+
+ free(tempPage);
+
+ if (gzclose(compressedMem))
+ fatal("Close failed on physical memory checkpoint file '%s'\n",
+ filename);
+
+}
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+ Param<string> file;
+ Param<Range<Addr> > range;
+ Param<Tick> latency;
+
+END_DECLARE_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+ INIT_PARAM_DFLT(file, "memory mapped file", ""),
+ INIT_PARAM(range, "Device Address Range"),
+ INIT_PARAM(latency, "Memory access latency")
+
+END_INIT_SIM_OBJECT_PARAMS(PhysicalMemory)
+
+CREATE_SIM_OBJECT(PhysicalMemory)
+{
+ PhysicalMemory::Params *p = new PhysicalMemory::Params;
+ p->name = getInstanceName();
+ p->addrRange = range;
+ p->latency = latency;
+ return new PhysicalMemory(p);
+}
+
+REGISTER_SIM_OBJECT("PhysicalMemory", PhysicalMemory)
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
new file mode 100644
index 000000000..02308b2ef
--- /dev/null
+++ b/src/mem/physical.hh
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/* @file
+ */
+
+#ifndef __PHYSICAL_MEMORY_HH__
+#define __PHYSICAL_MEMORY_HH__
+
+#include "base/range.hh"
+#include "mem/mem_object.hh"
+#include "mem/packet.hh"
+#include "mem/tport.hh"
+#include "sim/eventq.hh"
+#include <map>
+#include <string>
+
+//
+// Functional model for a contiguous block of physical memory. (i.e. RAM)
+//
+class PhysicalMemory : public MemObject
+{
+ class MemoryPort : public SimpleTimingPort
+ {
+ PhysicalMemory *memory;
+
+ public:
+
+ MemoryPort(const std::string &_name, PhysicalMemory *_memory);
+
+ protected:
+
+ virtual Tick recvAtomic(Packet *pkt);
+
+ virtual void recvFunctional(Packet *pkt);
+
+ virtual void recvStatusChange(Status status);
+
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop);
+
+ virtual int deviceBlockSize();
+ };
+
+ int numPorts;
+
+
+ private:
+ // prevent copying of a MainMemory object
+ PhysicalMemory(const PhysicalMemory &specmem);
+ const PhysicalMemory &operator=(const PhysicalMemory &specmem);
+
+ protected:
+ uint8_t *pmemAddr;
+ MemoryPort *port;
+ int pagePtr;
+ Tick lat;
+
+ public:
+ Addr new_page();
+ uint64_t size() { return params()->addrRange.size(); }
+
+ struct Params
+ {
+ std::string name;
+ Range<Addr> addrRange;
+ Tick latency;
+ };
+
+ protected:
+ Params *_params;
+
+ public:
+ const Params *params() const { return _params; }
+ PhysicalMemory(Params *p);
+ virtual ~PhysicalMemory();
+
+ public:
+ int deviceBlockSize();
+ void getAddressRanges(AddrRangeList &resp, AddrRangeList &snoop);
+ virtual Port *getPort(const std::string &if_name, int idx = -1);
+ void virtual init();
+ unsigned int drain(Event *de);
+
+ protected:
+ void doFunctionalAccess(Packet *pkt);
+ virtual Tick calculateLatency(Packet *pkt);
+ void recvStatusChange(Port::Status status);
+
+ public:
+ virtual void serialize(std::ostream &os);
+ virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+};
+
+#endif //__PHYSICAL_MEMORY_HH__
diff --git a/src/mem/port.cc b/src/mem/port.cc
new file mode 100644
index 000000000..17924b759
--- /dev/null
+++ b/src/mem/port.cc
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Steve Reinhardt
+ */
+
+/**
+ * @file
+ * Port object definitions.
+ */
+
+#include "base/chunk_generator.hh"
+#include "base/trace.hh"
+#include "mem/packet_impl.hh"
+#include "mem/port.hh"
+
+void
+Port::setPeer(Port *port)
+{
+ DPRINTF(Config, "setting peer to %s\n", port->name());
+ peer = port;
+}
+
+void
+Port::blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd)
+{
+ Request req;
+ Packet pkt(&req, cmd, Packet::Broadcast);
+
+ for (ChunkGenerator gen(addr, size, peerBlockSize());
+ !gen.done(); gen.next()) {
+ req.setPhys(gen.addr(), gen.size(), 0);
+ pkt.reinitFromRequest();
+ pkt.dataStatic(p);
+ sendFunctional(&pkt);
+ p += gen.size();
+ }
+}
+
+void
+Port::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ blobHelper(addr, p, size, Packet::WriteReq);
+}
+
+void
+Port::readBlob(Addr addr, uint8_t *p, int size)
+{
+ blobHelper(addr, p, size, Packet::ReadReq);
+}
+
+void
+Port::memsetBlob(Addr addr, uint8_t val, int size)
+{
+ // quick and dirty...
+ uint8_t *buf = new uint8_t[size];
+
+ memset(buf, val, size);
+ blobHelper(addr, buf, size, Packet::WriteReq);
+
+ delete [] buf;
+}
diff --git a/src/mem/port.hh b/src/mem/port.hh
new file mode 100644
index 000000000..6b4184043
--- /dev/null
+++ b/src/mem/port.hh
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ */
+
+/**
+ * @file
+ * Port Object Declaration. Ports are used to interface memory objects to
+ * each other. They will always come in pairs, and we refer to the other
+ * port object as the peer. These are used to make the design more
+ * modular so that a specific interface between every type of objcet doesn't
+ * have to be created.
+ */
+
+#ifndef __MEM_PORT_HH__
+#define __MEM_PORT_HH__
+
+#include <list>
+#include <inttypes.h>
+
+#include "base/misc.hh"
+#include "base/range.hh"
+#include "mem/packet.hh"
+#include "mem/request.hh"
+
+/** This typedef is used to clean up the parameter list of
+ * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared
+ * outside the Port object since it's also used by some mem objects.
+ * Eventually we should move this typedef to wherever Addr is
+ * defined.
+ */
+
+typedef std::list<Range<Addr> > AddrRangeList;
+typedef std::list<Range<Addr> >::iterator AddrRangeIter;
+
+/**
+ * Ports are used to interface memory objects to
+ * each other. They will always come in pairs, and we refer to the other
+ * port object as the peer. These are used to make the design more
+ * modular so that a specific interface between every type of objcet doesn't
+ * have to be created.
+ *
+ * Recv accesor functions are being called from the peer interface.
+ * Send accessor functions are being called from the device the port is
+ * associated with, and it will call the peer recv. accessor function.
+ */
+class Port
+{
+ private:
+
+ /** Descriptive name (for DPRINTF output) */
+ mutable std::string portName;
+
+ /** A pointer to the peer port. Ports always come in pairs, that way they
+ can use a standardized interface to communicate between different
+ memory objects. */
+ Port *peer;
+
+ public:
+
+ Port()
+ : peer(NULL)
+ { }
+
+ /**
+ * Constructor.
+ *
+ * @param _name Port name for DPRINTF output. Should include name
+ * of memory system object to which the port belongs.
+ */
+ Port(const std::string &_name)
+ : portName(_name), peer(NULL)
+ { }
+
+ /** Return port name (for DPRINTF). */
+ const std::string &name() const { return portName; }
+
+ virtual ~Port() {};
+
+ // mey be better to use subclasses & RTTI?
+ /** Holds the ports status. Currently just that a range recomputation needs
+ * to be done. */
+ enum Status {
+ RangeChange,
+ SnoopSquash
+ };
+
+ void setName(const std::string &name)
+ { portName = name; }
+
+ /** Function to set the pointer for the peer port.
+ @todo should be called by the configuration stuff (python).
+ */
+ void setPeer(Port *port);
+
+ /** Function to set the pointer for the peer port.
+ @todo should be called by the configuration stuff (python).
+ */
+ Port *getPeer() { return peer; }
+
+ protected:
+
+ /** These functions are protected because they should only be
+ * called by a peer port, never directly by any outside object. */
+
+ /** Called to recive a timing call from the peer port. */
+ virtual bool recvTiming(Packet *pkt) = 0;
+
+ /** Called to recive a atomic call from the peer port. */
+ virtual Tick recvAtomic(Packet *pkt) = 0;
+
+ /** Called to recive a functional call from the peer port. */
+ virtual void recvFunctional(Packet *pkt) = 0;
+
+ /** Called to recieve a status change from the peer port. */
+ virtual void recvStatusChange(Status status) = 0;
+
+ /** Called by a peer port if the send was unsuccesful, and had to
+ wait. This shouldn't be valid for response paths (IO Devices).
+ so it is set to panic if it isn't already defined.
+ */
+ virtual void recvRetry() { panic("??"); }
+
+ /** Called by a peer port in order to determine the block size of the
+ device connected to this port. It sometimes doesn't make sense for
+ this function to be called, a DMA interface doesn't really have a
+ block size, so it is defaulted to a panic.
+ */
+ virtual int deviceBlockSize() { panic("??"); }
+
+ /** The peer port is requesting us to reply with a list of the ranges we
+ are responsible for.
+ @param resp is a list of ranges responded to
+ @param snoop is a list of ranges snooped
+ */
+ virtual void getDeviceAddressRanges(AddrRangeList &resp,
+ AddrRangeList &snoop)
+ { panic("??"); }
+
+ public:
+
+ /** Function called by associated memory device (cache, memory, iodevice)
+ in order to send a timing request to the port. Simply calls the peer
+ port receive function.
+ @return This function returns if the send was succesful in it's
+ recieve. If it was a failure, then the port will wait for a recvRetry
+ at which point it can possibly issue a successful sendTiming. This is used in
+ case a cache has a higher priority request come in while waiting for
+ the bus to arbitrate.
+ */
+ bool sendTiming(Packet *pkt) { return peer->recvTiming(pkt); }
+
+ /** Function called by the associated device to send an atomic
+ * access, an access in which the data is moved and the state is
+ * updated in one cycle, without interleaving with other memory
+ * accesses. Returns estimated latency of access.
+ */
+ Tick sendAtomic(Packet *pkt)
+ { return peer->recvAtomic(pkt); }
+
+ /** Function called by the associated device to send a functional access,
+ an access in which the data is instantly updated everywhere in the
+ memory system, without affecting the current state of any block or
+ moving the block.
+ */
+ void sendFunctional(Packet *pkt)
+ { return peer->recvFunctional(pkt); }
+
+ /** Called by the associated device to send a status change to the device
+ connected to the peer interface.
+ */
+ void sendStatusChange(Status status) {peer->recvStatusChange(status); }
+
+ /** When a timing access doesn't return a success, some time later the
+ Retry will be sent.
+ */
+ void sendRetry() { return peer->recvRetry(); }
+
+ /** Called by the associated device if it wishes to find out the blocksize
+ of the device on attached to the peer port.
+ */
+ int peerBlockSize() { return peer->deviceBlockSize(); }
+
+ /** Called by the associated device if it wishes to find out the address
+ ranges connected to the peer ports devices.
+ */
+ void getPeerAddressRanges(AddrRangeList &resp, AddrRangeList &snoop)
+ { peer->getDeviceAddressRanges(resp, snoop); }
+
+ /** This function is a wrapper around sendFunctional()
+ that breaks a larger, arbitrarily aligned access into
+ appropriate chunks. The default implementation can use
+ getBlockSize() to determine the block size and go from there.
+ */
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+
+ /** This function is a wrapper around sendFunctional()
+ that breaks a larger, arbitrarily aligned access into
+ appropriate chunks. The default implementation can use
+ getBlockSize() to determine the block size and go from there.
+ */
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+
+ /** Fill size bytes starting at addr with byte value val. This
+ should not need to be virtual, since it can be implemented in
+ terms of writeBlob(). However, it shouldn't be
+ performance-critical either, so it could be if we wanted to.
+ */
+ virtual void memsetBlob(Addr addr, uint8_t val, int size);
+
+ private:
+
+ /** Internal helper function for read/writeBlob().
+ */
+ void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd);
+};
+
+/** A simple functional port that is only meant for one way communication to
+ * physical memory. It is only meant to be used to load data into memory before
+ * the simulation begins.
+ */
+
+class FunctionalPort : public Port
+{
+ public:
+ FunctionalPort(const std::string &_name)
+ : Port(_name)
+ {}
+
+ protected:
+ virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); }
+ virtual void recvStatusChange(Status status) {}
+
+ public:
+ /** a write function that also does an endian conversion. */
+ template <typename T>
+ inline void writeHtoG(Addr addr, T d);
+
+ /** a read function that also does an endian conversion. */
+ template <typename T>
+ inline T readGtoH(Addr addr);
+
+ template <typename T>
+ inline void write(Addr addr, T d)
+ {
+ writeBlob(addr, (uint8_t*)&d, sizeof(T));
+ }
+
+ template <typename T>
+ inline T read(Addr addr)
+ {
+ T d;
+ readBlob(addr, (uint8_t*)&d, sizeof(T));
+ return d;
+ }
+};
+
+#endif //__MEM_PORT_HH__
diff --git a/src/mem/port_impl.hh b/src/mem/port_impl.hh
new file mode 100644
index 000000000..b7980bdd2
--- /dev/null
+++ b/src/mem/port_impl.hh
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+
+template <typename T>
+void
+FunctionalPort::writeHtoG(Addr addr, T d)
+{
+ d = htog(d);
+ writeBlob(addr, (uint8_t*)&d, sizeof(T));
+}
+
+
+template <typename T>
+T
+FunctionalPort::readGtoH(Addr addr)
+{
+ T d;
+ readBlob(addr, (uint8_t*)&d, sizeof(T));
+ return gtoh(d);
+}
+
diff --git a/src/mem/request.hh b/src/mem/request.hh
new file mode 100644
index 000000000..6acd7526c
--- /dev/null
+++ b/src/mem/request.hh
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Steve Reinhardt
+ * Ali Saidi
+ */
+
+/**
+ * @file
+ * Declaration of a request, the overall memory request consisting of
+ the parts of the request that are persistent throughout the transaction.
+ */
+
+#ifndef __MEM_REQUEST_HH__
+#define __MEM_REQUEST_HH__
+
+#include "sim/host.hh"
+#include "sim/root.hh"
+
+#include <cassert>
+
+class Request;
+
+typedef Request* RequestPtr;
+
+
+/** The request is a Load locked/store conditional. */
+const unsigned LOCKED = 0x001;
+/** The virtual address is also the physical address. */
+const unsigned PHYSICAL = 0x002;
+/** The request is an ALPHA VPTE pal access (hw_ld). */
+const unsigned VPTE = 0x004;
+/** Use the alternate mode bits in ALPHA. */
+const unsigned ALTMODE = 0x008;
+/** The request is to an uncacheable address. */
+const unsigned UNCACHEABLE = 0x010;
+/** The request should not cause a page fault. */
+const unsigned NO_FAULT = 0x020;
+/** The request should be prefetched into the exclusive state. */
+const unsigned PF_EXCLUSIVE = 0x100;
+/** The request should be marked as LRU. */
+const unsigned EVICT_NEXT = 0x200;
+/** The request should ignore unaligned access faults */
+const unsigned NO_ALIGN_FAULT = 0x400;
+/** The request was an instruction read. */
+const unsigned INST_READ = 0x800;
+
+class Request
+{
+ private:
+ /**
+ * The physical address of the request. Valid only if validPaddr
+ * is set. */
+ Addr paddr;
+
+ /**
+ * The size of the request. This field must be set when vaddr or
+ * paddr is written via setVirt() or setPhys(), so it is always
+ * valid as long as one of the address fields is valid. */
+ int size;
+
+ /** Flag structure for the request. */
+ uint32_t flags;
+
+ /**
+ * The time this request was started. Used to calculate
+ * latencies. This field is set to curTick any time paddr or vaddr
+ * is written. */
+ Tick time;
+
+ /** The address space ID. */
+ int asid;
+ /** The virtual address of the request. */
+ Addr vaddr;
+
+ /** The return value of store conditional. */
+ uint64_t scResult;
+
+ /** The cpu number (for statistics, typically). */
+ int cpuNum;
+ /** The requesting thread id (for statistics, typically). */
+ int threadNum;
+
+ /** program counter of initiating access; for tracing/debugging */
+ Addr pc;
+
+ /** Whether or not paddr is valid (has been written yet). */
+ bool validPaddr;
+ /** Whether or not the asid & vaddr are valid. */
+ bool validAsidVaddr;
+ /** Whether or not the sc result is valid. */
+ bool validScResult;
+ /** Whether or not the cpu number & thread ID are valid. */
+ bool validCpuAndThreadNums;
+ /** Whether or not the pc is valid. */
+ bool validPC;
+
+ public:
+ /** Minimal constructor. No fields are initialized. */
+ Request()
+ : validPaddr(false), validAsidVaddr(false),
+ validScResult(false), validCpuAndThreadNums(false), validPC(false)
+ {}
+
+ /**
+ * Constructor for physical (e.g. device) requests. Initializes
+ * just physical address, size, flags, and timestamp (to curTick).
+ * These fields are adequate to perform a request. */
+ Request(Addr _paddr, int _size, int _flags)
+ : validCpuAndThreadNums(false)
+ { setPhys(_paddr, _size, _flags); }
+
+ Request(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc,
+ int _cpuNum, int _threadNum)
+ {
+ setThreadContext(_cpuNum, _threadNum);
+ setVirt(_asid, _vaddr, _size, _flags, _pc);
+ }
+
+ /**
+ * Set up CPU and thread numbers. */
+ void setThreadContext(int _cpuNum, int _threadNum)
+ {
+ cpuNum = _cpuNum;
+ threadNum = _threadNum;
+ validCpuAndThreadNums = true;
+ }
+
+ /**
+ * Set up a physical (e.g. device) request in a previously
+ * allocated Request object. */
+ void setPhys(Addr _paddr, int _size, int _flags)
+ {
+ paddr = _paddr;
+ size = _size;
+ flags = _flags;
+ time = curTick;
+ validPaddr = true;
+ validAsidVaddr = false;
+ validPC = false;
+ validScResult = false;
+ }
+
+ /**
+ * Set up a virtual (e.g., CPU) request in a previously
+ * allocated Request object. */
+ void setVirt(int _asid, Addr _vaddr, int _size, int _flags, Addr _pc)
+ {
+ asid = _asid;
+ vaddr = _vaddr;
+ size = _size;
+ flags = _flags;
+ pc = _pc;
+ time = curTick;
+ validPaddr = false;
+ validAsidVaddr = true;
+ validPC = true;
+ validScResult = false;
+ }
+
+ /** Set just the physical address. This should only be used to
+ * record the result of a translation, and thus the vaddr must be
+ * valid before this method is called. Otherwise, use setPhys()
+ * to guarantee that the size and flags are also set.
+ */
+ void setPaddr(Addr _paddr)
+ {
+ assert(validAsidVaddr);
+ paddr = _paddr;
+ validPaddr = true;
+ }
+
+ /** Accessor for paddr. */
+ Addr getPaddr() { assert(validPaddr); return paddr; }
+
+ /** Accessor for size. */
+ int getSize() { assert(validPaddr || validAsidVaddr); return size; }
+ /** Accessor for time. */
+ Tick getTime() { assert(validPaddr || validAsidVaddr); return time; }
+
+ /** Accessor for flags. */
+ uint32_t getFlags() { assert(validPaddr || validAsidVaddr); return flags; }
+ /** Accessor for paddr. */
+ void setFlags(uint32_t _flags)
+ { assert(validPaddr || validAsidVaddr); flags = _flags; }
+
+ /** Accessor function for vaddr.*/
+ Addr getVaddr() { assert(validAsidVaddr); return vaddr; }
+
+ /** Accessor function for asid.*/
+ int getAsid() { assert(validAsidVaddr); return asid; }
+
+ /** Accessor function to check if sc result is valid. */
+ bool scResultValid() { return validScResult; }
+ /** Accessor function for store conditional return value.*/
+ uint64_t getScResult() { assert(validScResult); return scResult; }
+ /** Accessor function for store conditional return value.*/
+ void setScResult(uint64_t _scResult)
+ { scResult = _scResult; validScResult = true; }
+
+ /** Accessor function for cpu number.*/
+ int getCpuNum() { assert(validCpuAndThreadNums); return cpuNum; }
+ /** Accessor function for thread number.*/
+ int getThreadNum() { assert(validCpuAndThreadNums); return threadNum; }
+
+ /** Accessor function for pc.*/
+ Addr getPC() { assert(validPC); return pc; }
+
+ /** Accessor Function to Check Cacheability. */
+ bool isUncacheable() { return getFlags() & UNCACHEABLE; }
+
+ bool isInstRead() { return getFlags() & INST_READ; }
+
+ friend class Packet;
+};
+
+#endif // __MEM_REQUEST_HH__
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
new file mode 100644
index 000000000..55c301c87
--- /dev/null
+++ b/src/mem/tport.cc
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#include "mem/tport.hh"
+
+void
+SimpleTimingPort::recvFunctional(Packet *pkt)
+{
+ // just do an atomic access and throw away the returned latency
+ recvAtomic(pkt);
+}
+
+bool
+SimpleTimingPort::recvTiming(Packet *pkt)
+{
+ // If the device is only a slave, it should only be sending
+ // responses, which should never get nacked. There used to be
+ // code to hanldle nacks here, but I'm pretty sure it didn't work
+ // correctly with the drain code, so that would need to be fixed
+ // if we ever added it back.
+ assert(pkt->result != Packet::Nacked);
+ Tick latency = recvAtomic(pkt);
+ // turn packet around to go back to requester
+ pkt->makeTimingResponse();
+ sendTimingLater(pkt, latency);
+ return true;
+}
+
+void
+SimpleTimingPort::recvRetry()
+{
+ bool result = true;
+ while (result && transmitList.size()) {
+ result = sendTiming(transmitList.front());
+ if (result)
+ transmitList.pop_front();
+ }
+ if (transmitList.size() == 0 && drainEvent) {
+ drainEvent->process();
+ drainEvent = NULL;
+ }
+}
+
+void
+SimpleTimingPort::SendEvent::process()
+{
+ port->outTiming--;
+ assert(port->outTiming >= 0);
+ if (port->sendTiming(packet)) {
+ // send successfule
+ if (port->transmitList.size() == 0 && port->drainEvent) {
+ port->drainEvent->process();
+ port->drainEvent = NULL;
+ }
+ } else {
+ // send unsuccessful (due to flow control). Will get retry
+ // callback later; save for then.
+ port->transmitList.push_back(packet);
+ }
+}
+
+
+unsigned int
+SimpleTimingPort::drain(Event *de)
+{
+ if (outTiming == 0 && transmitList.size() == 0)
+ return 0;
+ drainEvent = de;
+ return 1;
+}
diff --git a/src/mem/tport.hh b/src/mem/tport.hh
new file mode 100644
index 000000000..df6d48196
--- /dev/null
+++ b/src/mem/tport.hh
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+#ifndef __MEM_TPORT_HH__
+#define __MEM_TPORT_HH__
+
+/**
+ * @file
+ *
+ * Declaration of SimpleTimingPort.
+ */
+
+#include "mem/port.hh"
+#include "sim/eventq.hh"
+#include <list>
+#include <string>
+
+/**
+ * A simple port for interfacing objects that basically have only
+ * functional memory behavior (e.g. I/O devices) to the memory system.
+ * Both timing and functional accesses are implemented in terms of
+ * atomic accesses. A derived port class thus only needs to provide
+ * recvAtomic() to support all memory access modes.
+ *
+ * The tricky part is handling recvTiming(), where the response must
+ * be scheduled separately via a later call to sendTiming(). This
+ * feature is handled by scheduling an internal event that calls
+ * sendTiming() after a delay, and optionally rescheduling the
+ * response if it is nacked.
+ */
+class SimpleTimingPort : public Port
+{
+ protected:
+ /** A list of outgoing timing response packets that haven't been
+ * serviced yet. */
+ std::list<Packet*> transmitList;
+
+ /**
+ * This class is used to implemented sendTiming() with a delay. When
+ * a delay is requested a new event is created. When the event time
+ * expires it attempts to send the packet. If it cannot, the packet
+ * is pushed onto the transmit list to be sent when recvRetry() is
+ * called. */
+ class SendEvent : public Event
+ {
+ SimpleTimingPort *port;
+ Packet *packet;
+
+ public:
+ SendEvent(SimpleTimingPort *p, Packet *pkt, Tick t)
+ : Event(&mainEventQueue), port(p), packet(pkt)
+ { setFlags(AutoDelete); schedule(curTick + t); }
+
+ virtual void process();
+
+ virtual const char *description()
+ { return "Future scheduled sendTiming event"; }
+ };
+
+
+ /** Number of timing requests that are emulating the device timing before
+ * attempting to end up on the bus.
+ */
+ int outTiming;
+
+ /** If we need to drain, keep the drain event around until we're done
+ * here.*/
+ Event *drainEvent;
+
+ /** Schedule a sendTiming() event to be called in the future. */
+ void sendTimingLater(Packet *pkt, Tick time)
+ { outTiming++; new SendEvent(this, pkt, time); }
+
+ /** This function is notification that the device should attempt to send a
+ * packet again. */
+ virtual void recvRetry();
+
+ /** Implemented using recvAtomic(). */
+ void recvFunctional(Packet *pkt);
+
+ /** Implemented using recvAtomic(). */
+ bool recvTiming(Packet *pkt);
+
+ /**
+ * Simple ports generally don't care about any status
+ * changes... can always override this in cases where that's not
+ * true. */
+ virtual void recvStatusChange(Status status) { }
+
+
+ public:
+
+ SimpleTimingPort(std::string pname)
+ : Port(pname), outTiming(0), drainEvent(NULL)
+ {}
+
+ /** Hook for draining timing accesses from the system. The
+ * associated SimObject's drain() functions should be implemented
+ * something like this when this class is used:
+ \code
+ PioDevice::drain(Event *de)
+ {
+ unsigned int count;
+ count = SimpleTimingPort->drain(de);
+ if (count)
+ changeState(Draining);
+ else
+ changeState(Drained);
+ return count;
+ }
+ \endcode
+ */
+ unsigned int drain(Event *de);
+};
+
+#endif // __MEM_TPORT_HH__
diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc
new file mode 100644
index 000000000..d2c854086
--- /dev/null
+++ b/src/mem/translating_port.cc
@@ -0,0 +1,190 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Steve Reinhardt
+ */
+
+#include <string>
+#include "base/chunk_generator.hh"
+#include "mem/port.hh"
+#include "mem/translating_port.hh"
+#include "mem/page_table.hh"
+
+using namespace TheISA;
+
+TranslatingPort::TranslatingPort(const std::string &_name,
+ PageTable *p_table, bool alloc)
+ : FunctionalPort(_name), pTable(p_table), allocating(alloc)
+{ }
+
+TranslatingPort::~TranslatingPort()
+{ }
+
+bool
+TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ int prevSize = 0;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(),paddr))
+ return false;
+
+ Port::readBlob(paddr, p + prevSize, gen.size());
+ prevSize += gen.size();
+ }
+
+ return true;
+}
+
+void
+TranslatingPort::readBlob(Addr addr, uint8_t *p, int size)
+{
+ if (!tryReadBlob(addr, p, size))
+ fatal("readBlob(0x%x, ...) failed", addr);
+}
+
+
+bool
+TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size)
+{
+
+ Addr paddr;
+ int prevSize = 0;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(), paddr)) {
+ if (allocating) {
+ pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ pTable->translate(gen.addr(), paddr);
+ } else {
+ return false;
+ }
+ }
+
+ Port::writeBlob(paddr, p + prevSize, gen.size());
+ prevSize += gen.size();
+ }
+
+ return true;
+}
+
+
+void
+TranslatingPort::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ if (!tryWriteBlob(addr, p, size))
+ fatal("writeBlob(0x%x, ...) failed", addr);
+}
+
+bool
+TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size)
+{
+ Addr paddr;
+
+ for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
+
+ if (!pTable->translate(gen.addr(), paddr)) {
+ if (allocating) {
+ pTable->allocate(roundDown(gen.addr(), VMPageSize),
+ VMPageSize);
+ pTable->translate(gen.addr(), paddr);
+ } else {
+ return false;
+ }
+ }
+
+ Port::memsetBlob(paddr, val, gen.size());
+ }
+
+ return true;
+}
+
+void
+TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size)
+{
+ if (!tryMemsetBlob(addr, val, size))
+ fatal("memsetBlob(0x%x, ...) failed", addr);
+}
+
+
+bool
+TranslatingPort::tryWriteString(Addr addr, const char *str)
+{
+ Addr paddr,vaddr;
+ uint8_t c;
+
+ vaddr = addr;
+
+ do {
+ c = *str++;
+ if (!pTable->translate(vaddr++,paddr))
+ return false;
+
+ Port::writeBlob(paddr, &c, 1);
+ } while (c);
+
+ return true;
+}
+
+void
+TranslatingPort::writeString(Addr addr, const char *str)
+{
+ if (!tryWriteString(addr, str))
+ fatal("writeString(0x%x, ...) failed", addr);
+}
+
+bool
+TranslatingPort::tryReadString(std::string &str, Addr addr)
+{
+ Addr paddr,vaddr;
+ uint8_t c;
+
+ vaddr = addr;
+
+ do {
+ if (!pTable->translate(vaddr++,paddr))
+ return false;
+
+ Port::readBlob(paddr, &c, 1);
+ str += c;
+ } while (c);
+
+ return true;
+}
+
+void
+TranslatingPort::readString(std::string &str, Addr addr)
+{
+ if (!tryReadString(str, addr))
+ fatal("readString(0x%x, ...) failed", addr);
+}
+
diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh
new file mode 100644
index 000000000..7354278ba
--- /dev/null
+++ b/src/mem/translating_port.hh
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2001-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ron Dreslinski
+ * Ali Saidi
+ */
+
+#ifndef __MEM_TRANSLATING_PROT_HH__
+#define __MEM_TRANSLATING_PROT_HH__
+
+#include "mem/port.hh"
+
+class PageTable;
+
+class TranslatingPort : public FunctionalPort
+{
+ private:
+ PageTable *pTable;
+ bool allocating;
+
+ public:
+ TranslatingPort(const std::string &_name,
+ PageTable *p_table, bool alloc = false);
+ virtual ~TranslatingPort();
+
+ bool tryReadBlob(Addr addr, uint8_t *p, int size);
+ bool tryWriteBlob(Addr addr, uint8_t *p, int size);
+ bool tryMemsetBlob(Addr addr, uint8_t val, int size);
+ bool tryWriteString(Addr addr, const char *str);
+ bool tryReadString(std::string &str, Addr addr);
+
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+ virtual void memsetBlob(Addr addr, uint8_t val, int size);
+
+ void writeString(Addr addr, const char *str);
+ void readString(std::string &str, Addr addr);
+};
+
+#endif
diff --git a/src/mem/vport.cc b/src/mem/vport.cc
new file mode 100644
index 000000000..8030c5a15
--- /dev/null
+++ b/src/mem/vport.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/**
+ * @file
+ * Port object definitions.
+ */
+
+#include "base/chunk_generator.hh"
+#include "mem/vport.hh"
+
+void
+VirtualPort::readBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ if (tc)
+ paddr = TheISA::vtophys(tc,gen.addr());
+ else
+ paddr = TheISA::vtophys(gen.addr());
+
+ FunctionalPort::readBlob(paddr, p, gen.size());
+ p += gen.size();
+ }
+}
+
+void
+VirtualPort::writeBlob(Addr addr, uint8_t *p, int size)
+{
+ Addr paddr;
+ for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ if (tc)
+ paddr = TheISA::vtophys(tc,gen.addr());
+ else
+ paddr = TheISA::vtophys(gen.addr());
+
+ FunctionalPort::writeBlob(paddr, p, gen.size());
+ p += gen.size();
+ }
+}
+
diff --git a/src/mem/vport.hh b/src/mem/vport.hh
new file mode 100644
index 000000000..c83836258
--- /dev/null
+++ b/src/mem/vport.hh
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/**
+ * @file
+ * Virtual Port Object Declaration. These ports incorporate some translation
+ * into their access methods. Thus you can use one to read and write data
+ * to/from virtual addresses.
+ */
+
+#ifndef __MEM_VPORT_HH__
+#define __MEM_VPORT_HH__
+
+#include "mem/port_impl.hh"
+#include "config/full_system.hh"
+#include "arch/vtophys.hh"
+
+
+/** A class that translates a virtual address to a physical address and then
+ * calls the above read/write functions. If a thread context is provided the
+ * address can alway be translated, If not it can only be translated if it is a
+ * simple address masking operation (such as alpha super page accesses).
+ */
+
+class VirtualPort : public FunctionalPort
+{
+ private:
+ ThreadContext *tc;
+
+ public:
+ VirtualPort(const std::string &_name, ThreadContext *_tc = NULL)
+ : FunctionalPort(_name), tc(_tc)
+ {}
+
+ /** Return true if we have an thread context. This is used to
+ * prevent someone from accidently deleting the cpus statically
+ * allocated vport.
+ * @return true if a thread context isn't valid
+ */
+ bool nullThreadContext() { return tc != NULL; }
+
+ /** Version of readblob that translates virt->phys and deals
+ * with page boundries. */
+ virtual void readBlob(Addr addr, uint8_t *p, int size);
+
+ /** Version of writeBlob that translates virt->phys and deals
+ * with page boundries. */
+ virtual void writeBlob(Addr addr, uint8_t *p, int size);
+};
+
+#endif //__MEM_VPORT_HH__
+