diff options
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/bridge.cc | 189 | ||||
-rw-r--r-- | src/mem/bridge.hh | 57 | ||||
-rw-r--r-- | src/mem/bus.cc | 23 | ||||
-rw-r--r-- | src/mem/cache/cache_impl.hh | 8 | ||||
-rw-r--r-- | src/mem/tport.cc | 1 | ||||
-rw-r--r-- | src/mem/translating_port.cc | 17 | ||||
-rw-r--r-- | src/mem/translating_port.hh | 13 |
7 files changed, 229 insertions, 79 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index b25d135e2..e89473be3 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -43,21 +43,22 @@ Bridge::BridgePort::BridgePort(const std::string &_name, Bridge *_bridge, BridgePort *_otherPort, - int _delay, int _queueLimit, - bool fix_partial_write) + int _delay, int _nack_delay, int _req_limit, + int _resp_limit, bool fix_partial_write) : Port(_name), bridge(_bridge), otherPort(_otherPort), - delay(_delay), fixPartialWrite(fix_partial_write), - outstandingResponses(0), queueLimit(_queueLimit), sendEvent(this) + delay(_delay), nackDelay(_nack_delay), fixPartialWrite(fix_partial_write), + outstandingResponses(0), queuedRequests(0), inRetry(false), + reqQueueLimit(_req_limit), respQueueLimit(_resp_limit), sendEvent(this) { } -Bridge::Bridge(const std::string &n, int qsa, int qsb, - Tick _delay, int write_ack, bool fix_partial_write_a, - bool fix_partial_write_b) - : MemObject(n), - portA(n + "-portA", this, &portB, _delay, qsa, fix_partial_write_a), - portB(n + "-portB", this, &portA, _delay, qsa, fix_partial_write_b), - ackWrites(write_ack) +Bridge::Bridge(Params *p) + : MemObject(p->name), + portA(p->name + "-portA", this, &portB, p->delay, p->nack_delay, + p->req_size_a, p->resp_size_a, p->fix_partial_write_a), + portB(p->name + "-portB", this, &portA, p->delay, p->nack_delay, + p->req_size_b, p->resp_size_b, p->fix_partial_write_b), + ackWrites(p->write_ack), _params(p) { if (ackWrites) panic("No support for acknowledging writes\n"); @@ -92,34 +93,105 @@ Bridge::init() fatal("Busses don't have the same block size... Not supported.\n"); } +bool +Bridge::BridgePort::respQueueFull() +{ + assert(outstandingResponses >= 0 && outstandingResponses <= respQueueLimit); + return outstandingResponses >= respQueueLimit; +} + +bool +Bridge::BridgePort::reqQueueFull() +{ + assert(queuedRequests >= 0 && queuedRequests <= reqQueueLimit); + return queuedRequests >= reqQueueLimit; +} /** Function called by the port when the bus is receiving a Timing * transaction.*/ bool Bridge::BridgePort::recvTiming(PacketPtr pkt) { - if (pkt->flags & SNOOP_COMMIT) { - DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + if (!(pkt->flags & SNOOP_COMMIT)) + return true; + + + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", pkt->getSrc(), pkt->getDest(), pkt->getAddr()); - return otherPort->queueForSendTiming(pkt); + if (pkt->isRequest() && otherPort->reqQueueFull()) { + DPRINTF(BusBridge, "Remote queue full, nacking\n"); + nackRequest(pkt); + return true; + } + + if (pkt->needsResponse() && pkt->result != Packet::Nacked) + 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); + nackRequest(pkt); + return true; + } else { + DPRINTF(BusBridge, "Request Needs response, reserving space\n"); + ++outstandingResponses; + } + + otherPort->queueForSendTiming(pkt); + + return true; +} + +void +Bridge::BridgePort::nackRequest(PacketPtr pkt) +{ + // Nack the packet + pkt->result = Packet::Nacked; + pkt->setDest(pkt->getSrc()); + + //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()) { + assert(!sendEvent.scheduled()); + sendEvent.schedule(readyTime); + sendQueue.push_back(buf); + return; + } + + assert(sendEvent.scheduled() || inRetry); + + // does it go at the end? + if (readyTime >= sendQueue.back()->ready) { + sendQueue.push_back(buf); + return; } - else { - // Else it's just a snoop, properly return if we are blocking - return !queueFull(); + + // 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(); + bool done = false; + + while (i != end && !done) { + if (readyTime < (*i)->ready) { + if (i == begin) + sendEvent.reschedule(readyTime); + sendQueue.insert(i,buf); + done = true; + } + i++; } + assert(done); } -bool +void Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) { - if (queueFull()) { - DPRINTF(BusBridge, "Queue full, returning false\n"); - return false; - } - - if (pkt->isResponse()) { + if (pkt->isResponse() || pkt->result == Packet::Nacked) { // This is a response for a request we forwarded earlier. The // corresponding PacketBuffer should be stored in the packet's // senderState field. @@ -128,6 +200,13 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) // set up new packet dest & senderState based on values saved // from original request buf->fixResponse(pkt); + + // Check if this packet was expecting a response (this is either it or + // its a nacked packet and we won't be seeing that response) + if (buf->expectResponse) + --outstandingResponses; + + DPRINTF(BusBridge, "restoring sender state: %#X, from packet buffer: %#X\n", pkt->senderState, buf); DPRINTF(BusBridge, " is response, new dest %d\n", pkt->getDest()); @@ -146,10 +225,8 @@ Bridge::BridgePort::queueForSendTiming(PacketPtr pkt) if (sendQueue.empty()) { sendEvent.schedule(readyTime); } - + ++queuedRequests; sendQueue.push_back(buf); - - return true; } void @@ -157,7 +234,6 @@ Bridge::BridgePort::trySend() { assert(!sendQueue.empty()); - bool was_full = queueFull(); int pbs = peerBlockSize(); PacketBuffer *buf = sendQueue.front(); @@ -169,7 +245,8 @@ Bridge::BridgePort::trySend() pkt->flags &= ~SNOOP_COMMIT; //CLear it if it was set if (pkt->cmd == MemCmd::WriteInvalidateReq && fixPartialWrite && - pkt->getOffset(pbs) && pkt->getSize() != pbs) { + pkt->result != Packet::Nacked && pkt->getOffset(pbs) && + pkt->getSize() != pbs) { buf->partialWriteFix(this); pkt = buf->pkt; } @@ -184,10 +261,7 @@ Bridge::BridgePort::trySend() buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it if (buf->expectResponse) { - // Must wait for response. We just need to count outstanding - // responses (in case we want to cap them); PacketBuffer - // pointer will be recovered on response. - ++outstandingResponses; + // Must wait for response DPRINTF(BusBridge, " successful: awaiting response (%d)\n", outstandingResponses); } else { @@ -196,28 +270,34 @@ Bridge::BridgePort::trySend() delete buf; } + if (!buf->nacked) + --queuedRequests; + // If there are more packets to send, schedule event to try again. if (!sendQueue.empty()) { buf = sendQueue.front(); + DPRINTF(BusBridge, "Scheduling next send\n"); sendEvent.schedule(std::max(buf->ready, curTick + 1)); } - // Let things start sending again - if (was_full) { - DPRINTF(BusBridge, "Queue was full, sending retry\n"); - otherPort->sendRetry(); - } - } else { DPRINTF(BusBridge, " unsuccessful\n"); buf->undoPartialWriteFix(); + inRetry = true; } + DPRINTF(BusBridge, "trySend: queue size: %d outreq: %d outstanding resp: %d\n", + sendQueue.size(), queuedRequests, outstandingResponses); } void Bridge::BridgePort::recvRetry() { - trySend(); + inRetry = false; + Tick nextReady = sendQueue.front()->ready; + if (nextReady <= curTick) + trySend(); + else + sendEvent.schedule(nextReady); } /** Function called by the port when the bus is receiving a Atomic @@ -263,9 +343,12 @@ Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) - Param<int> queue_size_a; - Param<int> queue_size_b; + Param<int> req_size_a; + Param<int> req_size_b; + Param<int> resp_size_a; + Param<int> resp_size_b; Param<Tick> delay; + Param<Tick> nack_delay; Param<bool> write_ack; Param<bool> fix_partial_write_a; Param<bool> fix_partial_write_b; @@ -274,9 +357,12 @@ END_DECLARE_SIM_OBJECT_PARAMS(Bridge) BEGIN_INIT_SIM_OBJECT_PARAMS(Bridge) - INIT_PARAM(queue_size_a, "The size of the queue for data coming into side a"), - INIT_PARAM(queue_size_b, "The size of the queue for data coming into side b"), + INIT_PARAM(req_size_a, "The size of the queue for requests coming into side a"), + INIT_PARAM(req_size_b, "The size of the queue for requests coming into side b"), + INIT_PARAM(resp_size_a, "The size of the queue for responses coming into side a"), + INIT_PARAM(resp_size_b, "The size of the queue for responses coming into side b"), INIT_PARAM(delay, "The miminum delay to cross this bridge"), + INIT_PARAM(nack_delay, "The minimum delay to nack a packet"), INIT_PARAM(write_ack, "Acknowledge any writes that are received."), INIT_PARAM(fix_partial_write_a, "Fixup any partial block writes that are received"), INIT_PARAM(fix_partial_write_b, "Fixup any partial block writes that are received") @@ -285,8 +371,19 @@ END_INIT_SIM_OBJECT_PARAMS(Bridge) CREATE_SIM_OBJECT(Bridge) { - return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, - write_ack, fix_partial_write_a, fix_partial_write_b); + Bridge::Params *p = new Bridge::Params; + p->name = getInstanceName(); + p->req_size_a = req_size_a; + p->req_size_b = req_size_b; + p->resp_size_a = resp_size_a; + p->resp_size_b = resp_size_b; + p->delay = delay; + p->nack_delay = nack_delay; + p->write_ack = write_ack; + p->fix_partial_write_a = fix_partial_write_a; + p->fix_partial_write_b = fix_partial_write_b; + return new Bridge(p); } REGISTER_SIM_OBJECT("Bridge", Bridge) + diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index d1154eda0..cb5a6baed 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -66,6 +66,9 @@ class Bridge : public MemObject /** Minimum delay though this bridge. */ Tick delay; + /** Min delay to respond to a nack. */ + Tick nackDelay; + bool fixPartialWrite; class PacketBuffer : public Packet::SenderState { @@ -79,13 +82,16 @@ class Bridge : public MemObject bool partialWriteFixed; PacketPtr oldPkt; + bool nacked; - PacketBuffer(PacketPtr _pkt, Tick t) + PacketBuffer(PacketPtr _pkt, Tick t, bool nack = false) : ready(t), pkt(_pkt), origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), - expectResponse(_pkt->needsResponse()), partialWriteFixed(false) + expectResponse(_pkt->needsResponse() && !nack), + partialWriteFixed(false), nacked(nack) + { - if (!pkt->isResponse()) + if (!pkt->isResponse() && !nack) pkt->senderState = this; } @@ -144,19 +150,29 @@ class Bridge : public MemObject std::list<PacketBuffer*> sendQueue; int outstandingResponses; + int queuedRequests; + + /** If we're waiting for a retry to happen.*/ + bool inRetry; /** Max queue size for outbound packets */ - int queueLimit; + int reqQueueLimit; + + /** Max queue size for reserved responses. */ + int respQueueLimit; /** * Is this side blocked from accepting outbound packets? */ - bool queueFull() { return (sendQueue.size() == queueLimit); } + bool respQueueFull(); + bool reqQueueFull(); - bool queueForSendTiming(PacketPtr pkt); + void queueForSendTiming(PacketPtr pkt); void finishSend(PacketBuffer *buf); + void nackRequest(PacketPtr pkt); + /** * Handle send event, scheduled when the packet at the head of * the outbound queue is ready to transmit (for timing @@ -180,11 +196,10 @@ class Bridge : public MemObject SendEvent sendEvent; public: - /** Constructor for the BusPort.*/ - BridgePort(const std::string &_name, - Bridge *_bridge, BridgePort *_otherPort, - int _delay, int _queueLimit, bool fix_partial_write); + BridgePort(const std::string &_name, Bridge *_bridge, + BridgePort *_otherPort, int _delay, int _nack_delay, + int _req_limit, int _resp_limit, bool fix_partial_write); protected: @@ -220,14 +235,32 @@ class Bridge : public MemObject bool ackWrites; public: + struct Params + { + std::string name; + int req_size_a; + int req_size_b; + int resp_size_a; + int resp_size_b; + Tick delay; + Tick nack_delay; + bool write_ack; + bool fix_partial_write_a; + bool fix_partial_write_b; + }; + + protected: + Params *_params; + + public: + const Params *params() const { return _params; } /** A function used to return the port associated with this bus object. */ virtual Port *getPort(const std::string &if_name, int idx = -1); virtual void init(); - Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack, - bool fix_partial_write_a, bool fix_partial_write_b); + Bridge(Params *p); }; #endif //__MEM_BUS_HH__ diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 6682ade55..95d4e2873 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -171,8 +171,9 @@ bool Bus::recvTiming(PacketPtr pkt) { Port *port; - DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", - pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s result %d\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString(), + pkt->result); BusPort *pktPort; if (pkt->getSrc() == defaultId) @@ -272,20 +273,14 @@ Bus::recvRetry(int id) retryList.pop_front(); inRetry = false; - if (id != -1) { - //Bring tickNextIdle up to the present - while (tickNextIdle < curTick) - tickNextIdle += clock; - - //Burn a cycle for the missed grant. + //Bring tickNextIdle up to the present + while (tickNextIdle < curTick) tickNextIdle += clock; - if (!busIdle.scheduled()) { - busIdle.schedule(tickNextIdle); - } else { - busIdle.reschedule(tickNextIdle); - } - } // id != -1 + //Burn a cycle for the missed grant. + tickNextIdle += clock; + + busIdle.reschedule(tickNextIdle, true); } } //If we weren't able to drain before, we might be able to now. diff --git a/src/mem/cache/cache_impl.hh b/src/mem/cache/cache_impl.hh index 0a528aa5d..c70f10151 100644 --- a/src/mem/cache/cache_impl.hh +++ b/src/mem/cache/cache_impl.hh @@ -1192,6 +1192,8 @@ template<class TagStore, class Coherence> bool Cache<TagStore,Coherence>::CpuSidePort::recvTiming(PacketPtr pkt) { + assert(pkt->result != Packet::Nacked); + if (!pkt->req->isUncacheable() && pkt->isInvalidate() && !pkt->isRead() && !pkt->isWrite()) { @@ -1249,6 +1251,12 @@ template<class TagStore, class Coherence> bool Cache<TagStore,Coherence>::MemSidePort::recvTiming(PacketPtr pkt) { + // this needs to be fixed so that the cache updates the mshr and sends the + // packet back out on the link, but it probably won't happen so until this + // gets fixed, just panic when it does + if (pkt->result == Packet::Nacked) + panic("Need to implement cache resending nacked packets!\n"); + if (pkt->isRequest() && blocked) { DPRINTF(Cache,"Scheduling a retry while blocked\n"); diff --git a/src/mem/tport.cc b/src/mem/tport.cc index b384a0444..9a4bd7967 100644 --- a/src/mem/tport.cc +++ b/src/mem/tport.cc @@ -128,6 +128,7 @@ SimpleTimingPort::sendTiming(PacketPtr pkt, Tick time) } i++; } + assert(done); } void diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc index d2c854086..54de6625e 100644 --- a/src/mem/translating_port.cc +++ b/src/mem/translating_port.cc @@ -34,12 +34,14 @@ #include "mem/port.hh" #include "mem/translating_port.hh" #include "mem/page_table.hh" +#include "sim/process.hh" using namespace TheISA; TranslatingPort::TranslatingPort(const std::string &_name, - PageTable *p_table, bool alloc) - : FunctionalPort(_name), pTable(p_table), allocating(alloc) + Process *p, AllocType alloc) + : FunctionalPort(_name), pTable(p->pTable), process(p), + allocating(alloc) { } TranslatingPort::~TranslatingPort() @@ -81,13 +83,18 @@ TranslatingPort::tryWriteBlob(Addr addr, uint8_t *p, int size) for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { if (!pTable->translate(gen.addr(), paddr)) { - if (allocating) { + if (allocating == Always) { pTable->allocate(roundDown(gen.addr(), VMPageSize), VMPageSize); - pTable->translate(gen.addr(), paddr); + } else if (allocating == NextPage) { + // check if we've accessed the next page on the stack + if (!process->checkAndAllocNextPage(gen.addr())) + panic("Page table fault when accessing virtual address %#x " + "during functional write\n", gen.addr()); } else { return false; } + pTable->translate(gen.addr(), paddr); } Port::writeBlob(paddr, p + prevSize, gen.size()); @@ -113,7 +120,7 @@ TranslatingPort::tryMemsetBlob(Addr addr, uint8_t val, int size) for (ChunkGenerator gen(addr, size, VMPageSize); !gen.done(); gen.next()) { if (!pTable->translate(gen.addr(), paddr)) { - if (allocating) { + if (allocating == Always) { pTable->allocate(roundDown(gen.addr(), VMPageSize), VMPageSize); pTable->translate(gen.addr(), paddr); diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh index 7354278ba..76c7947be 100644 --- a/src/mem/translating_port.hh +++ b/src/mem/translating_port.hh @@ -35,16 +35,25 @@ #include "mem/port.hh" class PageTable; +class Process; class TranslatingPort : public FunctionalPort { + public: + enum AllocType { + Always, + Never, + NextPage + }; + private: PageTable *pTable; - bool allocating; + Process *process; + AllocType allocating; public: TranslatingPort(const std::string &_name, - PageTable *p_table, bool alloc = false); + Process *p, AllocType alloc); virtual ~TranslatingPort(); bool tryReadBlob(Addr addr, uint8_t *p, int size); |