summaryrefslogtreecommitdiff
path: root/src/mem
diff options
context:
space:
mode:
authorGabe Black <gblack@eecs.umich.edu>2012-01-28 07:24:01 -0800
committerGabe Black <gblack@eecs.umich.edu>2012-01-28 07:24:01 -0800
commitc3d41a2def15cdaf2ac3984315f452dacc6a0884 (patch)
tree5324ebec3add54b934a841eee901983ac3463a7f /src/mem
parentda2a4acc26ba264c3c4a12495776fd6a1c4fb133 (diff)
parent4acca8a0536d4445ed25b67edf571ae460446ab9 (diff)
downloadgem5-c3d41a2def15cdaf2ac3984315f452dacc6a0884.tar.xz
Merge with the main repo.
--HG-- rename : src/mem/vport.hh => src/mem/fs_translating_port_proxy.hh rename : src/mem/translating_port.cc => src/mem/se_translating_port_proxy.cc rename : src/mem/translating_port.hh => src/mem/se_translating_port_proxy.hh
Diffstat (limited to 'src/mem')
-rw-r--r--src/mem/Bridge.py16
-rw-r--r--src/mem/SConscript4
-rw-r--r--src/mem/bridge.cc399
-rw-r--r--src/mem/bridge.hh332
-rw-r--r--src/mem/bus.cc194
-rw-r--r--src/mem/bus.hh126
-rw-r--r--src/mem/cache/base.cc10
-rw-r--r--src/mem/cache/base.hh2
-rw-r--r--src/mem/cache/cache.hh24
-rw-r--r--src/mem/cache/cache_impl.hh61
-rw-r--r--src/mem/fs_translating_port_proxy.cc (renamed from src/mem/vport.cc)91
-rw-r--r--src/mem/fs_translating_port_proxy.hh (renamed from src/mem/vport.hh)72
-rw-r--r--src/mem/mem_object.cc6
-rw-r--r--src/mem/mem_object.hh4
-rw-r--r--src/mem/packet.cc3
-rw-r--r--src/mem/packet.hh1
-rw-r--r--src/mem/physical.cc105
-rw-r--r--src/mem/physical.hh37
-rw-r--r--src/mem/port.cc64
-rw-r--r--src/mem/port.hh129
-rw-r--r--src/mem/port_proxy.hh174
-rw-r--r--src/mem/protocol/MESI_CMP_directory-L1cache.sm27
-rw-r--r--src/mem/protocol/MI_example-cache.sm16
-rw-r--r--src/mem/protocol/MOESI_CMP_directory-L1cache.sm24
-rw-r--r--src/mem/protocol/MOESI_CMP_token-L1cache.sm35
-rw-r--r--src/mem/protocol/MOESI_hammer-cache.sm26
-rw-r--r--src/mem/protocol/MOESI_hammer-dir.sm2
-rw-r--r--src/mem/protocol/RubySlicc_Types.sm1
-rw-r--r--src/mem/ruby/system/RubyPort.cc32
-rw-r--r--src/mem/ruby/system/RubyPort.hh4
-rw-r--r--src/mem/ruby/system/RubyPortProxy.cc (renamed from src/mem/port_impl.hh)53
-rw-r--r--src/mem/ruby/system/RubyPortProxy.hh114
-rw-r--r--src/mem/ruby/system/SConscript1
-rw-r--r--src/mem/ruby/system/Sequencer.cc6
-rw-r--r--src/mem/ruby/system/Sequencer.hh2
-rw-r--r--src/mem/ruby/system/Sequencer.py3
-rw-r--r--src/mem/se_translating_port_proxy.cc (renamed from src/mem/translating_port.cc)56
-rw-r--r--src/mem/se_translating_port_proxy.hh (renamed from src/mem/translating_port.hh)47
-rw-r--r--src/mem/tport.cc19
-rw-r--r--src/mem/tport.hh34
40 files changed, 1545 insertions, 811 deletions
diff --git a/src/mem/Bridge.py b/src/mem/Bridge.py
index b48e1684d..38b344613 100644
--- a/src/mem/Bridge.py
+++ b/src/mem/Bridge.py
@@ -31,16 +31,12 @@ from MemObject import MemObject
class Bridge(MemObject):
type = 'Bridge'
- side_a = Port('Side A port')
- side_b = Port('Side B port')
- req_size_a = Param.Int(16, "The number of requests to buffer")
- req_size_b = Param.Int(16, "The number of requests to buffer")
- resp_size_a = Param.Int(16, "The number of requests to buffer")
- resp_size_b = Param.Int(16, "The number of requests to buffer")
+ slave = Port('Slave port')
+ master = Port('Master port')
+ req_size = Param.Int(16, "The number of requests to buffer")
+ resp_size = Param.Int(16, "The number of requests to buffer")
delay = Param.Latency('0ns', "The latency of this bridge")
nack_delay = Param.Latency('0ns', "The latency of this bridge")
write_ack = Param.Bool(False, "Should this bridge ack writes")
- filter_ranges_a = VectorParam.AddrRange([],
- "What addresses shouldn't be passed through the side of the bridge")
- filter_ranges_b = VectorParam.AddrRange([],
- "What addresses shouldn't be passed through the side of the bridge")
+ ranges = VectorParam.AddrRange([AllMemory],
+ "Address ranges to pass through the bridge")
diff --git a/src/mem/SConscript b/src/mem/SConscript
index 8418a4f51..09cc93c77 100644
--- a/src/mem/SConscript
+++ b/src/mem/SConscript
@@ -41,14 +41,14 @@ Source('mport.cc')
Source('packet.cc')
Source('port.cc')
Source('tport.cc')
-Source('vport.cc')
+Source('fs_translating_port_proxy.cc')
+Source('se_translating_port_proxy.cc')
if env['TARGET_ISA'] != 'no':
SimObject('PhysicalMemory.py')
Source('dram.cc')
Source('page_table.cc')
Source('physical.cc')
- Source('translating_port.cc')
DebugFlag('Bus')
DebugFlag('BusAddrRanges')
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc
index 9e5e64069..b48662118 100644
--- a/src/mem/bridge.cc
+++ b/src/mem/bridge.cc
@@ -1,5 +1,16 @@
-
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -28,58 +39,67 @@
*
* Authors: Ali Saidi
* Steve Reinhardt
+ * Andreas Hansson
*/
/**
* @file
- * Definition of a simple bus bridge without buffering.
+ * Implementation of a memory-mapped bus bridge that connects a master
+ * and a slave through a request and response queue.
*/
-#include <algorithm>
-
-#include "base/range_ops.hh"
#include "base/trace.hh"
#include "debug/BusBridge.hh"
#include "mem/bridge.hh"
#include "params/Bridge.hh"
-Bridge::BridgePort::BridgePort(const std::string &_name,
- Bridge *_bridge, BridgePort *_otherPort,
- int _delay, int _nack_delay, int _req_limit,
- int _resp_limit,
- std::vector<Range<Addr> > filter_ranges)
- : Port(_name, _bridge), bridge(_bridge), otherPort(_otherPort),
- delay(_delay), nackDelay(_nack_delay), filterRanges(filter_ranges),
- outstandingResponses(0), queuedRequests(0), inRetry(false),
- reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this)
+Bridge::BridgeSlavePort::BridgeSlavePort(const std::string &_name,
+ Bridge* _bridge,
+ BridgeMasterPort* _masterPort,
+ int _delay, int _nack_delay,
+ int _resp_limit,
+ std::vector<Range<Addr> > _ranges)
+ : Port(_name, _bridge), bridge(_bridge), masterPort(_masterPort),
+ delay(_delay), nackDelay(_nack_delay),
+ ranges(_ranges.begin(), _ranges.end()),
+ outstandingResponses(0), inRetry(false),
+ respQueueLimit(_resp_limit), sendEvent(this)
+{
+}
+
+Bridge::BridgeMasterPort::BridgeMasterPort(const std::string &_name,
+ Bridge* _bridge,
+ BridgeSlavePort* _slavePort,
+ int _delay, int _req_limit)
+ : Port(_name, _bridge), bridge(_bridge), slavePort(_slavePort),
+ delay(_delay), inRetry(false), reqQueueLimit(_req_limit), sendEvent(this)
{
}
Bridge::Bridge(Params *p)
: MemObject(p),
- portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay,
- p->req_size_a, p->resp_size_a, p->filter_ranges_a),
- portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay,
- p->req_size_b, p->resp_size_b, p->filter_ranges_b),
+ slavePort(p->name + "-slave", this, &masterPort, p->delay,
+ p->nack_delay, p->resp_size, p->ranges),
+ masterPort(p->name + "-master", this, &slavePort, p->delay, p->req_size),
ackWrites(p->write_ack), _params(p)
{
if (ackWrites)
panic("No support for acknowledging writes\n");
}
-Port *
+Port*
Bridge::getPort(const std::string &if_name, int idx)
{
- BridgePort *port;
+ Port* port;
- if (if_name == "side_a")
- port = &portA;
- else if (if_name == "side_b")
- port = &portB;
+ if (if_name == "slave")
+ port = &slavePort;
+ else if (if_name == "master")
+ port = &masterPort;
else
return NULL;
- if (port->getPeer() != NULL && !port->getPeer()->isDefaultPort())
+ if (port->getPeer() != NULL)
panic("bridge side %s already connected to %s.",
if_name, port->getPeer()->name());
return port;
@@ -89,106 +109,133 @@ Bridge::getPort(const std::string &if_name, int idx)
void
Bridge::init()
{
- // Make sure that both sides are connected to.
- if (!portA.isConnected() || !portB.isConnected())
+ // make sure both sides are connected and have the same block size
+ if (!slavePort.isConnected() || !masterPort.isConnected())
fatal("Both ports of bus bridge are not connected to a bus.\n");
- if (portA.peerBlockSize() != portB.peerBlockSize())
- fatal("port A size %d, port B size %d \n " \
+ if (slavePort.peerBlockSize() != masterPort.peerBlockSize())
+ fatal("Slave port size %d, master port size %d \n " \
"Busses don't have the same block size... Not supported.\n",
- portA.peerBlockSize(), portB.peerBlockSize());
+ slavePort.peerBlockSize(), masterPort.peerBlockSize());
+
+ // notify the master side of our address ranges
+ slavePort.sendRangeChange();
+}
+
+bool
+Bridge::BridgeSlavePort::respQueueFull()
+{
+ return outstandingResponses == respQueueLimit;
}
bool
-Bridge::BridgePort::respQueueFull()
+Bridge::BridgeMasterPort::reqQueueFull()
{
- assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit);
- return outstandingResponses >= respQueueLimit;
+ return requestQueue.size() == reqQueueLimit;
}
bool
-Bridge::BridgePort::reqQueueFull()
+Bridge::BridgeMasterPort::recvTiming(PacketPtr pkt)
{
- assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit);
- return queuedRequests >= reqQueueLimit;
+ // should only see responses on the master side
+ assert(pkt->isResponse());
+
+ // all checks are done when the request is accepted on the slave
+ // side, so we are guaranteed to have space for the response
+
+ DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+
+ DPRINTF(BusBridge, "Request queue size: %d\n", requestQueue.size());
+
+ slavePort->queueForSendTiming(pkt);
+
+ return true;
}
-/** Function called by the port when the bus is receiving a Timing
- * transaction.*/
bool
-Bridge::BridgePort::recvTiming(PacketPtr pkt)
+Bridge::BridgeSlavePort::recvTiming(PacketPtr pkt)
{
+ // should only see requests on the slave side
+ assert(pkt->isRequest());
+
DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n",
- pkt->getSrc(), pkt->getDest(), pkt->getAddr());
+ pkt->getSrc(), pkt->getDest(), pkt->getAddr());
- DPRINTF(BusBridge, "Local queue size: %d outreq: %d outresp: %d\n",
- sendQueue.size(), queuedRequests, outstandingResponses);
- DPRINTF(BusBridge, "Remote queue size: %d outreq: %d outresp: %d\n",
- otherPort->sendQueue.size(), otherPort->queuedRequests,
- otherPort->outstandingResponses);
+ DPRINTF(BusBridge, "Response queue size: %d outresp: %d\n",
+ responseQueue.size(), outstandingResponses);
- if (pkt->isRequest() && otherPort->reqQueueFull()) {
- DPRINTF(BusBridge, "Remote queue full, nacking\n");
+ if (masterPort->reqQueueFull()) {
+ DPRINTF(BusBridge, "Request queue full, nacking\n");
nackRequest(pkt);
return true;
}
if (pkt->needsResponse()) {
if (respQueueFull()) {
- DPRINTF(BusBridge, "Local queue full, no space for response, nacking\n");
- DPRINTF(BusBridge, "queue size: %d outreq: %d outstanding resp: %d\n",
- sendQueue.size(), queuedRequests, outstandingResponses);
+ DPRINTF(BusBridge,
+ "Response queue full, no space for response, nacking\n");
+ DPRINTF(BusBridge,
+ "queue size: %d outstanding resp: %d\n",
+ responseQueue.size(), outstandingResponses);
nackRequest(pkt);
return true;
} else {
DPRINTF(BusBridge, "Request Needs response, reserving space\n");
+ assert(outstandingResponses != respQueueLimit);
++outstandingResponses;
}
}
- otherPort->queueForSendTiming(pkt);
+ masterPort->queueForSendTiming(pkt);
return true;
}
void
-Bridge::BridgePort::nackRequest(PacketPtr pkt)
+Bridge::BridgeSlavePort::nackRequest(PacketPtr pkt)
{
// Nack the packet
pkt->makeTimingResponse();
pkt->setNacked();
- //put it on the list to send
+ // The Nack packets are stored in the response queue just like any
+ // other response, but they do not occupy any space as this is
+ // tracked by the outstandingResponses, this guarantees space for
+ // the Nack packets, but implicitly means we have an (unrealistic)
+ // unbounded Nack queue.
+
+ // put it on the list to send
Tick readyTime = curTick() + nackDelay;
PacketBuffer *buf = new PacketBuffer(pkt, readyTime, true);
// nothing on the list, add it and we're done
- if (sendQueue.empty()) {
+ if (responseQueue.empty()) {
assert(!sendEvent.scheduled());
- schedule(sendEvent, readyTime);
- sendQueue.push_back(buf);
+ bridge->schedule(sendEvent, readyTime);
+ responseQueue.push_back(buf);
return;
}
assert(sendEvent.scheduled() || inRetry);
// does it go at the end?
- if (readyTime >= sendQueue.back()->ready) {
- sendQueue.push_back(buf);
+ if (readyTime >= responseQueue.back()->ready) {
+ responseQueue.push_back(buf);
return;
}
// ok, somewhere in the middle, fun
- std::list<PacketBuffer*>::iterator i = sendQueue.begin();
- std::list<PacketBuffer*>::iterator end = sendQueue.end();
- std::list<PacketBuffer*>::iterator begin = sendQueue.begin();
+ std::list<PacketBuffer*>::iterator i = responseQueue.begin();
+ std::list<PacketBuffer*>::iterator end = responseQueue.end();
+ std::list<PacketBuffer*>::iterator begin = responseQueue.begin();
bool done = false;
while (i != end && !done) {
if (readyTime < (*i)->ready) {
if (i == begin)
- reschedule(sendEvent, readyTime);
- sendQueue.insert(i,buf);
+ bridge->reschedule(sendEvent, readyTime);
+ responseQueue.insert(i,buf);
done = true;
}
i++;
@@ -196,51 +243,60 @@ Bridge::BridgePort::nackRequest(PacketPtr pkt)
assert(done);
}
-
void
-Bridge::BridgePort::queueForSendTiming(PacketPtr pkt)
+Bridge::BridgeMasterPort::queueForSendTiming(PacketPtr pkt)
{
- 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, "response, new dest %d\n", pkt->getDest());
- delete buf;
+ Tick readyTime = curTick() + delay;
+ PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+
+ // 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 (requestQueue.empty()) {
+ bridge->schedule(sendEvent, readyTime);
}
+ assert(requestQueue.size() != reqQueueLimit);
- if (pkt->isRequest()) {
- ++queuedRequests;
- }
+ requestQueue.push_back(buf);
+}
+void
+Bridge::BridgeSlavePort::queueForSendTiming(PacketPtr pkt)
+{
+ // 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, "response, new dest %d\n", pkt->getDest());
+ delete buf;
Tick readyTime = curTick() + delay;
- PacketBuffer *buf = new PacketBuffer(pkt, readyTime);
+ buf = new PacketBuffer(pkt, readyTime);
// 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()) {
- schedule(sendEvent, readyTime);
+ if (responseQueue.empty()) {
+ bridge->schedule(sendEvent, readyTime);
}
- sendQueue.push_back(buf);
+ responseQueue.push_back(buf);
}
void
-Bridge::BridgePort::trySend()
+Bridge::BridgeMasterPort::trySend()
{
- assert(!sendQueue.empty());
+ assert(!requestQueue.empty());
- PacketBuffer *buf = sendQueue.front();
+ PacketBuffer *buf = requestQueue.front();
assert(buf->ready <= curTick());
@@ -249,110 +305,195 @@ Bridge::BridgePort::trySend()
DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
buf->origSrc, pkt->getDest(), pkt->getAddr());
- bool wasReq = pkt->isRequest();
- bool was_nacked_here = buf->nackedHere;
-
// If the send was successful, make sure sender state was set to NULL
// otherwise we could get a NACK back of a packet that didn't expect a
// response and we would try to use freed memory.
Packet::SenderState *old_sender_state = pkt->senderState;
- if (pkt->isRequest() && !buf->expectResponse)
+ if (!buf->expectResponse)
pkt->senderState = NULL;
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
+ requestQueue.pop_front();
+ // we no longer own packet, so it's not safe to look at it
+ buf->pkt = NULL;
- if (buf->expectResponse) {
- // Must wait for response
- DPRINTF(BusBridge, " successful: awaiting response (%d)\n",
- outstandingResponses);
- } else {
+ if (!buf->expectResponse) {
// no response expected... deallocate packet buffer now.
DPRINTF(BusBridge, " successful: no response expected\n");
delete buf;
}
- if (wasReq)
- --queuedRequests;
- else if (!was_nacked_here)
+ // If there are more packets to send, schedule event to try again.
+ if (!requestQueue.empty()) {
+ buf = requestQueue.front();
+ DPRINTF(BusBridge, "Scheduling next send\n");
+ bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
+ }
+ } else {
+ DPRINTF(BusBridge, " unsuccessful\n");
+ pkt->senderState = old_sender_state;
+ inRetry = true;
+ }
+
+ DPRINTF(BusBridge, "trySend: request queue size: %d\n",
+ requestQueue.size());
+}
+
+void
+Bridge::BridgeSlavePort::trySend()
+{
+ assert(!responseQueue.empty());
+
+ PacketBuffer *buf = responseQueue.front();
+
+ assert(buf->ready <= curTick());
+
+ PacketPtr pkt = buf->pkt;
+
+ DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n",
+ buf->origSrc, pkt->getDest(), pkt->getAddr());
+
+ bool was_nacked_here = buf->nackedHere;
+
+ // no need to worry about the sender state since we are not
+ // modifying it
+
+ if (sendTiming(pkt)) {
+ DPRINTF(BusBridge, " successful\n");
+ // send successful
+ responseQueue.pop_front();
+ // this is a response... deallocate packet buffer now.
+ delete buf;
+
+ if (!was_nacked_here) {
+ assert(outstandingResponses != 0);
--outstandingResponses;
+ }
// If there are more packets to send, schedule event to try again.
- if (!sendQueue.empty()) {
- buf = sendQueue.front();
+ if (!responseQueue.empty()) {
+ buf = responseQueue.front();
DPRINTF(BusBridge, "Scheduling next send\n");
- schedule(sendEvent, std::max(buf->ready, curTick() + 1));
+ bridge->schedule(sendEvent, std::max(buf->ready, curTick() + 1));
}
} else {
DPRINTF(BusBridge, " unsuccessful\n");
- pkt->senderState = old_sender_state;
inRetry = true;
}
- DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n",
- sendQueue.size(), queuedRequests, outstandingResponses);
+ DPRINTF(BusBridge, "trySend: queue size: %d outstanding resp: %d\n",
+ responseQueue.size(), outstandingResponses);
}
+void
+Bridge::BridgeMasterPort::recvRetry()
+{
+ inRetry = false;
+ Tick nextReady = requestQueue.front()->ready;
+ if (nextReady <= curTick())
+ trySend();
+ else
+ bridge->schedule(sendEvent, nextReady);
+}
void
-Bridge::BridgePort::recvRetry()
+Bridge::BridgeSlavePort::recvRetry()
{
inRetry = false;
- Tick nextReady = sendQueue.front()->ready;
+ Tick nextReady = responseQueue.front()->ready;
if (nextReady <= curTick())
trySend();
else
- schedule(sendEvent, nextReady);
+ bridge->schedule(sendEvent, nextReady);
}
-/** Function called by the port when the bus is receiving a Atomic
- * transaction.*/
Tick
-Bridge::BridgePort::recvAtomic(PacketPtr pkt)
+Bridge::BridgeMasterPort::recvAtomic(PacketPtr pkt)
{
- return delay + otherPort->sendAtomic(pkt);
+ // master port should never receive any atomic access (panic only
+ // works once the other side, i.e. the busses, respects this)
+ //
+ //panic("Master port on %s got a recvAtomic\n", bridge->name());
+ return 0;
+}
+
+Tick
+Bridge::BridgeSlavePort::recvAtomic(PacketPtr pkt)
+{
+ return delay + masterPort->sendAtomic(pkt);
}
-/** Function called by the port when the bus is receiving a Functional
- * transaction.*/
void
-Bridge::BridgePort::recvFunctional(PacketPtr pkt)
+Bridge::BridgeMasterPort::recvFunctional(PacketPtr pkt)
+{
+ // master port should never receive any functional access (panic
+ // only works once the other side, i.e. the busses, respect this)
+
+ // panic("Master port on %s got a recvFunctional\n", bridge->name());
+}
+
+void
+Bridge::BridgeSlavePort::recvFunctional(PacketPtr pkt)
{
std::list<PacketBuffer*>::iterator i;
pkt->pushLabel(name());
- for (i = sendQueue.begin(); i != sendQueue.end(); ++i) {
+ // check the response queue
+ for (i = responseQueue.begin(); i != responseQueue.end(); ++i) {
if (pkt->checkFunctional((*i)->pkt)) {
pkt->makeResponse();
return;
}
}
+ // also check the master port's request queue
+ if (masterPort->checkFunctional(pkt)) {
+ return;
+ }
+
pkt->popLabel();
// fall through if pkt still not satisfied
- otherPort->sendFunctional(pkt);
+ masterPort->sendFunctional(pkt);
}
-/** Function called by the port when the bus is receiving a status change.*/
+bool
+Bridge::BridgeMasterPort::checkFunctional(PacketPtr pkt)
+{
+ bool found = false;
+ std::list<PacketBuffer*>::iterator i = requestQueue.begin();
+
+ while(i != requestQueue.end() && !found) {
+ if (pkt->checkFunctional((*i)->pkt)) {
+ pkt->makeResponse();
+ found = true;
+ }
+ ++i;
+ }
+
+ return found;
+}
+
+/** Function called by the port when the bridge is receiving a range change.*/
void
-Bridge::BridgePort::recvStatusChange(Port::Status status)
+Bridge::BridgeMasterPort::recvRangeChange()
{
- otherPort->sendStatusChange(status);
+ // no need to forward as the bridge has a fixed set of ranges
}
void
-Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop)
+Bridge::BridgeSlavePort::recvRangeChange()
+{
+ // is a slave port so do nothing
+}
+
+AddrRangeList
+Bridge::BridgeSlavePort::getAddrRanges()
{
- otherPort->getPeerAddressRanges(resp, snoop);
- FilterRangeList(filterRanges, resp);
- // we don't allow snooping across bridges
- snoop = false;
+ return ranges;
}
Bridge *
diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh
index 732717dd4..d389c0a5e 100644
--- a/src/mem/bridge.hh
+++ b/src/mem/bridge.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -27,11 +39,13 @@
*
* Authors: Ali Saidi
* Steve Reinhardt
+ * Andreas Hansson
*/
/**
* @file
- * Declaration of a simple bus bridge object with no buffering
+ * Declaration of a memory-mapped bus bridge that connects a master
+ * and a slave through a request and response queue.
*/
#ifndef __MEM_BRIDGE_HH__
@@ -49,90 +63,232 @@
#include "params/Bridge.hh"
#include "sim/eventq.hh"
+/**
+ * A bridge is used to interface two different busses (or in general a
+ * memory-mapped master and slave), with buffering for requests and
+ * responses. The bridge has a fixed delay for packets passing through
+ * it and responds to a fixed set of address ranges.
+ *
+ * The bridge comprises a slave port and a master port, that buffer
+ * outgoing responses and requests respectively. Buffer space is
+ * reserved when a request arrives, also reserving response space
+ * before forwarding the request. An incoming request is always
+ * accepted (recvTiming returns true), but is potentially NACKed if
+ * there is no request space or response space.
+ */
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 packet buffer stores packets along with their sender state
+ * and scheduled time for transmission.
+ */
+ class PacketBuffer : public Packet::SenderState, public FastAlloc {
+
+ public:
+ Tick ready;
+ PacketPtr pkt;
+ bool nackedHere;
+ Packet::SenderState *origSenderState;
+ short origSrc;
+ bool expectResponse;
+
+ PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
+ : ready(t), pkt(_pkt), nackedHere(nack),
+ origSenderState(_pkt->senderState),
+ origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
+ expectResponse(_pkt->needsResponse() && !nack)
+
+ {
+ if (!pkt->isResponse() && !nack)
+ pkt->senderState = this;
+ }
+
+ void fixResponse(PacketPtr pkt)
+ {
+ assert(pkt->senderState == this);
+ pkt->setDest(origSrc);
+ pkt->senderState = origSenderState;
+ }
+ };
+
+ // Forward declaration to allow the slave port to have a pointer
+ class BridgeMasterPort;
+
+ /**
+ * The port on the side that receives requests and sends
+ * responses. The slave port has a set of address ranges that it
+ * is responsible for. The slave port also has a buffer for the
+ * responses not yet sent.
+ */
+ class BridgeSlavePort : public Port
{
+
+ private:
+
/** A pointer to the bridge to which this port belongs. */
Bridge *bridge;
/**
- * Pointer to the port on the other side of the bridge
+ * Pointer to the master port on the other side of the bridge
* (connected to the other bus).
*/
- BridgePort *otherPort;
+ BridgeMasterPort* masterPort;
- /** Minimum delay though this bridge. */
+ /** Minimum request delay though this bridge. */
Tick delay;
- /** Min delay to respond to a nack. */
+ /** Min delay to respond with a nack. */
Tick nackDelay;
- /** Pass ranges from one side of the bridge to the other? */
- std::vector<Range<Addr> > filterRanges;
+ /** Address ranges to pass through the bridge */
+ AddrRangeList ranges;
+
+ /**
+ * Response packet queue. Response packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge.
+ */
+ std::list<PacketBuffer*> responseQueue;
- class PacketBuffer : public Packet::SenderState, public FastAlloc {
+ /** Counter to track the outstanding responses. */
+ unsigned int outstandingResponses;
+
+ /** If we're waiting for a retry to happen. */
+ bool inRetry;
+
+ /** Max queue size for reserved responses. */
+ unsigned int respQueueLimit;
+
+ /**
+ * Is this side blocked from accepting new response packets.
+ *
+ * @return true if the reserved space has reached the set limit
+ */
+ bool respQueueFull();
+
+ /**
+ * Turn the request packet into a NACK response and put it in
+ * the response queue and schedule its transmission.
+ *
+ * @param pkt the request packet to NACK
+ */
+ void nackRequest(PacketPtr pkt);
+
+ /**
+ * Handle send event, scheduled when the packet at the head of
+ * the response queue is ready to transmit (for timing
+ * accesses only).
+ */
+ void trySend();
+
+ /**
+ * Private class for scheduling sending of responses from the
+ * response queue.
+ */
+ class SendEvent : public Event
+ {
+ BridgeSlavePort *port;
public:
- Tick ready;
- PacketPtr pkt;
- bool nackedHere;
- Packet::SenderState *origSenderState;
- short origSrc;
- bool expectResponse;
-
- PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false)
- : ready(t), pkt(_pkt), nackedHere(nack),
- origSenderState(_pkt->senderState),
- origSrc(nack ? _pkt->getDest() : _pkt->getSrc() ),
- expectResponse(_pkt->needsResponse() && !nack)
-
- {
- if (!pkt->isResponse() && !nack)
- pkt->senderState = this;
- }
-
- void fixResponse(PacketPtr pkt)
- {
- assert(pkt->senderState == this);
- pkt->setDest(origSrc);
- pkt->senderState = origSenderState;
- }
+ SendEvent(BridgeSlavePort *p) : port(p) {}
+ virtual void process() { port->trySend(); }
+ virtual const char *description() const { return "bridge send"; }
};
+ /** Send event for the response queue. */
+ SendEvent sendEvent;
+
+ public:
+
/**
- * Outbound packet queue. Packets are held in this queue for a
- * specified delay to model the processing delay of the
- * bridge.
+ * Constructor for the BridgeSlavePort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _masterPort the master port on the other side of the bridge
+ * @param _delay the delay from seeing a response to sending it
+ * @param _nack_delay the delay from a NACK to sending the response
+ * @param _resp_limit the size of the response queue
+ * @param _ranges a number of address ranges to forward
*/
- std::list<PacketBuffer*> sendQueue;
+ BridgeSlavePort(const std::string &_name, Bridge *_bridge,
+ BridgeMasterPort* _masterPort, int _delay,
+ int _nack_delay, int _resp_limit,
+ std::vector<Range<Addr> > _ranges);
- int outstandingResponses;
- int queuedRequests;
+ /**
+ * Queue a response packet to be sent out later and also schedule
+ * a send if necessary.
+ *
+ * @param pkt a response to send out after a delay
+ */
+ void queueForSendTiming(PacketPtr pkt);
- /** If we're waiting for a retry to happen.*/
- bool inRetry;
+ protected:
- /** Max queue size for outbound packets */
- int reqQueueLimit;
+ /** When receiving a timing request from the peer port,
+ pass it to the bridge. */
+ virtual bool recvTiming(PacketPtr pkt);
- /** Max queue size for reserved responses. */
- int respQueueLimit;
+ /** 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(PacketPtr pkt);
+
+ /** When receiving a Functional request from the peer port,
+ pass it to the bridge. */
+ virtual void recvFunctional(PacketPtr pkt);
/**
- * Is this side blocked from accepting outbound packets?
+ * When receiving a range change on the slave side do nothing.
*/
- bool respQueueFull();
- bool reqQueueFull();
+ virtual void recvRangeChange();
- void queueForSendTiming(PacketPtr pkt);
+ /** When receiving a address range request the peer port,
+ pass it to the bridge. */
+ virtual AddrRangeList getAddrRanges();
+ };
- void finishSend(PacketBuffer *buf);
- void nackRequest(PacketPtr pkt);
+ /**
+ * Port on the side that forwards requests and receives
+ * responses. The master port has a buffer for the requests not
+ * yet sent.
+ */
+ class BridgeMasterPort : public Port
+ {
+
+ private:
+
+ /** A pointer to the bridge to which this port belongs. */
+ Bridge* bridge;
+
+ /**
+ * Pointer to the slave port on the other side of the bridge
+ * (connected to the other bus).
+ */
+ BridgeSlavePort* slavePort;
+
+ /** Minimum delay though this bridge. */
+ Tick delay;
+
+ /**
+ * Request packet queue. Request packets are held in this
+ * queue for a specified delay to model the processing delay
+ * of the bridge.
+ */
+ std::list<PacketBuffer*> requestQueue;
+
+ /** If we're waiting for a retry to happen. */
+ bool inRetry;
+
+ /** Max queue size for request packets */
+ unsigned int reqQueueLimit;
/**
* Handle send event, scheduled when the packet at the head of
@@ -141,24 +297,62 @@ class Bridge : public MemObject
*/
void trySend();
+ /**
+ * Private class for scheduling sending of requests from the
+ * request queue.
+ */
class SendEvent : public Event
{
- BridgePort *port;
+ BridgeMasterPort *port;
public:
- SendEvent(BridgePort *p) : port(p) {}
+ SendEvent(BridgeMasterPort *p) : port(p) {}
virtual void process() { port->trySend(); }
virtual const char *description() const { return "bridge send"; }
};
+ /** Send event for the request queue. */
SendEvent sendEvent;
public:
- /** Constructor for the BusPort.*/
- BridgePort(const std::string &_name, Bridge *_bridge,
- BridgePort *_otherPort, int _delay, int _nack_delay,
- int _req_limit, int _resp_limit,
- std::vector<Range<Addr> > filter_ranges);
+
+ /**
+ * Constructor for the BridgeMasterPort.
+ *
+ * @param _name the port name including the owner
+ * @param _bridge the structural owner
+ * @param _slavePort the slave port on the other side of the bridge
+ * @param _delay the delay from seeing a request to sending it
+ * @param _req_limit the size of the request queue
+ */
+ BridgeMasterPort(const std::string &_name, Bridge *_bridge,
+ BridgeSlavePort* _slavePort, int _delay,
+ int _req_limit);
+
+ /**
+ * Is this side blocked from accepting new request packets.
+ *
+ * @return true if the occupied space has reached the set limit
+ */
+ bool reqQueueFull();
+
+ /**
+ * Queue a request packet to be sent out later and also schedule
+ * a send if necessary.
+ *
+ * @param pkt a request to send out after a delay
+ */
+ void queueForSendTiming(PacketPtr pkt);
+
+ /**
+ * Check a functional request against the packets in our
+ * request queue.
+ *
+ * @param pkt packet to check against
+ *
+ * @return true if we find a match
+ */
+ bool checkFunctional(PacketPtr pkt);
protected:
@@ -178,17 +372,17 @@ class Bridge : public MemObject
pass it to the bridge. */
virtual void recvFunctional(PacketPtr 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,
- bool &snoop);
+ /**
+ * When receiving a range change, pass it through the bridge.
+ */
+ virtual void recvRangeChange();
};
- BridgePort portA, portB;
+ /** Slave port of the bridge. */
+ BridgeSlavePort slavePort;
+
+ /** Master port of the bridge. */
+ BridgeMasterPort masterPort;
/** If this bridge should acknowledge writes. */
bool ackWrites;
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index db71b86b7..a20f90108 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,6 +38,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
+ * Andreas Hansson
*/
/**
@@ -33,9 +46,6 @@
* Definition of a bus object.
*/
-#include <algorithm>
-#include <limits>
-
#include "base/misc.hh"
#include "base/trace.hh"
#include "debug/Bus.hh"
@@ -46,8 +56,7 @@
Bus::Bus(const BusParams *p)
: MemObject(p), busId(p->bus_id), clock(p->clock),
headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
- drainEvent(NULL), busIdle(this), inRetry(false), maxId(0),
- defaultPort(NULL), funcPort(NULL), funcPortId(-4),
+ drainEvent(NULL), busIdle(this), inRetry(false), defaultPortId(-1),
useDefaultRange(p->use_default_range), defaultBlockSize(p->block_size),
cachedBlockSize(0), cachedBlockSizeValid(false)
{
@@ -58,65 +67,44 @@ Bus::Bus(const BusParams *p)
fatal("Bus clock period must be positive\n");
if (headerCycles <= 0)
fatal("Number of header cycles must be positive\n");
- clearBusCache();
clearPortCache();
}
Port *
Bus::getPort(const std::string &if_name, int idx)
{
+ std::string portName;
+ int id = interfaces.size();
if (if_name == "default") {
- if (defaultPort == NULL) {
- defaultPort = new BusPort(csprintf("%s-default",name()), this,
- defaultId);
- cachedBlockSizeValid = false;
- return defaultPort;
+ if (defaultPortId == -1) {
+ defaultPortId = id;
+ portName = csprintf("%s-default", name());
} else
- fatal("Default port already set\n");
- }
- int id;
- if (if_name == "functional") {
- if (!funcPort) {
- id = maxId++;
- funcPort = new BusPort(csprintf("%s-p%d-func", name(), id), this, id);
- funcPortId = id;
- interfaces[id] = funcPort;
- }
- return funcPort;
+ fatal("Default port already set on %s\n", name());
+ } else {
+ portName = csprintf("%s-p%d", name(), id);
}
-
- // if_name ignored? forced to be empty?
- id = maxId++;
- assert(maxId < std::numeric_limits<typeof(maxId)>::max());
- BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id);
- interfaces[id] = bp;
+ BusPort *bp = new BusPort(portName, this, id);
+ interfaces.push_back(bp);
cachedBlockSizeValid = false;
return bp;
}
void
-Bus::deletePortRefs(Port *p)
-{
-
- BusPort *bp = dynamic_cast<BusPort*>(p);
- if (bp == NULL)
- panic("Couldn't convert Port* to BusPort*\n");
- // If this is our one functional port
- if (funcPort == bp)
- return;
- interfaces.erase(bp->getId());
- clearBusCache();
- delete bp;
-}
-
-/** Get the ranges of anyone other buses that we are connected to. */
-void
Bus::init()
{
- m5::hash_map<short,BusPort*>::iterator intIter;
-
- for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
- intIter->second->sendStatusChange(Port::RangeChange);
+ std::vector<BusPort*>::iterator intIter;
+
+ // iterate over our interfaces and determine which of our neighbours
+ // are snooping and add them as snoopers
+ for (intIter = interfaces.begin(); intIter != interfaces.end();
+ intIter++) {
+ if ((*intIter)->getPeer()->isSnooping()) {
+ DPRINTF(BusAddrRanges, "Adding snooping neighbour %s\n",
+ (*intIter)->getPeer()->name());
+ snoopPorts.push_back(*intIter);
+ }
+ }
}
Bus::BusFreeEvent::BusFreeEvent(Bus *_bus)
@@ -194,16 +182,7 @@ Bus::recvTiming(PacketPtr pkt)
{
short src = pkt->getSrc();
- BusPort *src_port;
- if (src == defaultId)
- src_port = defaultPort;
- else {
- src_port = checkBusCache(src);
- if (src_port == NULL) {
- src_port = interfaces[src];
- updateBusCache(src, src_port);
- }
- }
+ BusPort *src_port = interfaces[src];
// If the bus is busy, or other devices are in line ahead of the current
// one, put this device on the retry list.
@@ -229,8 +208,7 @@ Bus::recvTiming(PacketPtr pkt)
if (dest == Packet::Broadcast) {
dest_port_id = findPort(pkt->getAddr());
- dest_port = (dest_port_id == defaultId) ?
- defaultPort : interfaces[dest_port_id];
+ dest_port = interfaces[dest_port_id];
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
BusPort *p = *s_iter;
@@ -241,20 +219,10 @@ Bus::recvTiming(PacketPtr pkt)
}
}
} else {
- assert(dest < maxId);
+ assert(dest < interfaces.size());
assert(dest != src); // catch infinite loops
dest_port_id = dest;
- if (dest_port_id == defaultId)
- dest_port = defaultPort;
- else {
- dest_port = checkBusCache(dest);
- if (dest_port == NULL) {
- dest_port = interfaces[dest_port_id];
- // updateBusCache(dest_port_id, dest_port);
- }
- }
- dest_port = (dest_port_id == defaultId) ?
- defaultPort : interfaces[dest_port_id];
+ dest_port = interfaces[dest_port_id];
}
if (dest_port_id == src) {
@@ -352,7 +320,7 @@ Bus::findPort(Addr addr)
for (AddrRangeIter i = defaultRange.begin(); i != a_end; i++) {
if (*i == addr) {
DPRINTF(Bus, " found addr %#llx on default\n", addr);
- return defaultId;
+ return defaultPortId;
}
}
@@ -361,7 +329,7 @@ Bus::findPort(Addr addr)
DPRINTF(Bus, "Unable to find destination for addr %#llx, "
"will use default port\n", addr);
- return defaultId;
+ return defaultPortId;
}
@@ -385,16 +353,7 @@ Bus::recvAtomic(PacketPtr pkt)
int orig_src = pkt->getSrc();
int target_port_id = findPort(pkt->getAddr());
- BusPort *target_port;
- if (target_port_id == defaultId)
- target_port = defaultPort;
- else {
- target_port = checkBusCache(target_port_id);
- if (target_port == NULL) {
- target_port = interfaces[target_port_id];
- updateBusCache(target_port_id, target_port);
- }
- }
+ BusPort *target_port = interfaces[target_port_id];
SnoopIter s_end = snoopPorts.end();
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != s_end; s_iter++) {
@@ -450,7 +409,7 @@ Bus::recvFunctional(PacketPtr pkt)
assert(pkt->getDest() == Packet::Broadcast);
int port_id = findPort(pkt->getAddr());
- Port *port = (port_id == defaultId) ? defaultPort : interfaces[port_id];
+ Port *port = interfaces[port_id];
// The packet may be changed by another bus on snoops, restore the
// id after each
int src_id = pkt->getSrc();
@@ -483,30 +442,25 @@ Bus::recvFunctional(PacketPtr pkt)
}
}
-/** Function called by the port when the bus is receiving a status change.*/
+/** Function called by the port when the bus is receiving a range change.*/
void
-Bus::recvStatusChange(Port::Status status, int id)
+Bus::recvRangeChange(int id)
{
AddrRangeList ranges;
- bool snoops;
AddrRangeIter iter;
- if (inRecvStatusChange.count(id))
+ if (inRecvRangeChange.count(id))
return;
- inRecvStatusChange.insert(id);
-
- assert(status == Port::RangeChange &&
- "The other statuses need to be implemented.");
+ inRecvRangeChange.insert(id);
DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id);
clearPortCache();
- if (id == defaultId) {
+ if (id == defaultPortId) {
defaultRange.clear();
// Only try to update these ranges if the user set a default responder.
if (useDefaultRange) {
- defaultPort->getPeerAddressRanges(ranges, snoops);
- assert(snoops == false);
+ AddrRangeList ranges = interfaces[id]->getPeer()->getAddrRanges();
for(iter = ranges.begin(); iter != ranges.end(); iter++) {
defaultRange.push_back(*iter);
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for default range\n",
@@ -515,7 +469,7 @@ Bus::recvStatusChange(Port::Status status, int id)
}
} else {
- assert((id < maxId && id >= 0) || id == defaultId);
+ assert(id < interfaces.size() && id >= 0);
BusPort *port = interfaces[id];
// Clean out any previously existent ids
@@ -527,20 +481,7 @@ Bus::recvStatusChange(Port::Status status, int id)
portIter++;
}
- for (SnoopIter s_iter = snoopPorts.begin();
- s_iter != snoopPorts.end(); ) {
- if ((*s_iter)->getId() == id)
- s_iter = snoopPorts.erase(s_iter);
- else
- s_iter++;
- }
-
- port->getPeerAddressRanges(ranges, snoops);
-
- if (snoops) {
- DPRINTF(BusAddrRanges, "Adding id %d to snoop list\n", id);
- snoopPorts.push_back(port);
- }
+ ranges = port->getPeer()->getAddrRanges();
for (iter = ranges.begin(); iter != ranges.end(); iter++) {
DPRINTF(BusAddrRanges, "Adding range %#llx - %#llx for id %d\n",
@@ -557,28 +498,25 @@ Bus::recvStatusChange(Port::Status status, int id)
// tell all our peers that our address range has changed.
// Don't tell the device that caused this change, it already knows
- m5::hash_map<short,BusPort*>::iterator intIter;
+ std::vector<BusPort*>::const_iterator intIter;
for (intIter = interfaces.begin(); intIter != interfaces.end(); intIter++)
- if (intIter->first != id && intIter->first != funcPortId)
- intIter->second->sendStatusChange(Port::RangeChange);
+ if ((*intIter)->getId() != id)
+ (*intIter)->sendRangeChange();
- if (id != defaultId && defaultPort)
- defaultPort->sendStatusChange(Port::RangeChange);
- inRecvStatusChange.erase(id);
+ inRecvRangeChange.erase(id);
}
-void
-Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
+AddrRangeList
+Bus::getAddrRanges(int id)
{
- resp.clear();
- snoop = false;
+ AddrRangeList ranges;
DPRINTF(BusAddrRanges, "received address range request, returning:\n");
for (AddrRangeIter dflt_iter = defaultRange.begin();
dflt_iter != defaultRange.end(); dflt_iter++) {
- resp.push_back(*dflt_iter);
+ ranges.push_back(*dflt_iter);
DPRINTF(BusAddrRanges, " -- Dflt: %#llx : %#llx\n",dflt_iter->start,
dflt_iter->end);
}
@@ -601,12 +539,21 @@ Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
}
}
if (portIter->second != id && !subset) {
- resp.push_back(portIter->first);
+ ranges.push_back(portIter->first);
DPRINTF(BusAddrRanges, " -- %#llx : %#llx\n",
portIter->first.start, portIter->first.end);
}
}
+ return ranges;
+}
+
+bool
+Bus::isSnooping(int id)
+{
+ // in essence, answer the question if there are other snooping
+ // ports rather than the port that is asking
+ bool snoop = false;
for (SnoopIter s_iter = snoopPorts.begin(); s_iter != snoopPorts.end();
s_iter++) {
if ((*s_iter)->getId() != id) {
@@ -614,6 +561,7 @@ Bus::addressRanges(AddrRangeList &resp, bool &snoop, int id)
break;
}
}
+ return snoop;
}
unsigned
diff --git a/src/mem/bus.hh b/src/mem/bus.hh
index 17d22ec83..5b8b373a5 100644
--- a/src/mem/bus.hh
+++ b/src/mem/bus.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -27,6 +39,7 @@
*
* Authors: Ron Dreslinski
* Ali Saidi
+ * Andreas Hansson
*/
/**
@@ -79,7 +92,16 @@ class Bus : public MemObject
void onRetryList(bool newVal)
{ _onRetryList = newVal; }
- int getId() { return id; }
+ int getId() const { return id; }
+
+ /**
+ * Determine if this port should be considered a snooper. This
+ * is determined by the bus.
+ *
+ * @return a boolean that is true if this port is snooping
+ */
+ virtual bool isSnooping()
+ { return bus->isSnooping(id); }
protected:
@@ -98,10 +120,10 @@ class Bus : public MemObject
virtual void recvFunctional(PacketPtr pkt)
{ pkt->setSrc(id); bus->recvFunctional(pkt); }
- /** When reciving a status changefrom the peer port (at id),
+ /** When reciving a range change from the peer port (at id),
pass it to the bus. */
- virtual void recvStatusChange(Status status)
- { bus->recvStatusChange(status, id); }
+ virtual void recvRangeChange()
+ { bus->recvRangeChange(id); }
/** When reciving a retry from the peer port (at id),
pass it to the bus. */
@@ -112,9 +134,8 @@ class Bus : public MemObject
// 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,
- bool &snoop)
- { bus->addressRanges(resp, snoop, id); }
+ virtual AddrRangeList getAddrRanges()
+ { return bus->getAddrRanges(id); }
// Ask the bus to ask everyone on the bus what their block size is and
// take the max of it. This might need to be changed a bit if we ever
@@ -147,9 +168,6 @@ class Bus : public MemObject
Event * drainEvent;
-
- static const int defaultId = -3; //Make it unique from Broadcast
-
typedef range_map<Addr,int>::iterator PortIter;
range_map<Addr, int> portMap;
@@ -174,8 +192,8 @@ class Bus : public MemObject
* 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);
+ /** Function called by the port when the bus is recieving a range change.*/
+ void recvRangeChange(int id);
/** Find which port connected to this bus (if any) should be given a packet
* with this address.
@@ -238,12 +256,23 @@ class Bus : public MemObject
portCache[0].valid = false;
}
- /** 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.
+ /**
+ * Return the address ranges this port is responsible for.
+ *
+ * @param id id of the bus port that made the request
+ *
+ * @return a list of non-overlapping address ranges
+ */
+ AddrRangeList getAddrRanges(int id);
+
+ /**
+ * Determine if the bus port is snooping or not.
+ *
+ * @param id id of the bus port that made the request
+ *
+ * @return a boolean indicating if this port is snooping or not
*/
- void addressRanges(AddrRangeList &resp, bool &snoop, int id);
+ bool isSnooping(int id);
/** Calculate the timing parameters for the packet. Updates the
* firstWordTime and finishTime fields of the packet object.
@@ -264,14 +293,11 @@ class Bus : public MemObject
BusFreeEvent busIdle;
bool inRetry;
- std::set<int> inRecvStatusChange;
+ std::set<int> inRecvRangeChange;
- /** max number of bus ids we've handed out so far */
- short maxId;
-
- /** An array of pointers to the peer port interfaces
+ /** An ordered vector of pointers to the peer port interfaces
connected to this bus.*/
- m5::hash_map<short,BusPort*> interfaces;
+ std::vector<BusPort*> interfaces;
/** An array of pointers to ports that retry should be called on because the
* original send failed for whatever reason.*/
@@ -300,10 +326,7 @@ class Bus : public MemObject
}
/** Port that handles requests that don't match any of the interfaces.*/
- BusPort *defaultPort;
-
- BusPort *funcPort;
- int funcPortId;
+ short defaultPortId;
/** If true, use address range provided by default device. Any
address not handled by another port and not in default device's
@@ -315,59 +338,10 @@ class Bus : public MemObject
unsigned cachedBlockSize;
bool cachedBlockSizeValid;
- // Cache for the peer port interfaces
- struct BusCache {
- bool valid;
- short id;
- BusPort *port;
- };
-
- BusCache busCache[3];
-
- // Checks the peer port interfaces cache for the port id and returns
- // a pointer to the matching port
- inline BusPort* checkBusCache(short id) {
- if (busCache[0].valid && id == busCache[0].id) {
- return busCache[0].port;
- }
- if (busCache[1].valid && id == busCache[1].id) {
- return busCache[1].port;
- }
- if (busCache[2].valid && id == busCache[2].id) {
- return busCache[2].port;
- }
-
- return NULL;
- }
-
- // Replaces the earliest entry in the cache with a new entry
- inline void updateBusCache(short id, BusPort *port) {
- busCache[2].valid = busCache[1].valid;
- busCache[2].id = busCache[1].id;
- busCache[2].port = busCache[1].port;
-
- busCache[1].valid = busCache[0].valid;
- busCache[1].id = busCache[0].id;
- busCache[1].port = busCache[0].port;
-
- busCache[0].valid = true;
- busCache[0].id = id;
- busCache[0].port = port;
- }
-
- // Invalidates the cache. Needs to be called in constructor.
- inline void clearBusCache() {
- busCache[2].valid = false;
- busCache[1].valid = false;
- busCache[0].valid = false;
- }
-
-
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 deletePortRefs(Port *p);
virtual void init();
virtual void startup();
diff --git a/src/mem/cache/base.cc b/src/mem/cache/base.cc
index 09e3d0869..2b7fa4b9f 100644
--- a/src/mem/cache/base.cc
+++ b/src/mem/cache/base.cc
@@ -71,11 +71,9 @@ BaseCache::BaseCache(const Params *p)
}
void
-BaseCache::CachePort::recvStatusChange(Port::Status status)
+BaseCache::CachePort::recvRangeChange() const
{
- if (status == Port::RangeChange) {
- otherPort->sendStatusChange(Port::RangeChange);
- }
+ otherPort->sendRangeChange();
}
@@ -127,7 +125,7 @@ BaseCache::CachePort::clearBlocked()
mustSendRetry = false;
SendRetryEvent *ev = new SendRetryEvent(this, true);
// @TODO: need to find a better time (next bus cycle?)
- schedule(ev, curTick() + 1);
+ cache->schedule(ev, curTick() + 1);
}
}
@@ -137,7 +135,7 @@ BaseCache::init()
{
if (!cpuSidePort || !memSidePort)
panic("Cache not hooked up on both sides\n");
- cpuSidePort->sendStatusChange(Port::RangeChange);
+ cpuSidePort->sendRangeChange();
}
diff --git a/src/mem/cache/base.hh b/src/mem/cache/base.hh
index 8c39a2400..fded6fca6 100644
--- a/src/mem/cache/base.hh
+++ b/src/mem/cache/base.hh
@@ -105,7 +105,7 @@ class BaseCache : public MemObject
CachePort(const std::string &_name, BaseCache *_cache,
const std::string &_label);
- virtual void recvStatusChange(Status status);
+ virtual void recvRangeChange() const;
virtual unsigned deviceBlockSize() const;
diff --git a/src/mem/cache/cache.hh b/src/mem/cache/cache.hh
index 1ed138bb5..b5c95b301 100644
--- a/src/mem/cache/cache.hh
+++ b/src/mem/cache/cache.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2012 ARM Limited
+ * All rights reserved.
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -78,8 +90,7 @@ class Cache : public BaseCache
return static_cast<Cache<TagStore> *>(cache);
}
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop);
+ virtual AddrRangeList getAddrRanges();
virtual bool recvTiming(PacketPtr pkt);
@@ -106,8 +117,7 @@ class Cache : public BaseCache
void processSendEvent();
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop);
+ virtual bool isSnooping();
virtual bool recvTiming(PacketPtr pkt);
@@ -204,7 +214,6 @@ class Cache : public BaseCache
Cache(const Params *p, TagStore *tags, BasePrefetcher *prefetcher);
virtual Port *getPort(const std::string &if_name, int idx = -1);
- virtual void deletePortRefs(Port *p);
void regStats();
@@ -225,10 +234,9 @@ class Cache : public BaseCache
/**
* Performs the access specified by the request.
* @param pkt The request to perform.
- * @return The result of the access.
+ * @param fromCpuSide from the CPU side port or the memory side port
*/
- void functionalAccess(PacketPtr pkt, CachePort *incomingPort,
- CachePort *otherSidePort);
+ void functionalAccess(PacketPtr pkt, bool fromCpuSide);
/**
* Handles a response (cache line fill/write ack) from the bus.
diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh
index a56495abb..13484eb79 100644
--- a/src/mem/cache/cache_impl.hh
+++ b/src/mem/cache/cache_impl.hh
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2012 ARM Limited
* All rights reserved.
*
* The license below extends only to copyright in the software and shall
@@ -103,30 +103,13 @@ Cache<TagStore>::getPort(const std::string &if_name, int idx)
return cpuSidePort;
} else if (if_name == "mem_side") {
return memSidePort;
- } else if (if_name == "functional") {
- CpuSidePort *funcPort =
- new CpuSidePort(name() + "-cpu_side_funcport", this,
- "CpuSideFuncPort");
- funcPort->setOtherPort(memSidePort);
- return funcPort;
- } else {
+ } else {
panic("Port name %s unrecognized\n", if_name);
}
}
template<class TagStore>
void
-Cache<TagStore>::deletePortRefs(Port *p)
-{
- if (cpuSidePort == p || memSidePort == p)
- panic("Can only delete functional ports\n");
-
- delete p;
-}
-
-
-template<class TagStore>
-void
Cache<TagStore>::cmpAndSwap(BlkType *blk, PacketPtr pkt)
{
uint64_t overwrite_val;
@@ -768,9 +751,7 @@ Cache<TagStore>::atomicAccess(PacketPtr pkt)
template<class TagStore>
void
-Cache<TagStore>::functionalAccess(PacketPtr pkt,
- CachePort *incomingPort,
- CachePort *otherSidePort)
+Cache<TagStore>::functionalAccess(PacketPtr pkt, bool fromCpuSide)
{
Addr blk_addr = blockAlign(pkt->getAddr());
BlkType *blk = tags->findBlock(pkt->getAddr());
@@ -796,10 +777,10 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt,
(mshr && mshr->inService && mshr->isPendingDirty()));
bool done = have_dirty
- || incomingPort->checkFunctional(pkt)
+ || cpuSidePort->checkFunctional(pkt)
|| mshrQueue.checkFunctional(pkt, blk_addr)
|| writeBuffer.checkFunctional(pkt, blk_addr)
- || otherSidePort->checkFunctional(pkt);
+ || memSidePort->checkFunctional(pkt);
DPRINTF(Cache, "functional %s %x %s%s%s\n",
pkt->cmdString(), pkt->getAddr(),
@@ -812,7 +793,15 @@ Cache<TagStore>::functionalAccess(PacketPtr pkt,
if (done) {
pkt->makeResponse();
} else {
- otherSidePort->sendFunctional(pkt);
+ // if it came as a request from the CPU side then make sure it
+ // continues towards the memory side
+ if (fromCpuSide) {
+ memSidePort->sendFunctional(pkt);
+ } else if (forwardSnoops) {
+ // if it came from the memory side, it must be a snoop request
+ // and we should only forward it if we are forwarding snoops
+ cpuSidePort->sendFunctional(pkt);
+ }
}
}
@@ -1559,14 +1548,15 @@ Cache<TagStore>::nextMSHRReadyTime()
///////////////
template<class TagStore>
-void
+AddrRangeList
Cache<TagStore>::CpuSidePort::
-getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+getAddrRanges()
{
// CPU side port doesn't snoop; it's a target only. It can
// potentially respond to any address.
- snoop = false;
- resp.push_back(myCache()->getAddrRange());
+ AddrRangeList ranges;
+ ranges.push_back(myCache()->getAddrRange());
+ return ranges;
}
@@ -1598,7 +1588,7 @@ template<class TagStore>
void
Cache<TagStore>::CpuSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, this, otherPort);
+ myCache()->functionalAccess(pkt, true);
}
@@ -1617,14 +1607,13 @@ CpuSidePort::CpuSidePort(const std::string &_name, Cache<TagStore> *_cache,
///////////////
template<class TagStore>
-void
-Cache<TagStore>::MemSidePort::
-getDeviceAddressRanges(AddrRangeList &resp, bool &snoop)
+bool
+Cache<TagStore>::MemSidePort::isSnooping()
{
// Memory-side port always snoops, but never passes requests
// through to targets on the cpu side (so we don't add anything to
// the address range list).
- snoop = true;
+ return true;
}
@@ -1670,7 +1659,7 @@ template<class TagStore>
void
Cache<TagStore>::MemSidePort::recvFunctional(PacketPtr pkt)
{
- myCache()->functionalAccess(pkt, this, otherPort);
+ myCache()->functionalAccess(pkt, false);
}
@@ -1723,7 +1712,7 @@ Cache<TagStore>::MemSidePort::sendPacket()
// @TODO: need to facotr in prefetch requests here somehow
if (nextReady != MaxTick) {
DPRINTF(CachePort, "more packets to send @ %d\n", nextReady);
- schedule(sendEvent, std::max(nextReady, curTick() + 1));
+ cache->schedule(sendEvent, std::max(nextReady, curTick() + 1));
} else {
// no more to send right now: if we're draining, we may be done
if (drainEvent && !sendEvent->scheduled()) {
diff --git a/src/mem/vport.cc b/src/mem/fs_translating_port_proxy.cc
index ab061c019..c0898a003 100644
--- a/src/mem/vport.cc
+++ b/src/mem/fs_translating_port_proxy.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,6 +38,7 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
+ * Andreas Hansson
*/
/**
@@ -34,49 +47,81 @@
*/
#include "base/chunk_generator.hh"
-#include "config/the_isa.hh"
+#include "cpu/base.hh"
#include "cpu/thread_context.hh"
-#include "mem/vport.hh"
+#include "mem/fs_translating_port_proxy.hh"
+
+using namespace TheISA;
+
+FSTranslatingPortProxy::FSTranslatingPortProxy(ThreadContext *tc)
+ : PortProxy(*(tc->getCpuPtr()->getPort("dcache_port"))), _tc(tc)
+{
+}
+
+FSTranslatingPortProxy::FSTranslatingPortProxy(Port &port)
+ : PortProxy(port), _tc(NULL)
+{
+}
+
+FSTranslatingPortProxy::~FSTranslatingPortProxy()
+{
+}
void
-VirtualPort::readBlob(Addr addr, uint8_t *p, int size)
+FSTranslatingPortProxy::readBlob(Addr addr, uint8_t *p, int size)
{
Addr paddr;
for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
- gen.next())
+ gen.next())
{
- if (tc)
- paddr = TheISA::vtophys(tc,gen.addr());
+ if (_tc)
+ paddr = TheISA::vtophys(_tc,gen.addr());
else
paddr = TheISA::vtophys(gen.addr());
- FunctionalPort::readBlob(paddr, p, gen.size());
+ PortProxy::readBlob(paddr, p, gen.size());
p += gen.size();
}
}
void
-VirtualPort::writeBlob(Addr addr, uint8_t *p, int size)
+FSTranslatingPortProxy::writeBlob(Addr addr, uint8_t *p, int size)
{
Addr paddr;
for (ChunkGenerator gen(addr, size, TheISA::PageBytes); !gen.done();
- gen.next())
+ gen.next())
{
- if (tc)
- paddr = TheISA::vtophys(tc,gen.addr());
+ if (_tc)
+ paddr = TheISA::vtophys(_tc,gen.addr());
else
paddr = TheISA::vtophys(gen.addr());
- FunctionalPort::writeBlob(paddr, p, gen.size());
+ PortProxy::writeBlob(paddr, p, gen.size());
p += gen.size();
}
}
void
+FSTranslatingPortProxy::memsetBlob(Addr address, uint8_t v, int size)
+{
+ Addr paddr;
+ for (ChunkGenerator gen(address, size, TheISA::PageBytes); !gen.done();
+ gen.next())
+ {
+ if (_tc)
+ paddr = TheISA::vtophys(_tc,gen.addr());
+ else
+ paddr = TheISA::vtophys(gen.addr());
+
+ PortProxy::memsetBlob(paddr, v, gen.size());
+ }
+}
+
+void
CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen)
{
uint8_t *dst = (uint8_t *)dest;
- VirtualPort *vp = tc->getVirtPort();
+ FSTranslatingPortProxy* vp = tc->getVirtProxy();
vp->readBlob(src, dst, cplen);
}
@@ -85,7 +130,7 @@ void
CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen)
{
uint8_t *src = (uint8_t *)source;
- VirtualPort *vp = tc->getVirtPort();
+ FSTranslatingPortProxy* vp = tc->getVirtProxy();
vp->writeBlob(dest, src, cplen);
}
@@ -93,21 +138,25 @@ CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen)
void
CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen)
{
- int len = 0;
char *start = dst;
- VirtualPort *vp = tc->getVirtPort();
+ FSTranslatingPortProxy* vp = tc->getVirtProxy();
- do {
- vp->readBlob(vaddr++, (uint8_t*)dst++, 1);
- } while (len < maxlen && start[len++] != 0 );
+ bool foundNull = false;
+ while ((dst - start + 1) < maxlen && !foundNull) {
+ vp->readBlob(vaddr++, (uint8_t*)dst, 1);
+ if (dst == '\0')
+ foundNull = true;
+ dst++;
+ }
- dst[len] = 0;
+ if (!foundNull)
+ *dst = '\0';
}
void
CopyStringIn(ThreadContext *tc, char *src, Addr vaddr)
{
- VirtualPort *vp = tc->getVirtPort();
+ FSTranslatingPortProxy* vp = tc->getVirtProxy();
for (ChunkGenerator gen(vaddr, strlen(src), TheISA::PageBytes); !gen.done();
gen.next())
{
diff --git a/src/mem/vport.hh b/src/mem/fs_translating_port_proxy.hh
index 7cf24587c..826def902 100644
--- a/src/mem/vport.hh
+++ b/src/mem/fs_translating_port_proxy.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2006 The Regents of The University of Michigan
* All rights reserved.
*
@@ -26,44 +38,49 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Ali Saidi
+ * Andreas Hansson
*/
/**
* @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.
+ * TranslatingPortProxy Object Declaration for FS.
+ *
+ * Port proxies are used when non structural entities need access to
+ * the memory system. Proxy objects replace the previous
+ * FunctionalPort, TranslatingPort and VirtualPort objects, which
+ * provided the same functionality as the proxies, but were instances
+ * of ports not corresponding to real structural ports of the
+ * simulated system. Via the port proxies all the accesses go through
+ * an actual port and thus are transparent to a potentially
+ * distributed memory and automatically adhere to the memory map of
+ * the system.
*/
-#ifndef __MEM_VPORT_HH__
-#define __MEM_VPORT_HH__
+#ifndef __MEM_FS_PORT_PROXY_HH__
+#define __MEM_FS_PORT_PROXY_HH__
#include "arch/vtophys.hh"
-#include "mem/port_impl.hh"
+#include "mem/port_proxy.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).
+/**
+ * A TranslatingPortProxy in FS mode translates a virtual address to a
+ * physical address and then calls the read/write functions of the
+ * port. 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
+class FSTranslatingPortProxy : public PortProxy
{
private:
- ThreadContext *tc;
+ 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; }
+ FSTranslatingPortProxy(ThreadContext* tc);
+
+ FSTranslatingPortProxy(Port &port);
+
+ virtual ~FSTranslatingPortProxy();
/** Version of readblob that translates virt->phys and deals
* with page boundries. */
@@ -72,13 +89,16 @@ class VirtualPort : public FunctionalPort
/** Version of writeBlob that translates virt->phys and deals
* with page boundries. */
virtual void writeBlob(Addr addr, uint8_t *p, int size);
-};
+ /**
+ * Fill size bytes starting at addr with byte value val.
+ */
+ virtual void memsetBlob(Addr address, uint8_t v, int size);
+};
void CopyOut(ThreadContext *tc, void *dest, Addr src, size_t cplen);
void CopyIn(ThreadContext *tc, Addr dest, void *source, size_t cplen);
void CopyStringOut(ThreadContext *tc, char *dst, Addr vaddr, size_t maxlen);
void CopyStringIn(ThreadContext *tc, char *src, Addr vaddr);
-#endif //__MEM_VPORT_HH__
-
+#endif //__MEM_FS_PORT_PROXY_HH__
diff --git a/src/mem/mem_object.cc b/src/mem/mem_object.cc
index 20a1b4cd8..111d3718c 100644
--- a/src/mem/mem_object.cc
+++ b/src/mem/mem_object.cc
@@ -34,9 +34,3 @@ MemObject::MemObject(const Params *params)
: SimObject(params)
{
}
-
-void
-MemObject::deletePortRefs(Port *p)
-{
- panic("This object does not support port deletion\n");
-}
diff --git a/src/mem/mem_object.hh b/src/mem/mem_object.hh
index b8bf4b939..5865fc935 100644
--- a/src/mem/mem_object.hh
+++ b/src/mem/mem_object.hh
@@ -56,10 +56,6 @@ class MemObject : public SimObject
public:
/** Additional function to return the Port of a memory object. */
virtual Port *getPort(const std::string &if_name, int idx = -1) = 0;
-
- /** Tell object that this port is about to disappear, so it should remove it
- * from any structures that it's keeping it in. */
- virtual void deletePortRefs(Port *p) ;
};
#endif //__MEM_MEM_OBJECT_HH__
diff --git a/src/mem/packet.cc b/src/mem/packet.cc
index 64f4fcd14..4c3a785dc 100644
--- a/src/mem/packet.cc
+++ b/src/mem/packet.cc
@@ -168,6 +168,9 @@ MemCmd::commandInfo[] =
{ SET2(IsRequest, IsPrint), InvalidCmd, "PrintReq" },
/* Flush Request */
{ SET3(IsRequest, IsFlush, NeedsExclusive), InvalidCmd, "FlushReq" },
+ /* Invalidation Request */
+ { SET3(NeedsExclusive, IsInvalidate, IsRequest),
+ InvalidCmd, "InvalidationReq" },
};
bool
diff --git a/src/mem/packet.hh b/src/mem/packet.hh
index 6347c21ea..e49ce7577 100644
--- a/src/mem/packet.hh
+++ b/src/mem/packet.hh
@@ -108,6 +108,7 @@ class MemCmd
// Fake simulator-only commands
PrintReq, // Print state matching address
FlushReq, //request for a cache flush
+ InvalidationReq, // request for address to be invalidated from lsq
NUM_MEM_CMDS
};
diff --git a/src/mem/physical.cc b/src/mem/physical.cc
index d5c4e892f..09ed8b292 100644
--- a/src/mem/physical.cc
+++ b/src/mem/physical.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010 ARM Limited
+ * Copyright (c) 2010-2011 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -115,7 +115,7 @@ PhysicalMemory::init()
for (PortIterator pi = ports.begin(); pi != ports.end(); ++pi) {
if (*pi)
- (*pi)->sendStatusChange(Port::RangeChange);
+ (*pi)->sendRangeChange();
}
}
@@ -125,6 +125,65 @@ PhysicalMemory::~PhysicalMemory()
munmap((char*)pmemAddr, size());
}
+void
+PhysicalMemory::regStats()
+{
+ using namespace Stats;
+
+ bytesRead
+ .name(name() + ".bytes_read")
+ .desc("Number of bytes read from this memory")
+ ;
+ bytesInstRead
+ .name(name() + ".bytes_inst_read")
+ .desc("Number of instructions bytes read from this memory")
+ ;
+ bytesWritten
+ .name(name() + ".bytes_written")
+ .desc("Number of bytes written to this memory")
+ ;
+ numReads
+ .name(name() + ".num_reads")
+ .desc("Number of read requests responded to by this memory")
+ ;
+ numWrites
+ .name(name() + ".num_writes")
+ .desc("Number of write requests responded to by this memory")
+ ;
+ numOther
+ .name(name() + ".num_other")
+ .desc("Number of other requests responded to by this memory")
+ ;
+ bwRead
+ .name(name() + ".bw_read")
+ .desc("Total read bandwidth from this memory (bytes/s)")
+ .precision(0)
+ .prereq(bytesRead)
+ ;
+ bwInstRead
+ .name(name() + ".bw_inst_read")
+ .desc("Instruction read bandwidth from this memory (bytes/s)")
+ .precision(0)
+ .prereq(bytesInstRead)
+ ;
+ bwWrite
+ .name(name() + ".bw_write")
+ .desc("Write bandwidth from this memory (bytes/s)")
+ .precision(0)
+ .prereq(bytesWritten)
+ ;
+ bwTotal
+ .name(name() + ".bw_total")
+ .desc("Total bandwidth to/from this memory (bytes/s)")
+ .precision(0)
+ .prereq(bwTotal)
+ ;
+ bwRead = bytesRead / simSeconds;
+ bwInstRead = bytesInstRead / simSeconds;
+ bwWrite = bytesWritten / simSeconds;
+ bwTotal = (bytesRead + bytesWritten) / simSeconds;
+}
+
unsigned
PhysicalMemory::deviceBlockSize() const
{
@@ -303,6 +362,7 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt)
assert(!pkt->req->isInstFetch());
TRACE_PACKET("Read/Write");
+ numOther++;
} else if (pkt->isRead()) {
assert(!pkt->isWrite());
if (pkt->isLLSC()) {
@@ -311,12 +371,18 @@ PhysicalMemory::doAtomicAccess(PacketPtr pkt)
if (pmemAddr)
memcpy(pkt->getPtr<uint8_t>(), hostAddr, pkt->getSize());
TRACE_PACKET(pkt->req->isInstFetch() ? "IFetch" : "Read");
+ numReads++;
+ bytesRead += pkt->getSize();
+ if (pkt->req->isInstFetch())
+ bytesInstRead += pkt->getSize();
} else if (pkt->isWrite()) {
if (writeOK(pkt)) {
if (pmemAddr)
memcpy(hostAddr, pkt->getPtr<uint8_t>(), pkt->getSize());
assert(!pkt->req->isInstFetch());
TRACE_PACKET("Write");
+ numWrites++;
+ bytesWritten += pkt->getSize();
}
} else if (pkt->isInvalidate()) {
//upgrade or invalidate
@@ -371,13 +437,6 @@ PhysicalMemory::doFunctionalAccess(PacketPtr pkt)
Port *
PhysicalMemory::getPort(const std::string &if_name, int idx)
{
- // Accept request for "functional" port for backwards compatibility
- // with places where this function is called from C++. I'd prefer
- // to move all these into Python someday.
- if (if_name == "functional") {
- return new MemoryPort(csprintf("%s-functional", name()), this);
- }
-
if (if_name != "port") {
panic("PhysicalMemory::getPort: unknown port %s requested", if_name);
}
@@ -397,36 +456,30 @@ PhysicalMemory::getPort(const std::string &if_name, int idx)
return port;
}
-
-void
-PhysicalMemory::recvStatusChange(Port::Status status)
-{
-}
-
PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name,
PhysicalMemory *_memory)
: SimpleTimingPort(_name, _memory), memory(_memory)
{ }
void
-PhysicalMemory::MemoryPort::recvStatusChange(Port::Status status)
+PhysicalMemory::MemoryPort::recvRangeChange()
{
- memory->recvStatusChange(status);
+ // memory is a slave and thus should never have to worry about its
+ // neighbours address ranges
}
-void
-PhysicalMemory::MemoryPort::getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop)
+AddrRangeList
+PhysicalMemory::MemoryPort::getAddrRanges()
{
- memory->getAddressRanges(resp, snoop);
+ return memory->getAddrRanges();
}
-void
-PhysicalMemory::getAddressRanges(AddrRangeList &resp, bool &snoop)
+AddrRangeList
+PhysicalMemory::getAddrRanges()
{
- snoop = false;
- resp.clear();
- resp.push_back(RangeSize(start(), size()));
+ AddrRangeList ranges;
+ ranges.push_back(RangeSize(start(), size()));
+ return ranges;
}
unsigned
diff --git a/src/mem/physical.hh b/src/mem/physical.hh
index cd6d809e2..b447237c7 100644
--- a/src/mem/physical.hh
+++ b/src/mem/physical.hh
@@ -38,11 +38,13 @@
#include <string>
#include "base/range.hh"
+#include "base/statistics.hh"
#include "mem/mem_object.hh"
#include "mem/packet.hh"
#include "mem/tport.hh"
#include "params/PhysicalMemory.hh"
#include "sim/eventq.hh"
+#include "sim/stats.hh"
//
// Functional model for a contiguous block of physical memory. (i.e. RAM)
@@ -65,10 +67,9 @@ class PhysicalMemory : public MemObject
virtual void recvFunctional(PacketPtr pkt);
- virtual void recvStatusChange(Status status);
+ virtual void recvRangeChange();
- virtual void getDeviceAddressRanges(AddrRangeList &resp,
- bool &snoop);
+ virtual AddrRangeList getAddrRanges();
virtual unsigned deviceBlockSize() const;
};
@@ -155,6 +156,28 @@ class PhysicalMemory : public MemObject
uint64_t _size;
uint64_t _start;
+
+ /** Number of total bytes read from this memory */
+ Stats::Scalar bytesRead;
+ /** Number of instruction bytes read from this memory */
+ Stats::Scalar bytesInstRead;
+ /** Number of bytes written to this memory */
+ Stats::Scalar bytesWritten;
+ /** Number of read requests */
+ Stats::Scalar numReads;
+ /** Number of write requests */
+ Stats::Scalar numWrites;
+ /** Number of other requests */
+ Stats::Scalar numOther;
+ /** Read bandwidth from this memory */
+ Stats::Formula bwRead;
+ /** Read bandwidth from this memory */
+ Stats::Formula bwInstRead;
+ /** Write bandwidth from this memory */
+ Stats::Formula bwWrite;
+ /** Total bandwidth from this memory */
+ Stats::Formula bwTotal;
+
public:
uint64_t size() { return _size; }
uint64_t start() { return _start; }
@@ -172,7 +195,7 @@ class PhysicalMemory : public MemObject
public:
unsigned deviceBlockSize() const;
- void getAddressRanges(AddrRangeList &resp, bool &snoop);
+ AddrRangeList getAddrRanges();
virtual Port *getPort(const std::string &if_name, int idx = -1);
void virtual init();
unsigned int drain(Event *de);
@@ -181,9 +204,13 @@ class PhysicalMemory : public MemObject
Tick doAtomicAccess(PacketPtr pkt);
void doFunctionalAccess(PacketPtr pkt);
virtual Tick calculateLatency(PacketPtr pkt);
- void recvStatusChange(Port::Status status);
public:
+ /**
+ * Register Statistics
+ */
+ void regStats();
+
virtual void serialize(std::ostream &os);
virtual void unserialize(Checkpoint *cp, const std::string &section);
diff --git a/src/mem/port.cc b/src/mem/port.cc
index c87785a49..fb1715db6 100644
--- a/src/mem/port.cc
+++ b/src/mem/port.cc
@@ -40,61 +40,8 @@
#include "mem/mem_object.hh"
#include "mem/port.hh"
-class DefaultPeerPort : public Port
-{
- protected:
- void blowUp() const
- {
- fatal("%s: Unconnected port!", peer->name());
- }
-
- public:
- DefaultPeerPort()
- : Port("default_port", NULL)
- { }
-
- bool recvTiming(PacketPtr)
- {
- blowUp();
- return false;
- }
-
- Tick recvAtomic(PacketPtr)
- {
- blowUp();
- return 0;
- }
-
- void recvFunctional(PacketPtr)
- {
- blowUp();
- }
-
- void recvStatusChange(Status)
- {
- blowUp();
- }
-
- unsigned
- deviceBlockSize() const
- {
- blowUp();
- return 0;
- }
-
- void getDeviceAddressRanges(AddrRangeList &, bool &)
- {
- blowUp();
- }
-
- bool isDefaultPort() const { return true; }
-};
-
-DefaultPeerPort defaultPeerPort;
-
Port::Port(const std::string &_name, MemObject *_owner)
- : EventManager(_owner), portName(_name), peer(&defaultPeerPort),
- owner(_owner)
+ : portName(_name), peer(NULL), owner(_owner)
{
}
@@ -113,19 +60,10 @@ Port::setPeer(Port *port)
void
Port::setOwner(MemObject *_owner)
{
- eventq = _owner->queue();
owner = _owner;
}
void
-Port::removeConn()
-{
- if (peer->getOwner())
- peer->getOwner()->deletePortRefs(peer);
- peer = NULL;
-}
-
-void
Port::blobHelper(Addr addr, uint8_t *p, int size, MemCmd cmd)
{
Request req;
diff --git a/src/mem/port.hh b/src/mem/port.hh
index bb74bf497..98b3ad5f1 100644
--- a/src/mem/port.hh
+++ b/src/mem/port.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2002-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -47,10 +59,8 @@
#include "base/types.hh"
#include "mem/packet.hh"
#include "mem/request.hh"
-#include "sim/eventq.hh"
-/** This typedef is used to clean up the parameter list of
- * getDeviceAddressRanges() and getPeerAddressRanges(). It's declared
+/** This typedef is used to clean up getAddrRanges(). 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.
@@ -59,7 +69,6 @@
typedef std::list<Range<Addr> > AddrRangeList;
typedef std::list<Range<Addr> >::iterator AddrRangeIter;
-class EventQueue;
class MemObject;
/**
@@ -73,7 +82,7 @@ class MemObject;
* 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 : public EventManager
+class Port
{
protected:
/** Descriptive name (for DPRINTF output) */
@@ -103,13 +112,6 @@ class Port : public EventManager
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
- };
-
void setName(const std::string &name)
{ portName = name; }
@@ -125,13 +127,7 @@ class Port : public EventManager
/** Function to return the owner of this port. */
MemObject *getOwner() { return owner; }
- /** Inform the peer port to delete itself and notify it's owner about it's
- * demise. */
- void removeConn();
-
- virtual bool isDefaultPort() const { return false; }
-
- bool isConnected() { return peer && !peer->isDefaultPort(); }
+ bool isConnected() { return peer != NULL; }
protected:
@@ -147,8 +143,8 @@ class Port : public EventManager
/** Called to recive a functional call from the peer port. */
virtual void recvFunctional(PacketPtr pkt) = 0;
- /** Called to recieve a status change from the peer port. */
- virtual void recvStatusChange(Status status) = 0;
+ /** Called to recieve an address range change from the peer port. */
+ virtual void recvRangeChange() = 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).
@@ -163,17 +159,31 @@ class Port : public EventManager
*/
virtual unsigned deviceBlockSize() const { return 0; }
- /** 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,
- bool &snoop)
- { panic("??"); }
-
public:
+ /**
+ * Get a list of the non-overlapping address ranges we are
+ * responsible for. The default implementation returns an empty
+ * list and thus no address ranges. Any slave port must override
+ * this function and return a populated list with at least one
+ * item.
+ *
+ * @return a list of ranges responded to
+ */
+ virtual AddrRangeList getAddrRanges()
+ { AddrRangeList ranges; return ranges; }
+
+ /**
+ * Determine if this port is snooping or not. The default
+ * implementation returns false and thus tells the neighbour we
+ * are not snooping. Any port that is to snoop (e.g. a cache
+ * connected to a bus) has to override this function.
+ *
+ * @return true if the port should be considered a snooper
+ */
+ virtual bool isSnooping()
+ { return false; }
+
/** 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.
@@ -201,10 +211,11 @@ class Port : public EventManager
void sendFunctional(PacketPtr 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); }
+ /**
+ * Called by the associated device to send a status range to the
+ * peer interface.
+ */
+ void sendRangeChange() const { peer->recvRangeChange(); }
/** When a timing access doesn't return a success, some time later the
Retry will be sent.
@@ -216,12 +227,6 @@ class Port : public EventManager
*/
unsigned peerBlockSize() const { 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, bool &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
@@ -255,48 +260,4 @@ class Port : public EventManager
void blobHelper(Addr addr, uint8_t *p, int size, MemCmd 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, MemObject *_owner = NULL)
- : Port(_name, _owner)
- {}
-
- protected:
- virtual bool recvTiming(PacketPtr pkt) { panic("FuncPort is UniDir");
- M5_DUMMY_RETURN }
- virtual Tick recvAtomic(PacketPtr pkt) { panic("FuncPort is UniDir");
- M5_DUMMY_RETURN }
- virtual void recvFunctional(PacketPtr 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_proxy.hh b/src/mem/port_proxy.hh
new file mode 100644
index 000000000..31ad4c1cd
--- /dev/null
+++ b/src/mem/port_proxy.hh
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Andreas Hansson
+ */
+
+/**
+ * @file
+ * PortProxy Object Declaration.
+ *
+ * Port proxies are used when non structural entities need access to
+ * the memory system. Proxy objects replace the previous
+ * FunctionalPort, TranslatingPort and VirtualPort objects, which
+ * provided the same functionality as the proxies, but were instances
+ * of ports not corresponding to real structural ports of the
+ * simulated system. Via the port proxies all the accesses go through
+ * an actual port and thus are transparent to a potentially
+ * distributed memory and automatically adhere to the memory map of
+ * the system.
+ */
+
+#ifndef __MEM_PORT_PROXY_HH__
+#define __MEM_PORT_PROXY_HH__
+
+#include "config/the_isa.hh"
+#if THE_ISA != NO_ISA
+ #include "arch/isa_traits.hh"
+#endif
+
+#include "base/types.hh"
+#include "mem/port.hh"
+#include "sim/byteswap.hh"
+
+/**
+ * This object is a proxy for a structural port,
+ * to be used for debug accesses.
+ *
+ * This proxy object is used when non structural entities
+ * (e.g. thread contexts, object file loaders) need access to the
+ * memory system. It calls the corresponding functions on the underlying
+ * structural port, and provides templatized convenience access functions.
+ *
+ * The addresses are interpreted as physical addresses.
+ *
+ * @sa SETranslatingProxy
+ * @sa FSTranslatingProxy
+ */
+class PortProxy
+{
+ protected:
+ Port &_port;
+
+ public:
+ PortProxy(Port &port) : _port(port) { }
+ virtual ~PortProxy() { }
+
+ public:
+ /**
+ * Read size bytes memory at address and store in p.
+ */
+ virtual void readBlob(Addr address, uint8_t* p, int size)
+ { _port.readBlob(address, p, size); }
+
+ /**
+ * Write size bytes from p to address.
+ */
+ virtual void writeBlob(Addr address, uint8_t* p, int size)
+ { _port.writeBlob(address, p, size); }
+
+ /**
+ * Fill size bytes starting at addr with byte value val.
+ */
+ virtual void memsetBlob(Addr address, uint8_t v, int size)
+ { _port.memsetBlob(address, v, size); }
+
+ /**
+ * Read sizeof(T) bytes from address and return as object T.
+ */
+ template <typename T>
+ T read(Addr address);
+
+ /**
+ * Write object T to address. Writes sizeof(T) bytes.
+ */
+ template <typename T>
+ void write(Addr address, T data);
+
+#if THE_ISA != NO_ISA
+ /**
+ * Read sizeof(T) bytes from address and return as object T.
+ * Performs Guest to Host endianness transform.
+ */
+ template <typename T>
+ T readGtoH(Addr address);
+
+ /**
+ * Write object T to address. Writes sizeof(T) bytes.
+ * Performs Host to Guest endianness transform.
+ */
+ template <typename T>
+ void writeHtoG(Addr address, T data);
+#endif
+};
+
+
+template <typename T>
+T
+PortProxy::read(Addr address)
+{
+ T data;
+ readBlob(address, (uint8_t*)&data, sizeof(T));
+ return data;
+}
+
+template <typename T>
+void
+PortProxy::write(Addr address, T data)
+{
+ writeBlob(address, (uint8_t*)&data, sizeof(T));
+}
+
+#if THE_ISA != NO_ISA
+template <typename T>
+T
+PortProxy::readGtoH(Addr address)
+{
+ T data;
+ readBlob(address, (uint8_t*)&data, sizeof(T));
+ return TheISA::gtoh(data);
+}
+
+template <typename T>
+void
+PortProxy::writeHtoG(Addr address, T data)
+{
+ data = TheISA::htog(data);
+ writeBlob(address, (uint8_t*)&data, sizeof(T));
+}
+#endif
+
+#endif // __MEM_PORT_PROXY_HH__
diff --git a/src/mem/protocol/MESI_CMP_directory-L1cache.sm b/src/mem/protocol/MESI_CMP_directory-L1cache.sm
index f0be1fd34..934405786 100644
--- a/src/mem/protocol/MESI_CMP_directory-L1cache.sm
+++ b/src/mem/protocol/MESI_CMP_directory-L1cache.sm
@@ -27,14 +27,15 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-machine(L1Cache, "MSI Directory L1 Cache CMP")
+machine(L1Cache, "MESI Directory L1 Cache CMP")
: Sequencer * sequencer,
CacheMemory * L1IcacheMemory,
CacheMemory * L1DcacheMemory,
int l2_select_num_bits,
int l1_request_latency = 2,
int l1_response_latency = 2,
- int to_l2_latency = 1
+ int to_l2_latency = 1,
+ bool send_evictions
{
// NODE L1 CACHE
// From this node's L1 cache TO the network
@@ -67,7 +68,6 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
IS_I, AccessPermission:Busy, desc="L1 idle, issued GETS, saw Inv before data because directory doesn't block on GETS hit";
M_I, AccessPermission:Busy, desc="L1 replacing, waiting for ACK";
- E_I, AccessPermission:Busy, desc="L1 replacing, waiting for ACK";
SINK_WB_ACK, AccessPermission:Busy, desc="This is to sink WB_Acks from L2";
}
@@ -544,6 +544,12 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
}
}
+ action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
action(g_issuePUTX, "g", desc="send data to the L2 cache") {
enqueue(requestIntraChipL1Network_out, RequestMsg, latency=l1_response_latency) {
@@ -696,7 +702,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
//*****************************************************
// Transitions for Load/Store/Replacement/WriteBack from transient states
- transition({IS, IM, IS_I, M_I, E_I, SM}, {Load, Ifetch, Store, L1_Replacement}) {
+ transition({IS, IM, IS_I, M_I, SM}, {Load, Ifetch, Store, L1_Replacement}) {
z_recycleMandatoryQueue;
}
@@ -748,10 +754,12 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
}
transition(S, L1_Replacement, I) {
+ forward_eviction_to_cpu;
ff_deallocateL1CacheBlock;
}
transition(S, Inv, I) {
+ forward_eviction_to_cpu;
fi_sendInvAck;
l_popRequestQueue;
}
@@ -770,6 +778,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
transition(E, L1_Replacement, M_I) {
// silent E replacement??
+ forward_eviction_to_cpu;
i_allocateTBE;
g_issuePUTX; // send data, but hold in case forwarded request
ff_deallocateL1CacheBlock;
@@ -777,11 +786,13 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
transition(E, Inv, I) {
// don't send data
+ forward_eviction_to_cpu;
fi_sendInvAck;
l_popRequestQueue;
}
transition(E, Fwd_GETX, I) {
+ forward_eviction_to_cpu;
d_sendDataToRequestor;
l_popRequestQueue;
}
@@ -804,6 +815,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
}
transition(M, L1_Replacement, M_I) {
+ forward_eviction_to_cpu;
i_allocateTBE;
g_issuePUTX; // send data, but hold in case forwarded request
ff_deallocateL1CacheBlock;
@@ -815,6 +827,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
}
transition(M, Inv, I) {
+ forward_eviction_to_cpu;
f_sendDataToL2;
l_popRequestQueue;
}
@@ -825,6 +838,7 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
}
transition(M, Fwd_GETX, I) {
+ forward_eviction_to_cpu;
d_sendDataToRequestor;
l_popRequestQueue;
}
@@ -866,7 +880,6 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
o_popIncomingResponseQueue;
}
-
transition(IS, DataS_fromL1, S) {
u_writeDataToL1Cache;
j_sendUnblock;
@@ -935,7 +948,6 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
transition(SINK_WB_ACK, {Load, Store, Ifetch, L1_Replacement}){
z_recycleMandatoryQueue;
-
}
transition(SINK_WB_ACK, Inv){
@@ -948,6 +960,3 @@ machine(L1Cache, "MSI Directory L1 Cache CMP")
o_popIncomingResponseQueue;
}
}
-
-
-
diff --git a/src/mem/protocol/MI_example-cache.sm b/src/mem/protocol/MI_example-cache.sm
index b11fddd95..2f2e4e3d7 100644
--- a/src/mem/protocol/MI_example-cache.sm
+++ b/src/mem/protocol/MI_example-cache.sm
@@ -3,7 +3,8 @@ machine(L1Cache, "MI Example L1 Cache")
: Sequencer * sequencer,
CacheMemory * cacheMemory,
int cache_response_latency = 12,
- int issue_latency = 2
+ int issue_latency = 2,
+ bool send_evictions
{
// NETWORK BUFFERS
@@ -54,7 +55,6 @@ machine(L1Cache, "MI Example L1 Cache")
DataBlock DataBlk, desc="Data in the block";
}
-
// TBE fields
structure(TBE, desc="...") {
State TBEState, desc="Transient state";
@@ -70,7 +70,6 @@ machine(L1Cache, "MI Example L1 Cache")
// STRUCTURES
-
TBETable TBEs, template_hack="<L1Cache_TBE>";
// PROTOTYPES
@@ -249,7 +248,6 @@ machine(L1Cache, "MI Example L1 Cache")
}
}
-
action(e_sendData, "e", desc="Send data from cache to requestor") {
peek(forwardRequestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, latency=cache_response_latency) {
@@ -353,13 +351,18 @@ machine(L1Cache, "MI Example L1 Cache")
}
}
+ action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
action(v_allocateTBE, "v", desc="Allocate TBE") {
TBEs.allocate(address);
set_tbe(TBEs[address]);
}
-
action(w_deallocateTBE, "w", desc="Deallocate TBE") {
TBEs.deallocate(address);
unset_tbe();
@@ -435,6 +438,7 @@ machine(L1Cache, "MI Example L1 Cache")
transition(M, Fwd_GETX, I) {
e_sendData;
+ forward_eviction_to_cpu;
o_popForwardedRequestQueue;
}
@@ -446,6 +450,7 @@ machine(L1Cache, "MI Example L1 Cache")
v_allocateTBE;
b_issuePUT;
x_copyDataFromCacheToTBE;
+ forward_eviction_to_cpu;
h_deallocateL1CacheBlock;
}
@@ -474,4 +479,3 @@ machine(L1Cache, "MI Example L1 Cache")
o_popForwardedRequestQueue;
}
}
-
diff --git a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm
index 2845d1ad1..7a5cc6511 100644
--- a/src/mem/protocol/MOESI_CMP_directory-L1cache.sm
+++ b/src/mem/protocol/MOESI_CMP_directory-L1cache.sm
@@ -37,7 +37,8 @@ machine(L1Cache, "Directory protocol")
CacheMemory * L1IcacheMemory,
CacheMemory * L1DcacheMemory,
int l2_select_num_bits,
- int request_latency = 2
+ int request_latency = 2,
+ bool send_evictions
{
// NODE L1 CACHE
@@ -530,7 +531,6 @@ machine(L1Cache, "Directory protocol")
}
}
-
action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
@@ -689,7 +689,6 @@ machine(L1Cache, "Directory protocol")
useTimerTable.set(address, 50);
}
-
action(ub_dmaUnblockL2Cache, "ub", desc="Send dma ack to l2 cache") {
peek(requestNetwork_in, RequestMsg) {
enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
@@ -775,7 +774,6 @@ machine(L1Cache, "Directory protocol")
}
}
-
// L2 will usually request data for a writeback
action(qq_sendWBDataFromTBEToL2, "\q", desc="Send data from TBE to L2") {
enqueue(responseNetwork_out, ResponseMsg, latency=request_latency) {
@@ -811,7 +809,6 @@ machine(L1Cache, "Directory protocol")
//assert(in_msg.Dirty == false);
}
}
-
}
action(v_writeDataToCacheVerify, "v", desc="Write data to cache, assert it was same as before") {
@@ -844,7 +841,12 @@ machine(L1Cache, "Directory protocol")
}
}
-
+ action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
action(uu_profileMiss, "\u", desc="Profile the demand miss") {
peek(mandatoryQueue_in, RubyRequest) {
@@ -931,11 +933,13 @@ machine(L1Cache, "Directory protocol")
transition(S, L1_Replacement, SI) {
i_allocateTBE;
dd_issuePUTS;
+ forward_eviction_to_cpu;
kk_deallocateL1CacheBlock;
}
transition(S, Inv, I) {
f_sendAck;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -966,11 +970,13 @@ machine(L1Cache, "Directory protocol")
transition(O, L1_Replacement, OI) {
i_allocateTBE;
dd_issuePUTO;
+ forward_eviction_to_cpu;
kk_deallocateL1CacheBlock;
}
transition(O, Fwd_GETX, I) {
ee_sendDataExclusive;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -999,16 +1005,19 @@ machine(L1Cache, "Directory protocol")
transition(MM, L1_Replacement, MI) {
i_allocateTBE;
d_issuePUTX;
+ forward_eviction_to_cpu;
kk_deallocateL1CacheBlock;
}
transition(MM, Fwd_GETX, I) {
ee_sendDataExclusive;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
transition(MM, Fwd_GETS, I) {
ee_sendDataExclusive;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1037,12 +1046,14 @@ machine(L1Cache, "Directory protocol")
transition(M, L1_Replacement, MI) {
i_allocateTBE;
d_issuePUTX;
+ forward_eviction_to_cpu;
kk_deallocateL1CacheBlock;
}
transition(M, Fwd_GETX, I) {
// e_sendData;
ee_sendDataExclusive;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1080,6 +1091,7 @@ machine(L1Cache, "Directory protocol")
// Transitions from SM
transition(SM, Inv, IM) {
f_sendAck;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
diff --git a/src/mem/protocol/MOESI_CMP_token-L1cache.sm b/src/mem/protocol/MOESI_CMP_token-L1cache.sm
index 66789b594..7cc41cc20 100644
--- a/src/mem/protocol/MOESI_CMP_token-L1cache.sm
+++ b/src/mem/protocol/MOESI_CMP_token-L1cache.sm
@@ -43,7 +43,8 @@ machine(L1Cache, "Token protocol")
int retry_threshold = 1,
int fixed_timeout_latency = 100,
bool dynamic_timeout_enabled = true,
- bool no_mig_atomic = true
+ bool no_mig_atomic = true,
+ bool send_evictions
{
// From this node's L1 cache TO the network
@@ -1398,7 +1399,6 @@ machine(L1Cache, "Token protocol")
}
}
-
action(q_updateTokensFromResponse, "q", desc="Update the token count based on the incoming response message") {
peek(responseNetwork_in, ResponseMsg) {
assert(is_valid(cache_entry));
@@ -1522,6 +1522,13 @@ machine(L1Cache, "Token protocol")
}
}
+ action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
+
action(uu_profileMiss, "\u", desc="Profile the demand miss") {
peek(mandatoryQueue_in, RubyRequest) {
if (L1DcacheMemory.isTagPresent(address)) {
@@ -1572,7 +1579,6 @@ machine(L1Cache, "Token protocol")
zz_stallAndWaitMandatoryQueue;
}
-
// Lockdowns
transition({NP, I, S, O, M, MM, M_W, MM_W, IM, SM, OM, IS}, Own_Lock_or_Unlock) {
l_popPersistentQueue;
@@ -1702,6 +1708,7 @@ machine(L1Cache, "Token protocol")
transition(S, L1_Replacement, I) {
ta_traceStalledAddress;
cc_sharedReplacement; // Only needed in some cases
+ forward_eviction_to_cpu;
gg_deallocateL1CacheBlock;
ka_wakeUpAllDependents;
}
@@ -1709,6 +1716,7 @@ machine(L1Cache, "Token protocol")
transition(S, {Transient_GETX, Transient_Local_GETX}, I) {
t_sendAckWithCollectedTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
m_popRequestQueue;
}
@@ -1729,6 +1737,7 @@ machine(L1Cache, "Token protocol")
transition({S, S_L}, Persistent_GETX, I_L) {
e_sendAckWithCollectedTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -1780,6 +1789,7 @@ machine(L1Cache, "Token protocol")
transition(O, L1_Replacement, I) {
ta_traceStalledAddress;
c_ownedReplacement;
+ forward_eviction_to_cpu
gg_deallocateL1CacheBlock;
ka_wakeUpAllDependents;
}
@@ -1787,12 +1797,14 @@ machine(L1Cache, "Token protocol")
transition(O, {Transient_GETX, Transient_Local_GETX}, I) {
dd_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
m_popRequestQueue;
}
transition(O, Persistent_GETX, I_L) {
ee_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -1803,6 +1815,7 @@ machine(L1Cache, "Token protocol")
transition(O, Persistent_GETS_Last_Token, I_L) {
fo_sendDataWithOwnerToken;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -1867,6 +1880,7 @@ machine(L1Cache, "Token protocol")
transition(MM, L1_Replacement, I) {
ta_traceStalledAddress;
c_ownedReplacement;
+ forward_eviction_to_cpu
gg_deallocateL1CacheBlock;
ka_wakeUpAllDependents;
}
@@ -1874,6 +1888,7 @@ machine(L1Cache, "Token protocol")
transition(MM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_Local_GETS}, I) {
dd_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
m_popRequestQueue;
}
@@ -1885,6 +1900,7 @@ machine(L1Cache, "Token protocol")
transition(MM, {Persistent_GETX, Persistent_GETS}, I_L) {
ee_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -1934,6 +1950,7 @@ machine(L1Cache, "Token protocol")
transition(M, L1_Replacement, I) {
ta_traceStalledAddress;
c_ownedReplacement;
+ forward_eviction_to_cpu
gg_deallocateL1CacheBlock;
ka_wakeUpAllDependents;
}
@@ -1941,6 +1958,7 @@ machine(L1Cache, "Token protocol")
transition(M, {Transient_GETX, Transient_Local_GETX}, I) {
dd_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
m_popRequestQueue;
}
@@ -1961,6 +1979,7 @@ machine(L1Cache, "Token protocol")
transition(M, Persistent_GETX, I_L) {
ee_sendDataWithAllTokens;
p_informL2AboutTokenLoss;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -1990,22 +2009,21 @@ machine(L1Cache, "Token protocol")
transition(M_W, Use_TimeoutStarverX, I_L) {
s_deallocateTBE;
ee_sendDataWithAllTokens;
+ forward_eviction_to_cpu;
p_informL2AboutTokenLoss;
jj_unsetUseTimer;
}
-
-
// migratory
transition(MM_W, {Use_TimeoutStarverX, Use_TimeoutStarverS}, I_L) {
s_deallocateTBE;
ee_sendDataWithAllTokens;
+ forward_eviction_to_cpu;
p_informL2AboutTokenLoss;
jj_unsetUseTimer;
}
-
// Transient_GETX and Transient_GETS in transient states
transition(OM, {Transient_GETX, Transient_Local_GETX, Transient_GETS, Transient_GETS_Last_Token, Transient_Local_GETS_Last_Token, Transient_Local_GETS}) {
m_popRequestQueue; // Even if we have the data, we can pretend we don't have it yet.
@@ -2040,6 +2058,7 @@ machine(L1Cache, "Token protocol")
transition({SM, SM_L}, Persistent_GETX, IM_L) {
e_sendAckWithCollectedTokens;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -2054,6 +2073,7 @@ machine(L1Cache, "Token protocol")
transition(OM, Persistent_GETX, IM_L) {
ee_sendDataWithAllTokens;
+ forward_eviction_to_cpu
l_popPersistentQueue;
}
@@ -2120,6 +2140,7 @@ machine(L1Cache, "Token protocol")
transition({IM, SM}, {Transient_GETX, Transient_Local_GETX}, IM) { // We don't have the data yet, but we might have collected some tokens. We give them up here to avoid livelock
t_sendAckWithCollectedTokens;
+ forward_eviction_to_cpu;
m_popRequestQueue;
}
@@ -2336,7 +2357,6 @@ machine(L1Cache, "Token protocol")
kd_wakeUpDependents;
}
-
// Own_Lock_or_Unlock
transition(I_L, Own_Lock_or_Unlock, I) {
@@ -2364,4 +2384,3 @@ machine(L1Cache, "Token protocol")
kd_wakeUpDependents;
}
}
-
diff --git a/src/mem/protocol/MOESI_hammer-cache.sm b/src/mem/protocol/MOESI_hammer-cache.sm
index ce16a8777..219096d26 100644
--- a/src/mem/protocol/MOESI_hammer-cache.sm
+++ b/src/mem/protocol/MOESI_hammer-cache.sm
@@ -41,7 +41,8 @@ machine(L1Cache, "AMD Hammer-like protocol")
int cache_response_latency = 10,
int issue_latency = 2,
int l2_cache_hit_latency = 10,
- bool no_mig_atomic = true
+ bool no_mig_atomic = true,
+ bool send_evictions
{
// NETWORK BUFFERS
@@ -1207,6 +1208,13 @@ machine(L1Cache, "AMD Hammer-like protocol")
unset_cache_entry();
}
+ action(forward_eviction_to_cpu, "\cc", desc="sends eviction information to the processor") {
+ if (send_evictions) {
+ DPRINTF(RubySlicc, "Sending invalidation for %s to the CPU\n", address);
+ sequencer.evictionCallback(address);
+ }
+ }
+
action(uu_profileMiss, "\u", desc="Profile the demand miss") {
peek(mandatoryQueue_in, RubyRequest) {
if (L1IcacheMemory.isTagPresent(address)) {
@@ -1486,17 +1494,20 @@ machine(L1Cache, "AMD Hammer-like protocol")
i_allocateTBE;
bf_issueGETF;
uu_profileMiss;
+ forward_eviction_to_cpu;
gg_deallocateL1CacheBlock;
k_popMandatoryQueue;
}
transition(S, L2_Replacement, I) {
+ forward_eviction_to_cpu;
rr_deallocateL2CacheBlock;
ka_wakeUpAllDependents;
}
transition(S, {Other_GETX, Invalidate}, I) {
f_sendAck;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1528,6 +1539,7 @@ machine(L1Cache, "AMD Hammer-like protocol")
bf_issueGETF;
p_decrementNumberOfMessagesByOne;
uu_profileMiss;
+ forward_eviction_to_cpu;
gg_deallocateL1CacheBlock;
k_popMandatoryQueue;
}
@@ -1535,12 +1547,14 @@ machine(L1Cache, "AMD Hammer-like protocol")
transition(O, L2_Replacement, OI) {
i_allocateTBE;
d_issuePUT;
+ forward_eviction_to_cpu;
rr_deallocateL2CacheBlock;
ka_wakeUpAllDependents;
}
transition(O, {Other_GETX, Invalidate}, I) {
e_sendData;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1569,6 +1583,7 @@ machine(L1Cache, "AMD Hammer-like protocol")
i_allocateTBE;
bf_issueGETF;
p_decrementNumberOfMessagesByOne;
+ forward_eviction_to_cpu;
gg_deallocateL1CacheBlock;
k_popMandatoryQueue;
}
@@ -1582,17 +1597,20 @@ machine(L1Cache, "AMD Hammer-like protocol")
transition(MM, L2_Replacement, MI) {
i_allocateTBE;
d_issuePUT;
+ forward_eviction_to_cpu;
rr_deallocateL2CacheBlock;
ka_wakeUpAllDependents;
}
transition(MM, {Other_GETX, Invalidate}, I) {
c_sendExclusiveData;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
transition(MM, Other_GETS, I) {
c_sendExclusiveData;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1625,12 +1643,14 @@ machine(L1Cache, "AMD Hammer-like protocol")
transition(M, L2_Replacement, MI) {
i_allocateTBE;
d_issuePUT;
+ forward_eviction_to_cpu;
rr_deallocateL2CacheBlock;
ka_wakeUpAllDependents;
}
transition(M, {Other_GETX, Invalidate}, I) {
c_sendExclusiveData;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1700,11 +1720,13 @@ machine(L1Cache, "AMD Hammer-like protocol")
transition(SM, {Other_GETX, Invalidate}, IM) {
f_sendAck;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
transition(SM_F, {Other_GETX, Invalidate}, IM_F) {
f_sendAck;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
@@ -1754,12 +1776,14 @@ machine(L1Cache, "AMD Hammer-like protocol")
transition(OM, {Other_GETX, Invalidate}, IM) {
e_sendData;
pp_incrementNumberOfMessagesByOne;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
transition(OM_F, {Other_GETX, Invalidate}, IM_F) {
q_sendDataFromTBEToCache;
pp_incrementNumberOfMessagesByOne;
+ forward_eviction_to_cpu;
l_popForwardQueue;
}
diff --git a/src/mem/protocol/MOESI_hammer-dir.sm b/src/mem/protocol/MOESI_hammer-dir.sm
index a20619d46..dfb62e844 100644
--- a/src/mem/protocol/MOESI_hammer-dir.sm
+++ b/src/mem/protocol/MOESI_hammer-dir.sm
@@ -87,7 +87,7 @@ machine(Directory, "AMD Hammer-like protocol")
O_DR_B, AccessPermission:Busy, desc="Owner, Dma Read waiting for cache responses";
WB, AccessPermission:Busy, desc="Blocked on a writeback";
WB_O_W, AccessPermission:Busy, desc="Blocked on memory write, will go to O";
- WB_E_W, AccessPermission:Busy, desc="Blocked on memory write, will go to E";
+ WB_E_W, AccessPermission:Read_Write, desc="Blocked on memory write, will go to E";
NO_F, AccessPermission:Busy, desc="Blocked on a flush";
NO_F_W, AccessPermission:Busy, desc="Not Owner, Blocked, waiting for Dram";
diff --git a/src/mem/protocol/RubySlicc_Types.sm b/src/mem/protocol/RubySlicc_Types.sm
index c76e0fe3e..3b90dab20 100644
--- a/src/mem/protocol/RubySlicc_Types.sm
+++ b/src/mem/protocol/RubySlicc_Types.sm
@@ -107,6 +107,7 @@ structure (Sequencer, external = "yes") {
void writeCallback(Address, GenericMachineType, DataBlock, Time, Time, Time);
void checkCoherence(Address);
void profileNack(Address, int, int, uint64);
+ void evictionCallback(Address);
}
structure(RubyRequest, desc="...", interface="Message", external="yes") {
diff --git a/src/mem/ruby/system/RubyPort.cc b/src/mem/ruby/system/RubyPort.cc
index 64faf6aed..b60ca2a07 100644
--- a/src/mem/ruby/system/RubyPort.cc
+++ b/src/mem/ruby/system/RubyPort.cc
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * Copyright (c) 2011 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -93,14 +94,6 @@ RubyPort::getPort(const std::string &if_name, int idx)
return physMemPort;
}
- if (if_name == "functional") {
- // Calls for the functional port only want to access
- // functional memory. Therefore, directly pass these calls
- // ports to physmem.
- assert(physmem != NULL);
- return physmem->getPort(if_name, idx);
- }
-
return NULL;
}
@@ -464,8 +457,11 @@ RubyPort::M5Port::recvFunctional(PacketPtr pkt)
// turn packet around to go back to requester if response expected
if (needsResponse) {
pkt->setFunctionalResponseStatus(accessSucceeded);
- DPRINTF(RubyPort, "Sending packet back over port\n");
- sendFunctional(pkt);
+
+ // @todo There should not be a reverse call since the response is
+ // communicated through the packet pointer
+ // DPRINTF(RubyPort, "Sending packet back over port\n");
+ // sendFunctional(pkt);
}
DPRINTF(RubyPort, "Functional access %s!\n",
accessSucceeded ? "successful":"failed");
@@ -668,9 +664,8 @@ RubyPort::PioPort::sendTiming(PacketPtr pkt)
bool
RubyPort::M5Port::isPhysMemAddress(Addr addr)
{
- AddrRangeList physMemAddrList;
- bool snoop = false;
- ruby_port->physMemPort->getPeerAddressRanges(physMemAddrList, snoop);
+ AddrRangeList physMemAddrList =
+ ruby_port->physMemPort->getPeer()->getAddrRanges();
for (AddrRangeIter iter = physMemAddrList.begin();
iter != physMemAddrList.end();
iter++) {
@@ -688,3 +683,14 @@ RubyPort::M5Port::deviceBlockSize() const
{
return (unsigned) RubySystem::getBlockSizeBytes();
}
+
+void
+RubyPort::ruby_eviction_callback(const Address& address)
+{
+ DPRINTF(RubyPort, "Sending invalidations.\n");
+ Request req(address.getAddress(), 0, 0);
+ for (CpuPortIter it = cpu_ports.begin(); it != cpu_ports.end(); it++) {
+ Packet *pkt = new Packet(&req, MemCmd::InvalidationReq, -1);
+ (*it)->sendTiming(pkt);
+ }
+}
diff --git a/src/mem/ruby/system/RubyPort.hh b/src/mem/ruby/system/RubyPort.hh
index d8dbe0cda..2ffdef3d9 100644
--- a/src/mem/ruby/system/RubyPort.hh
+++ b/src/mem/ruby/system/RubyPort.hh
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2009 Advanced Micro Devices, Inc.
+ * Copyright (c) 2011 Mark D. Hill and David A. Wood
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -58,6 +59,7 @@ class RubyPort : public MemObject
RubySystem*_system, bool _access_phys_mem);
bool sendTiming(PacketPtr pkt);
void hitCallback(PacketPtr pkt);
+ void evictionCallback(const Address& address);
unsigned deviceBlockSize() const;
bool onRetryList()
@@ -129,8 +131,8 @@ class RubyPort : public MemObject
protected:
const std::string m_name;
void ruby_hit_callback(PacketPtr pkt);
- void hit(PacketPtr pkt);
void testDrainComplete();
+ void ruby_eviction_callback(const Address& address);
int m_version;
AbstractController* m_controller;
diff --git a/src/mem/port_impl.hh b/src/mem/ruby/system/RubyPortProxy.cc
index bc9592164..29a693ca6 100644
--- a/src/mem/port_impl.hh
+++ b/src/mem/ruby/system/RubyPortProxy.cc
@@ -1,6 +1,15 @@
/*
- * Copyright (c) 2006 The Regents of The University of Michigan
- * All rights reserved.
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -25,29 +34,37 @@
* (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
+ * Authors: Andreas Hansson
*/
-#include "arch/isa_traits.hh"
-#include "config/the_isa.hh"
-#include "mem/port.hh"
-#include "sim/byteswap.hh"
+#include "mem/ruby/system/RubyPortProxy.hh"
-template <typename T>
-void
-FunctionalPort::writeHtoG(Addr addr, T d)
+RubyPortProxy::RubyPortProxy(const RubyPortProxyParams* p) :
+ RubyPort(p) {
+}
+
+RubyPortProxy::~RubyPortProxy()
{
- d = TheISA::htog(d);
- writeBlob(addr, (uint8_t*)&d, sizeof(T));
}
+void
+RubyPortProxy::init()
+{
+ // Merely override to not care about the m_controller being NULL
+}
-template <typename T>
-T
-FunctionalPort::readGtoH(Addr addr)
+RequestStatus
+RubyPortProxy::makeRequest(PacketPtr pkt)
{
- T d;
- readBlob(addr, (uint8_t*)&d, sizeof(T));
- return TheISA::gtoh(d);
+ // This sequencer should only be used through the functional
+ // accesses made by the system port and so simply fail if this
+ // happens.
+ panic("RubyPortProxy::makeRequest should not be called");
+ return RequestStatus_NULL;
}
+RubyPortProxy*
+RubyPortProxyParams::create()
+{
+ return new RubyPortProxy(this);
+}
diff --git a/src/mem/ruby/system/RubyPortProxy.hh b/src/mem/ruby/system/RubyPortProxy.hh
new file mode 100644
index 000000000..8f88541e5
--- /dev/null
+++ b/src/mem/ruby/system/RubyPortProxy.hh
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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: Andreas Hansson
+ */
+
+/**
+ * @file
+ * RobyPortProxy for connecting system port to Ruby
+ *
+ * A trivial wrapper that allows the system port to connect to Ruby
+ * and use nothing but functional accesses.
+ */
+
+#ifndef __MEM_RUBY_SYSTEM_RUBYPORTPROXY_HH__
+#define __MEM_RUBY_SYSTEM_RUBYPORTPROXY_HH__
+
+#include "mem/ruby/system/RubyPort.hh"
+#include "params/RubyPortProxy.hh"
+
+class RubyPortProxy : public RubyPort
+{
+
+ public:
+
+ /**
+ * Create a new RubyPortProxy.
+ *
+ * @param p Parameters inherited from the RubyPort
+ */
+ RubyPortProxy(const RubyPortProxyParams* p);
+
+ /**
+ * Destruct a RubyPortProxy.
+ */
+ virtual ~RubyPortProxy();
+
+ /**
+ * Initialise a RubyPortProxy by doing nothing and avoid
+ * involving the super class.
+ */
+ void init();
+
+ /**
+ * Pure virtual member in the super class that we are forced to
+ * implement even if it is never used (since there are only
+ * functional accesses).
+ *
+ * @param pkt The packet to serve to Ruby
+ * @returns always a NULL status
+ */
+ RequestStatus makeRequest(PacketPtr pkt);
+
+ /**
+ * Pure virtual member in the super class that we are forced to
+ * implement even if it is never used (since there are only
+ * functional accesses).
+ *
+ * @returns always 0
+ */
+ int outstandingCount() const { return 0; }
+
+ /**
+ * Pure virtual member in the super class that we are forced to
+ * implement even if it is never used (since there are only
+ * functional accesses).
+ *
+ * @returns always false
+ */
+ bool isDeadlockEventScheduled() const { return false; }
+
+ /**
+ * Pure virtual member in the super class that we are forced to
+ * implement even if it is never used (since there are only
+ * functional accesses).
+ */
+ void descheduleDeadlockEvent() { }
+
+};
+
+#endif // __MEM_RUBY_SYSTEM_RUBYPORTPROXY_HH__
diff --git a/src/mem/ruby/system/SConscript b/src/mem/ruby/system/SConscript
index 66d7d95bb..cbb1da3b1 100644
--- a/src/mem/ruby/system/SConscript
+++ b/src/mem/ruby/system/SConscript
@@ -49,6 +49,7 @@ Source('WireBuffer.cc')
Source('MemoryNode.cc')
Source('PersistentTable.cc')
Source('RubyPort.cc')
+Source('RubyPortProxy.cc')
Source('Sequencer.cc')
Source('System.cc')
Source('TimerTable.cc')
diff --git a/src/mem/ruby/system/Sequencer.cc b/src/mem/ruby/system/Sequencer.cc
index 3f9ceb34d..1cd54d45c 100644
--- a/src/mem/ruby/system/Sequencer.cc
+++ b/src/mem/ruby/system/Sequencer.cc
@@ -733,3 +733,9 @@ Sequencer::checkCoherence(const Address& addr)
g_system_ptr->checkGlobalCoherenceInvariant(addr);
#endif
}
+
+void
+Sequencer::evictionCallback(const Address& address)
+{
+ ruby_eviction_callback(address);
+}
diff --git a/src/mem/ruby/system/Sequencer.hh b/src/mem/ruby/system/Sequencer.hh
index 4a6d46c01..e262e32e8 100644
--- a/src/mem/ruby/system/Sequencer.hh
+++ b/src/mem/ruby/system/Sequencer.hh
@@ -117,6 +117,7 @@ class Sequencer : public RubyPort, public Consumer
void markRemoved();
void removeRequest(SequencerRequest* request);
+ void evictionCallback(const Address& address);
private:
void issueRequest(PacketPtr pkt, RubyRequestType type);
@@ -181,4 +182,3 @@ operator<<(std::ostream& out, const Sequencer& obj)
}
#endif // __MEM_RUBY_SYSTEM_SEQUENCER_HH__
-
diff --git a/src/mem/ruby/system/Sequencer.py b/src/mem/ruby/system/Sequencer.py
index 5d56dc000..ddf760f7b 100644
--- a/src/mem/ruby/system/Sequencer.py
+++ b/src/mem/ruby/system/Sequencer.py
@@ -44,6 +44,9 @@ class RubyPort(MemObject):
access_phys_mem = Param.Bool(True,
"should the rubyport atomically update phys_mem")
ruby_system = Param.RubySystem("")
+
+class RubyPortProxy(RubyPort):
+ type = 'RubyPortProxy'
class RubySequencer(RubyPort):
type = 'RubySequencer'
diff --git a/src/mem/translating_port.cc b/src/mem/se_translating_port_proxy.cc
index 7d3123012..0f7ecb491 100644
--- a/src/mem/translating_port.cc
+++ b/src/mem/se_translating_port_proxy.cc
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -27,6 +39,7 @@
*
* Authors: Ron Dreslinski
* Steve Reinhardt
+ * Andreas Hansson
*/
#include <string>
@@ -35,22 +48,22 @@
#include "base/chunk_generator.hh"
#include "config/the_isa.hh"
#include "mem/page_table.hh"
-#include "mem/port.hh"
-#include "mem/translating_port.hh"
+#include "mem/se_translating_port_proxy.hh"
#include "sim/process.hh"
using namespace TheISA;
-TranslatingPort::TranslatingPort(const std::string &_name, Process *p,
- AllocType alloc)
- : FunctionalPort(_name), pTable(p->pTable), process(p), allocating(alloc)
+SETranslatingPortProxy::SETranslatingPortProxy(Port& port, Process *p,
+ AllocType alloc)
+ : PortProxy(port), pTable(p->pTable), process(p),
+ allocating(alloc)
{ }
-TranslatingPort::~TranslatingPort()
+SETranslatingPortProxy::~SETranslatingPortProxy()
{ }
bool
-TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size)
+SETranslatingPortProxy::tryReadBlob(Addr addr, uint8_t *p, int size)
{
int prevSize = 0;
@@ -60,7 +73,7 @@ TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size)
if (!pTable->translate(gen.addr(),paddr))
return false;
- Port::readBlob(paddr, p + prevSize, gen.size());
+ PortProxy::readBlob(paddr, p + prevSize, gen.size());
prevSize += gen.size();
}
@@ -68,7 +81,7 @@ TranslatingPort::tryReadBlob(Addr addr, uint8_t *p, int size)
}
void
-TranslatingPort::readBlob(Addr addr, uint8_t *p, int size)
+SETranslatingPortProxy::readBlob(Addr addr, uint8_t *p, int size)
{
if (!tryReadBlob(addr, p, size))
fatal("readBlob(0x%x, ...) failed", addr);
@@ -76,7 +89,7 @@ TranslatingPort::readBlob(Addr addr, uint8_t *p, int size)
bool
-TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size)
+SETranslatingPortProxy::tryWriteBlob(Addr addr, uint8_t *p, int size)
{
int prevSize = 0;
@@ -98,7 +111,7 @@ TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size)
pTable->translate(gen.addr(), paddr);
}
- Port::writeBlob(paddr, p + prevSize, gen.size());
+ PortProxy::writeBlob(paddr, p + prevSize, gen.size());
prevSize += gen.size();
}
@@ -107,14 +120,14 @@ TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size)
void
-TranslatingPort::writeBlob(Addr addr, uint8_t *p, int size)
+SETranslatingPortProxy::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)
+SETranslatingPortProxy::tryMemsetBlob(Addr addr, uint8_t val, int size)
{
for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) {
Addr paddr;
@@ -128,14 +141,15 @@ TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size)
return false;
}
}
- Port::memsetBlob(paddr, val, gen.size());
+
+ PortProxy::memsetBlob(paddr, val, gen.size());
}
return true;
}
void
-TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size)
+SETranslatingPortProxy::memsetBlob(Addr addr, uint8_t val, int size)
{
if (!tryMemsetBlob(addr, val, size))
fatal("memsetBlob(0x%x, ...) failed", addr);
@@ -143,7 +157,7 @@ TranslatingPort::memsetBlob(Addr addr, uint8_t val, int size)
bool
-TranslatingPort::tryWriteString(Addr addr, const char *str)
+SETranslatingPortProxy::tryWriteString(Addr addr, const char *str)
{
uint8_t c;
@@ -156,21 +170,21 @@ TranslatingPort::tryWriteString(Addr addr, const char *str)
if (!pTable->translate(vaddr++, paddr))
return false;
- Port::writeBlob(paddr, &c, 1);
+ PortProxy::writeBlob(paddr, &c, 1);
} while (c);
return true;
}
void
-TranslatingPort::writeString(Addr addr, const char *str)
+SETranslatingPortProxy::writeString(Addr addr, const char *str)
{
if (!tryWriteString(addr, str))
fatal("writeString(0x%x, ...) failed", addr);
}
bool
-TranslatingPort::tryReadString(std::string &str, Addr addr)
+SETranslatingPortProxy::tryReadString(std::string &str, Addr addr)
{
uint8_t c;
@@ -182,7 +196,7 @@ TranslatingPort::tryReadString(std::string &str, Addr addr)
if (!pTable->translate(vaddr++, paddr))
return false;
- Port::readBlob(paddr, &c, 1);
+ PortProxy::readBlob(paddr, &c, 1);
str += c;
} while (c);
@@ -190,7 +204,7 @@ TranslatingPort::tryReadString(std::string &str, Addr addr)
}
void
-TranslatingPort::readString(std::string &str, Addr addr)
+SETranslatingPortProxy::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/se_translating_port_proxy.hh
index 438d8fe61..71e8b4f50 100644
--- a/src/mem/translating_port.hh
+++ b/src/mem/se_translating_port_proxy.hh
@@ -1,4 +1,16 @@
/*
+ * Copyright (c) 2011 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
* Copyright (c) 2001-2005 The Regents of The University of Michigan
* All rights reserved.
*
@@ -27,18 +39,33 @@
*
* Authors: Ron Dreslinski
* Ali Saidi
+ * Andreas Hansson
*/
-#ifndef __MEM_TRANSLATING_PROT_HH__
-#define __MEM_TRANSLATING_PROT_HH__
-
-#include "mem/port.hh"
+#ifndef __MEM_SE_TRANSLATING_PORT_PROXY_HH__
+#define __MEM_SE_TRANSLATING_PORT_PROXY_HH__
-class PageTable;
-class Process;
+#include "mem/page_table.hh"
+#include "mem/port_proxy.hh"
+#include "sim/process.hh"
-class TranslatingPort : public FunctionalPort
+/**
+ * @file
+ * TranslatingPortProxy Object Declaration for SE.
+ *
+ * Port proxies are used when non structural entities need access to
+ * the memory system. Proxy objects replace the previous
+ * FunctionalPort, TranslatingPort and VirtualPort objects, which
+ * provided the same functionality as the proxies, but were instances
+ * of ports not corresponding to real structural ports of the
+ * simulated system. Via the port proxies all the accesses go through
+ * an actual port and thus are transparent to a potentially
+ * distributed memory and automatically adhere to the memory map of
+ * the system.
+ */
+class SETranslatingPortProxy : public PortProxy
{
+
public:
enum AllocType {
Always,
@@ -52,8 +79,8 @@ class TranslatingPort : public FunctionalPort
AllocType allocating;
public:
- TranslatingPort(const std::string &_name, Process *p, AllocType alloc);
- virtual ~TranslatingPort();
+ SETranslatingPortProxy(Port& port, Process* p, AllocType alloc);
+ virtual ~SETranslatingPortProxy();
bool tryReadBlob(Addr addr, uint8_t *p, int size);
bool tryWriteBlob(Addr addr, uint8_t *p, int size);
@@ -69,4 +96,4 @@ class TranslatingPort : public FunctionalPort
void readString(std::string &str, Addr addr);
};
-#endif
+#endif // __MEM_SE_TRANSLATING_PORT_PROXY_HH__
diff --git a/src/mem/tport.cc b/src/mem/tport.cc
index 8e02215f2..7b1fdb850 100644
--- a/src/mem/tport.cc
+++ b/src/mem/tport.cc
@@ -29,12 +29,13 @@
*/
#include "debug/Bus.hh"
+#include "mem/mem_object.hh"
#include "mem/tport.hh"
using namespace std;
SimpleTimingPort::SimpleTimingPort(string pname, MemObject *_owner)
- : Port(pname, _owner), sendEvent(0), drainEvent(NULL),
+ : Port(pname, _owner), sendEvent(NULL), drainEvent(NULL),
waitingOnRetry(false)
{
sendEvent = new EventWrapper<SimpleTimingPort,
@@ -104,6 +105,20 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
return true;
}
+void
+SimpleTimingPort::schedSendEvent(Tick when)
+{
+ if (waitingOnRetry) {
+ assert(!sendEvent->scheduled());
+ return;
+ }
+
+ if (!sendEvent->scheduled()) {
+ owner->schedule(sendEvent, when);
+ } else if (sendEvent->when() > when) {
+ owner->reschedule(sendEvent, when);
+ }
+}
void
SimpleTimingPort::schedSendTiming(PacketPtr pkt, Tick when)
@@ -153,7 +168,7 @@ SimpleTimingPort::sendDeferredPacket()
if (success) {
if (!transmitList.empty() && !sendEvent->scheduled()) {
Tick time = transmitList.front().tick;
- schedule(sendEvent, time <= curTick() ? curTick()+1 : time);
+ owner->schedule(sendEvent, time <= curTick() ? curTick()+1 : time);
}
if (transmitList.empty() && drainEvent && !sendEvent->scheduled()) {
diff --git a/src/mem/tport.hh b/src/mem/tport.hh
index f081d8656..eaf5acd5d 100644
--- a/src/mem/tport.hh
+++ b/src/mem/tport.hh
@@ -106,21 +106,14 @@ class SimpleTimingPort : public Port
Tick deferredPacketReadyTime()
{ return transmitList.empty() ? MaxTick : transmitList.front().tick; }
- void
- schedSendEvent(Tick when)
- {
- if (waitingOnRetry) {
- assert(!sendEvent->scheduled());
- return;
- }
-
- if (!sendEvent->scheduled()) {
- schedule(sendEvent, when);
- } else if (sendEvent->when() > when) {
- reschedule(sendEvent, when);
- }
- }
-
+ /**
+ * Schedule a send even if not already waiting for a retry. If the
+ * requested time is before an already scheduled send event it
+ * will be rescheduled.
+ *
+ * @param when
+ */
+ void schedSendEvent(Tick when);
/** Schedule a sendTiming() event to be called in the future.
* @param pkt packet to send
@@ -146,10 +139,13 @@ class SimpleTimingPort : public Port
bool recvTiming(PacketPtr 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) { }
+ * Simple ports are generally used as slave ports (i.e. the
+ * respond to requests) and thus do not expect to receive any
+ * range changes (as the neighbouring port has a master role and
+ * do not have any address ranges. A subclass can override the
+ * default behaviuor if needed.
+ */
+ virtual void recvRangeChange() { }
public: