diff options
Diffstat (limited to 'src/mem')
-rw-r--r-- | src/mem/bridge.cc | 270 | ||||
-rw-r--r-- | src/mem/bridge.hh | 214 | ||||
-rw-r--r-- | src/mem/bus.cc | 60 | ||||
-rw-r--r-- | src/mem/bus.hh | 18 | ||||
-rw-r--r-- | src/mem/packet.cc | 50 | ||||
-rw-r--r-- | src/mem/packet.hh | 138 | ||||
-rw-r--r-- | src/mem/physical.cc | 30 | ||||
-rw-r--r-- | src/mem/physical.hh | 2 | ||||
-rw-r--r-- | src/mem/port.cc | 26 | ||||
-rw-r--r-- | src/mem/port.hh | 29 | ||||
-rw-r--r-- | src/mem/request.hh | 1 | ||||
-rw-r--r-- | src/mem/translating_port.cc | 5 | ||||
-rw-r--r-- | src/mem/translating_port.hh | 9 | ||||
-rw-r--r-- | src/mem/vport.hh | 4 |
14 files changed, 478 insertions, 378 deletions
diff --git a/src/mem/bridge.cc b/src/mem/bridge.cc index c4b137869..736e8dc81 100644 --- a/src/mem/bridge.cc +++ b/src/mem/bridge.cc @@ -31,209 +31,209 @@ * @file Definition of a simple bus bridge without buffering. */ +#include <algorithm> #include "base/trace.hh" #include "mem/bridge.hh" #include "sim/builder.hh" +Bridge::BridgePort::BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit) + : Port(_name), bridge(_bridge), otherPort(_otherPort), + delay(_delay), outstandingResponses(0), + queueLimit(_queueLimit), sendEvent(this) +{ +} + +Bridge::Bridge(const std::string &n, int qsa, int qsb, + Tick _delay, int write_ack) + : MemObject(n), + portA(n + "-portA", this, &portB, _delay, qsa), + portB(n + "-portB", this, &portA, _delay, qsa), + ackWrites(write_ack) +{ +} + +Port * +Bridge::getPort(const std::string &if_name) +{ + BridgePort *port; + + if (if_name == "side_a") + port = &portA; + else if (if_name == "side_b") + port = &portB; + else + return NULL; + + if (port->getPeer() != NULL) + panic("bridge side %s already connected to.", if_name); + return port; +} + + void Bridge::init() { // Make sure that both sides are connected to. - if (sideA == NULL || sideB == NULL) + if (portA.getPeer() == NULL || portB.getPeer() == NULL) panic("Both ports of bus bridge are not connected to a bus.\n"); } -/** Function called by the port when the bus is recieving a Timing +/** Function called by the port when the bus is receiving a Timing * transaction.*/ bool -Bridge::recvTiming(Packet *pkt, Side id) +Bridge::BridgePort::recvTiming(Packet *pkt) { - if (blockedA && id == SideA) - return false; - if (blockedB && id == SideB) - return false; - - if (delay) { - if (!sendEvent.scheduled()) - sendEvent.schedule(curTick + delay); - if (id == SideA) { - inboundA.push_back(std::make_pair<Packet*, Tick>(pkt, curTick)); - blockCheck(SideA); - } else { - inboundB.push_back(std::make_pair<Packet*, Tick>(pkt, curTick)); - blockCheck(SideB); - } - } else { - if (id == SideB) { - sideA->sendPkt(pkt); - blockCheck(SideB); - } else { - sideB->sendPkt(pkt); - blockCheck(SideA); - } + DPRINTF(BusBridge, "recvTiming: src %d dest %d addr 0x%x\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr()); + + 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, " is response, new dest %d\n", pkt->getDest()); + delete buf; } - return true; + return otherPort->queueForSendTiming(pkt); } -void -Bridge::blockCheck(Side id) -{ - /* Check that we still have buffer space available. */ - if (id == SideB) { - if (sideA->numQueued() + inboundB.size() >= queueSizeA && !blockedB) { - sideB->sendStatusChange(Port::Blocked); - blockedB = true; - } else if (sideA->numQueued() + inboundB.size() < queueSizeA && blockedB) { - sideB->sendStatusChange(Port::Unblocked); - blockedB = false; - } - } else { - if (sideB->numQueued() + inboundA.size() >= queueSizeB && !blockedA) { - sideA->sendStatusChange(Port::Blocked); - blockedA = true; - } else if (sideB->numQueued() + inboundA.size() < queueSizeB && blockedA) { - sideA->sendStatusChange(Port::Unblocked); - blockedA = false; - } - } -} -void Bridge::timerEvent() +bool +Bridge::BridgePort::queueForSendTiming(Packet *pkt) { - Tick t = 0; + if (queueFull()) + return false; - assert(inboundA.size() || inboundB.size()); - if (inboundA.size()) { - while (inboundA.front().second <= curTick + delay){ - sideB->sendPkt(inboundA.front()); - inboundA.pop_front(); - } - if (inboundA.size()) - t = inboundA.front().second + delay; - } - if (inboundB.size()) { - while (inboundB.front().second <= curTick + delay){ - sideB->sendPkt(inboundA.front()); - inboundB.pop_front(); - } - if (inboundB.size()) - if (t == 0) - t = inboundB.front().second + delay; - else - t = std::min(t,inboundB.front().second + delay); - } else { - panic("timerEvent() called but nothing to do?"); + 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 (sendQueue.empty()) { + sendEvent.schedule(readyTime); } - if (t != 0) - sendEvent.schedule(t); + sendQueue.push_back(buf); + + // Did we just become blocked? If yes, let other side know. + if (queueFull()) + otherPort->sendStatusChange(Port::Blocked); + + return true; } void -Bridge::BridgePort::sendPkt(Packet *pkt) +Bridge::BridgePort::finishSend(PacketBuffer *buf) { - if (!sendTiming(pkt)) - outbound.push_back(std::make_pair<Packet*,Tick>(pkt, curTick)); + if (buf->expectResponse) { + // Must wait for response. We just need to count outstanding + // responses (in case we want to cap them); PacketBuffer + // pointer will be recovered on response. + ++outstandingResponses; + DPRINTF(BusBridge, " successful: awaiting response (%d)\n", + outstandingResponses); + } else { + // no response expected... deallocate packet buffer now. + DPRINTF(BusBridge, " successful: no response expected\n"); + delete buf; + } + + // If there are more packets to send, schedule event to try again. + if (!sendQueue.empty()) { + buf = sendQueue.front(); + sendEvent.schedule(std::max(buf->ready, curTick + 1)); + } } + void -Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p) +Bridge::BridgePort::trySend() { - if (!sendTiming(p.first)) - outbound.push_back(p); + assert(!sendQueue.empty()); + + PacketBuffer *buf = sendQueue.front(); + + assert(buf->ready <= curTick); + + Packet *pkt = buf->pkt; + + DPRINTF(BusBridge, "trySend: origSrc %d dest %d addr 0x%x\n", + buf->origSrc, pkt->getDest(), pkt->getAddr()); + + if (sendTiming(pkt)) { + // send successful + sendQueue.pop_front(); + buf->pkt = NULL; // we no longer own packet, so it's not safe to look at it + finishSend(buf); + } else { + DPRINTF(BusBridge, " unsuccessful\n"); + } } Packet * Bridge::BridgePort::recvRetry() { - Packet *pkt; - assert(outbound.size() > 0); - assert(outbound.front().second >= curTick + bridge->delay); - pkt = outbound.front().first; - outbound.pop_front(); - bridge->blockCheck(side); + PacketBuffer *buf = sendQueue.front(); + Packet *pkt = buf->pkt; + finishSend(buf); return pkt; } -/** Function called by the port when the bus is recieving a Atomic +/** Function called by the port when the bus is receiving a Atomic * transaction.*/ Tick -Bridge::recvAtomic(Packet *pkt, Side id) +Bridge::BridgePort::recvAtomic(Packet *pkt) { - pkt->time += delay; - - if (id == SideA) - return sideB->sendAtomic(pkt); - else - return sideA->sendAtomic(pkt); + return otherPort->sendAtomic(pkt) + delay; } -/** Function called by the port when the bus is recieving a Functional +/** Function called by the port when the bus is receiving a Functional * transaction.*/ void -Bridge::recvFunctional(Packet *pkt, Side id) +Bridge::BridgePort::recvFunctional(Packet *pkt) { - pkt->time += delay; - std::list<std::pair<Packet*, Tick> >::iterator i; + std::list<PacketBuffer*>::iterator i; bool pktContinue = true; - for(i = inboundA.begin(); i != inboundA.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = inboundB.begin(); i != inboundB.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = sideA->outbound.begin(); i != sideA->outbound.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); - } - } - - for(i = sideB->outbound.begin(); i != sideB->outbound.end(); ++i) { - if (pkt->intersect(i->first)) { - pktContinue &= fixPacket(pkt, i->first); + for (i = sendQueue.begin(); i != sendQueue.end(); ++i) { + if (pkt->intersect((*i)->pkt)) { + pktContinue &= fixPacket(pkt, (*i)->pkt); } } if (pktContinue) { - if (id == SideA) - sideB->sendFunctional(pkt); - else - sideA->sendFunctional(pkt); + otherPort->sendFunctional(pkt); } } -/** Function called by the port when the bus is recieving a status change.*/ +/** Function called by the port when the bus is receiving a status change.*/ void -Bridge::recvStatusChange(Port::Status status, Side id) +Bridge::BridgePort::recvStatusChange(Port::Status status) { if (status == Port::Blocked || status == Port::Unblocked) - return ; + return; - if (id == SideA) - sideB->sendStatusChange(status); - else - sideA->sendStatusChange(status); + otherPort->sendStatusChange(status); } void -Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id) +Bridge::BridgePort::getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop) { - if (id == SideA) - sideB->getPeerAddressRanges(resp, snoop); - else - sideA->getPeerAddressRanges(resp, snoop); + otherPort->getPeerAddressRanges(resp, snoop); } BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) diff --git a/src/mem/bridge.hh b/src/mem/bridge.hh index 5f19ded40..8a5cbf92a 100644 --- a/src/mem/bridge.hh +++ b/src/mem/bridge.hh @@ -46,132 +46,127 @@ class Bridge : public MemObject { - public: - enum Side + protected: + /** Decleration of the buses port type, one will be instantiated for each + of the interfaces connecting to the bus. */ + class BridgePort : public Port { - SideA, - SideB - }; + /** A pointer to the bridge to which this port belongs. */ + Bridge *bridge; - protected: - /** Function called by the port when the bus is recieving a Timing - transaction.*/ - bool recvTiming(Packet *pkt, Side id); + /** + * Pointer to the port on the other side of the bridge + * (connected to the other bus). + */ + BridgePort *otherPort; - /** Function called by the port when the bus is recieving a Atomic - transaction.*/ - Tick recvAtomic(Packet *pkt, Side id); + /** Minimum delay though this bridge. */ + Tick delay; - /** Function called by the port when the bus is recieving a Functional - transaction.*/ - void recvFunctional(Packet *pkt, Side id); + class PacketBuffer : public Packet::SenderState { - /** Function called by the port when the bus is recieving a status change.*/ - void recvStatusChange(Port::Status status, Side id); + public: + Tick ready; + Packet *pkt; + Packet::SenderState *origSenderState; + short origSrc; + bool expectResponse; - /** Process address range request. - * @param resp addresses that we can respond to - * @param snoop addresses that we would like to snoop - * @param id ide of the busport that made the request. - */ - void addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id); + PacketBuffer(Packet *_pkt, Tick t) + : ready(t), pkt(_pkt), + origSenderState(_pkt->senderState), origSrc(_pkt->getSrc()), + expectResponse(_pkt->needsResponse()) + { + pkt->senderState = this; + } + void fixResponse(Packet *pkt) + { + assert(pkt->senderState == this); + pkt->setDest(origSrc); + pkt->senderState = origSenderState; + } + }; - /** Event that the SendEvent calls when it fires. This code must reschedule - * the send event as required. */ - void timerEvent(); + /** + * Outbound packet queue. Packets are held in this queue for a + * specified delay to model the processing delay of the + * bridge. + */ + std::list<PacketBuffer*> sendQueue; - /** Decleration of the buses port type, one will be instantiated for each - of the interfaces connecting to the bus. */ - class BridgePort : public Port - { - /** A pointer to the bus to which this port belongs. */ - Bridge *bridge; + int outstandingResponses; + + /** Max queue size for outbound packets */ + int queueLimit; + + /** + * Is this side blocked from accepting outbound packets? + */ + bool queueFull() { return (sendQueue.size() == queueLimit); } + + bool queueForSendTiming(Packet *pkt); + + void finishSend(PacketBuffer *buf); + + /** + * Handle send event, scheduled when the packet at the head of + * the outbound queue is ready to transmit (for timing + * accesses only). + */ + void trySend(); + + class SendEvent : public Event + { + BridgePort *port; + + public: + SendEvent(BridgePort *p) + : Event(&mainEventQueue), port(p) {} + + virtual void process() { port->trySend(); } - /** A id to keep track of the intercafe ID this port is connected to. */ - Bridge::Side side; + virtual const char *description() { return "bridge send event"; } + }; + + SendEvent sendEvent; public: /** Constructor for the BusPort.*/ - BridgePort(Bridge *_bridge, Side _side) - : bridge(_bridge), side(_side) - { } - - int numQueued() { return outbound.size(); } + BridgePort(const std::string &_name, + Bridge *_bridge, BridgePort *_otherPort, + int _delay, int _queueLimit); protected: - /** Data this is waiting to be transmitted. */ - std::list<std::pair<Packet*, Tick> > outbound; - - void sendPkt(Packet *pkt); - void sendPkt(std::pair<Packet*, Tick> p); - /** When reciving a timing request from the peer port, + /** When receiving a timing request from the peer port, pass it to the bridge. */ - virtual bool recvTiming(Packet *pkt) - { return bridge->recvTiming(pkt, side); } + virtual bool recvTiming(Packet *pkt); - /** When reciving a retry request from the peer port, + /** When receiving a retry request from the peer port, pass it to the bridge. */ virtual Packet* recvRetry(); - /** When reciving a Atomic requestfrom the peer port, + /** When receiving a Atomic requestfrom the peer port, pass it to the bridge. */ - virtual Tick recvAtomic(Packet *pkt) - { return bridge->recvAtomic(pkt, side); } + virtual Tick recvAtomic(Packet *pkt); - /** When reciving a Functional request from the peer port, + /** When receiving a Functional request from the peer port, pass it to the bridge. */ - virtual void recvFunctional(Packet *pkt) - { bridge->recvFunctional(pkt, side); } + virtual void recvFunctional(Packet *pkt); - /** When reciving a status changefrom the peer port, + /** When receiving a status changefrom the peer port, pass it to the bridge. */ - virtual void recvStatusChange(Status status) - { bridge->recvStatusChange(status, side); } + virtual void recvStatusChange(Status status); - /** When reciving a address range request the peer port, + /** When receiving a address range request the peer port, pass it to the bridge. */ - virtual void getDeviceAddressRanges(AddrRangeList &resp, AddrRangeList &snoop) - { bridge->addressRanges(resp, snoop, side); } - - friend class Bridge; - }; - - class SendEvent : public Event - { - Bridge *bridge; - - SendEvent(Bridge *b) - : Event(&mainEventQueue), bridge(b) {} - - virtual void process() { bridge->timerEvent(); } - - virtual const char *description() { return "bridge delay event"; } - friend class Bridge; + virtual void getDeviceAddressRanges(AddrRangeList &resp, + AddrRangeList &snoop); }; - SendEvent sendEvent; - - /** Sides of the bus bridges. */ - BridgePort* sideA; - BridgePort* sideB; - - /** inbound queues on both sides. */ - std::list<std::pair<Packet*, Tick> > inboundA; - std::list<std::pair<Packet*, Tick> > inboundB; - - /** The size of the queue for data coming into side a */ - int queueSizeA; - int queueSizeB; - - /* if the side is blocked or not. */ - bool blockedA; - bool blockedB; - - /** Miminum delay though this bridge. */ - Tick delay; + BridgePort portA, portB; /** If this bridge should acknowledge writes. */ bool ackWrites; @@ -179,36 +174,11 @@ class Bridge : public MemObject public: /** A function used to return the port associated with this bus object. */ - virtual Port *getPort(const std::string &if_name) - { - if (if_name == "side_a") { - if (sideA != NULL) - panic("bridge side a already connected to."); - sideA = new BridgePort(this, SideA); - return sideA; - } else if (if_name == "side_b") { - if (sideB != NULL) - panic("bridge side b already connected to."); - sideB = new BridgePort(this, SideB); - return sideB; - } else - return NULL; - } + virtual Port *getPort(const std::string &if_name); virtual void init(); - Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack) - : MemObject(n), sendEvent(this), sideA(NULL), sideB(NULL), - queueSizeA(qsa), queueSizeB(qsb), blockedA(false), blockedB(false), - delay(_delay), ackWrites(write_ack) - {} - - /** Check if the port should block/unblock after recieving/sending a packet. - * */ - void blockCheck(Side id); - - friend class Bridge::SendEvent; - + Bridge(const std::string &n, int qsa, int qsb, Tick _delay, int write_ack); }; #endif //__MEM_BUS_HH__ diff --git a/src/mem/bus.cc b/src/mem/bus.cc index f7c2b874a..cfc99a64f 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -35,6 +35,16 @@ #include "mem/bus.hh" #include "sim/builder.hh" +Port * +Bus::getPort(const std::string &if_name) +{ + // if_name ignored? forced to be empty? + int id = interfaces.size(); + BusPort *bp = new BusPort(csprintf("%s-p%d", name(), id), this, id); + interfaces.push_back(bp); + return bp; +} + /** Get the ranges of anyone that we are connected to. */ void Bus::init() @@ -45,17 +55,22 @@ Bus::init() } -/** Function called by the port when the bus is recieving a Timing +/** Function called by the port when the bus is receiving a Timing * transaction.*/ bool Bus::recvTiming(Packet *pkt) { Port *port; - if (pkt->dest == Packet::Broadcast) { - port = findPort(pkt->addr, pkt->src); + DPRINTF(Bus, "recvTiming: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + + short dest = pkt->getDest(); + if (dest == Packet::Broadcast) { + port = findPort(pkt->getAddr(), pkt->getSrc()); } else { - assert(pkt->dest > 0 && pkt->dest < interfaces.size()); - port = interfaces[pkt->dest]; + assert(dest >= 0 && dest < interfaces.size()); + assert(dest != pkt->getSrc()); // catch infinite loops + port = interfaces[dest]; } return port->sendTiming(pkt); } @@ -73,7 +88,7 @@ Bus::findPort(Addr addr, int id) if (portList[i].range == addr) { dest_id = portList[i].portId; found = true; - DPRINTF(Bus, "Found Addr: %llx on device %d\n", addr, dest_id); + DPRINTF(Bus, " found addr 0x%llx on device %d\n", addr, dest_id); } i++; } @@ -86,33 +101,37 @@ Bus::findPort(Addr addr, int id) return interfaces[dest_id]; } -/** Function called by the port when the bus is recieving a Atomic +/** Function called by the port when the bus is receiving a Atomic * transaction.*/ Tick Bus::recvAtomic(Packet *pkt) { - assert(pkt->dest == Packet::Broadcast); - return findPort(pkt->addr, pkt->src)->sendAtomic(pkt); + DPRINTF(Bus, "recvAtomic: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + return findPort(pkt->getAddr(), pkt->getSrc())->sendAtomic(pkt); } -/** Function called by the port when the bus is recieving a Functional +/** Function called by the port when the bus is receiving a Functional * transaction.*/ void Bus::recvFunctional(Packet *pkt) { - assert(pkt->dest == Packet::Broadcast); - findPort(pkt->addr, pkt->src)->sendFunctional(pkt); + DPRINTF(Bus, "recvFunctional: packet src %d dest %d addr 0x%x cmd %s\n", + pkt->getSrc(), pkt->getDest(), pkt->getAddr(), pkt->cmdString()); + assert(pkt->getDest() == Packet::Broadcast); + findPort(pkt->getAddr(), pkt->getSrc())->sendFunctional(pkt); } -/** Function called by the port when the bus is recieving a status change.*/ +/** Function called by the port when the bus is receiving a status change.*/ void Bus::recvStatusChange(Port::Status status, int id) { - DPRINTF(Bus, "Bus %d recieved status change from device id %d\n", - busId, id); assert(status == Port::RangeChange && "The other statuses need to be implemented."); + DPRINTF(BusAddrRanges, "received RangeChange from device id %d\n", id); + assert(id < interfaces.size() && id >= 0); int x; Port *port = interfaces[id]; @@ -138,8 +157,8 @@ Bus::recvStatusChange(Port::Status status, int id) dm.portId = id; dm.range = *iter; - DPRINTF(MMU, "Adding range %llx - %llx for id %d\n", dm.range.start, - dm.range.end, id); + DPRINTF(BusAddrRanges, "Adding range %llx - %llx for id %d\n", + dm.range.start, dm.range.end, id); portList.push_back(dm); } DPRINTF(MMU, "port list has %d entries\n", portList.size()); @@ -159,13 +178,12 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) resp.clear(); snoop.clear(); - DPRINTF(Bus, "Bus id %d recieved address range request returning\n", - busId); + DPRINTF(BusAddrRanges, "received address range request, returning:\n"); for (portIter = portList.begin(); portIter != portList.end(); portIter++) { if (portIter->portId != id) { resp.push_back(portIter->range); - DPRINTF(Bus, "-- %#llX : %#llX\n", portIter->range.start, - portIter->range.end); + DPRINTF(BusAddrRanges, " -- %#llX : %#llX\n", + portIter->range.start, portIter->range.end); } } } diff --git a/src/mem/bus.hh b/src/mem/bus.hh index 38573e514..5eeb07904 100644 --- a/src/mem/bus.hh +++ b/src/mem/bus.hh @@ -100,8 +100,8 @@ class Bus : public MemObject public: /** Constructor for the BusPort.*/ - BusPort(Bus *_bus, int _id) - : bus(_bus), id(_id) + BusPort(const std::string &_name, Bus *_bus, int _id) + : Port(_name), bus(_bus), id(_id) { } protected: @@ -109,17 +109,17 @@ class Bus : public MemObject /** When reciving a timing request from the peer port (at id), pass it to the bus. */ virtual bool recvTiming(Packet *pkt) - { pkt->src = id; return bus->recvTiming(pkt); } + { pkt->setSrc(id); return bus->recvTiming(pkt); } /** When reciving a Atomic requestfrom the peer port (at id), pass it to the bus. */ virtual Tick recvAtomic(Packet *pkt) - { pkt->src = id; return bus->recvAtomic(pkt); } + { pkt->setSrc(id); return bus->recvAtomic(pkt); } /** When reciving a Functional requestfrom the peer port (at id), pass it to the bus. */ virtual void recvFunctional(Packet *pkt) - { pkt->src = id; bus->recvFunctional(pkt); } + { pkt->setSrc(id); bus->recvFunctional(pkt); } /** When reciving a status changefrom the peer port (at id), pass it to the bus. */ @@ -146,13 +146,7 @@ class Bus : public MemObject public: /** A function used to return the port associated with this bus object. */ - virtual Port *getPort(const std::string &if_name) - { - // if_name ignored? forced to be empty? - int id = interfaces.size(); - interfaces.push_back(new BusPort(this, id)); - return interfaces.back(); - } + virtual Port *getPort(const std::string &if_name); virtual void init(); diff --git a/src/mem/packet.cc b/src/mem/packet.cc index a9be7ac51..3b415d77f 100644 --- a/src/mem/packet.cc +++ b/src/mem/packet.cc @@ -34,11 +34,31 @@ #include "base/misc.hh" #include "mem/packet.hh" +static const std::string ReadReqString("ReadReq"); +static const std::string WriteReqString("WriteReq"); +static const std::string WriteReqNoAckString("WriteReqNoAck"); +static const std::string ReadRespString("ReadResp"); +static const std::string WriteRespString("WriteResp"); +static const std::string OtherCmdString("<other>"); + +const std::string & +Packet::cmdString() const +{ + switch (cmd) { + case ReadReq: return ReadReqString; + case WriteReq: return WriteReqString; + case WriteReqNoAck: return WriteReqNoAckString; + case ReadResp: return ReadRespString; + case WriteResp: return WriteRespString; + default: return OtherCmdString; + } +} /** delete the data pointed to in the data pointer. Ok to call to matter how * data was allocted. */ void -Packet::deleteData() { +Packet::deleteData() +{ assert(staticData || dynamicData); if (staticData) return; @@ -51,22 +71,24 @@ Packet::deleteData() { /** If there isn't data in the packet, allocate some. */ void -Packet::allocate() { +Packet::allocate() +{ if (data) return; assert(!staticData); dynamicData = true; arrayData = true; - data = new uint8_t[size]; + data = new uint8_t[getSize()]; } /** Do the packet modify the same addresses. */ bool -Packet::intersect(Packet *p) { - Addr s1 = addr; - Addr e1 = addr + size; - Addr s2 = p->addr; - Addr e2 = p->addr + p->size; +Packet::intersect(Packet *p) +{ + Addr s1 = getAddr(); + Addr e1 = getAddr() + getSize(); + Addr s2 = p->getAddr(); + Addr e2 = p->getAddr() + p->getSize(); if (s1 >= s2 && s1 < e2) return true; @@ -77,7 +99,8 @@ Packet::intersect(Packet *p) { /** Minimally reset a packet so something like simple cpu can reuse it. */ void -Packet::reset() { +Packet::reset() +{ result = Unknown; if (dynamicData) { deleteData(); @@ -88,7 +111,8 @@ Packet::reset() { } - - -bool fixPacket(Packet *func, Packet *timing) -{ panic("Need to implement!"); } +bool +fixPacket(Packet *func, Packet *timing) +{ + panic("Need to implement!"); +} diff --git a/src/mem/packet.hh b/src/mem/packet.hh index e8a7b0c73..83f52ede5 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -43,24 +43,6 @@ struct Packet; typedef Packet* PacketPtr; typedef uint8_t* PacketDataPtr; -/** List of all commands associated with a packet. */ -enum Command -{ - Read, - Write -}; - -/** The result of a particular pakets request. */ -enum PacketResult -{ - Success, - BadAddress, - Unknown -}; - -class SenderState{}; -class Coherence{}; - /** * A Packet is the structure to handle requests between two levels * of the memory system. The Request is a global object that trancends @@ -74,7 +56,7 @@ class Coherence{}; * Packets are assumed to be returned in the case of a single response. If * the transaction has no response, then the consumer will delete the packet. */ -struct Packet +class Packet { private: /** A pointer to the data being transfered. It can be differnt sizes @@ -95,57 +77,132 @@ struct Packet bool arrayData; - public: /** The address of the request, could be virtual or physical (depending on cache configurations). */ Addr addr; - /** Flag structure to hold flags for this particular packet */ - uint64_t flags; + /** Indicates the size of the request. */ + int size; + + /** A index of the source of the transaction. */ + short src; + + /** A index to the destination of the transaction. */ + short dest; + + bool addrValid; + bool sizeValid; + bool srcValid; + + public: + + static const short Broadcast = -1; /** A pointer to the overall request. */ RequestPtr req; + class CoherenceState { + public: + virtual ~CoherenceState() {} + }; + /** A virtual base opaque structure used to hold coherence status messages. */ - Coherence *coherence; // virtual base opaque, + CoherenceState *coherence; // virtual base opaque, // assert(dynamic_cast<Foo>) etc. - /** A virtual base opaque structure used to hold the senders state. */ - void *senderState; // virtual base opaque, - // assert(dynamic_cast<Foo>) etc. - - /** Indicates the size of the request. */ - int size; + class SenderState { + public: + virtual ~SenderState() {} + }; - /** A index of the source of the transaction. */ - short src; + /** A virtual base opaque structure used to hold the senders state. */ + SenderState *senderState; // virtual base opaque, + // assert(dynamic_cast<Foo>) etc. - static const short Broadcast = -1; + private: + /** List of command attributes. */ + enum CommandAttribute + { + IsRead = 1 << 0, + IsWrite = 1 << 1, + IsPrefetch = 1 << 2, + IsInvalidate = 1 << 3, + IsRequest = 1 << 4, + IsResponse = 1 << 5, + NeedsResponse = 1 << 6, + }; - /** A index to the destination of the transaction. */ - short dest; + public: + /** List of all commands associated with a packet. */ + enum Command + { + ReadReq = IsRead | IsRequest | NeedsResponse, + WriteReq = IsWrite | IsRequest | NeedsResponse, + WriteReqNoAck = IsWrite | IsRequest, + ReadResp = IsRead | IsResponse, + WriteResp = IsWrite | IsResponse + }; + + const std::string &cmdString() const; /** The command of the transaction. */ Command cmd; + bool isRead() { return (cmd & IsRead) != 0; } + bool isRequest() { return (cmd & IsRequest) != 0; } + bool isResponse() { return (cmd & IsResponse) != 0; } + bool needsResponse() { return (cmd & NeedsResponse) != 0; } + + void makeTimingResponse() { + assert(needsResponse()); + int icmd = (int)cmd; + icmd &= ~(IsRequest | NeedsResponse); + icmd |= IsResponse; + cmd = (Command)icmd; + dest = src; + srcValid = false; + } + /** The time this request was responded to. Used to calculate latencies. */ Tick time; + /** The result of a particular packets request. */ + enum Result + { + Success, + BadAddress, + Unknown + }; + /** The result of the packet transaction. */ - PacketResult result; + Result result; /** Accessor function that returns the source index of the packet. */ - short getSrc() const { return src; } + short getSrc() const { assert(srcValid); return src; } + void setSrc(short _src) { src = _src; srcValid = true; } /** Accessor function that returns the destination index of the packet. */ short getDest() const { return dest; } + void setDest(short _dest) { dest = _dest; } + + Addr getAddr() const { assert(addrValid); return addr; } + void setAddr(Addr _addr) { addr = _addr; addrValid = true; } + + int getSize() const { assert(sizeValid); return size; } + void setSize(int _size) { size = _size; sizeValid = true; } - Packet() + + Packet(Request *_req, Command _cmd, short _dest) : data(NULL), staticData(false), dynamicData(false), arrayData(false), + addr(_req->paddr), size(_req->size), dest(_dest), + addrValid(_req->validPaddr), sizeValid(_req->validSize), + srcValid(false), + req(_req), coherence(NULL), senderState(NULL), cmd(_cmd), time(curTick), result(Unknown) - {} + { + } ~Packet() { deleteData(); } @@ -154,6 +211,11 @@ struct Packet /** Minimally reset a packet so something like simple cpu can reuse it. */ void reset(); + void reinitFromRequest() { + if (req->validPaddr) setAddr(req->paddr); + if (req->validSize) setSize(req->size); + } + /** Set the data pointer to the following value that should not be freed. */ template <typename T> void dataStatic(T *p); diff --git a/src/mem/physical.cc b/src/mem/physical.cc index bc2500678..26dbef0cd 100644 --- a/src/mem/physical.cc +++ b/src/mem/physical.cc @@ -127,7 +127,8 @@ PhysicalMemory::doTimingAccess (Packet *pkt, MemoryPort* memoryPort) { doFunctionalAccess(pkt); - pkt->dest = pkt->src; + // turn packet around to go back to requester + pkt->makeTimingResponse(); MemResponseEvent* response = new MemResponseEvent(pkt, memoryPort); response->schedule(curTick + lat); @@ -145,16 +146,18 @@ PhysicalMemory::doAtomicAccess(Packet *pkt) void PhysicalMemory::doFunctionalAccess(Packet *pkt) { - assert(pkt->addr + pkt->size < pmem_size); + assert(pkt->getAddr() + pkt->getSize() < pmem_size); switch (pkt->cmd) { - case Read: - memcpy(pkt->getPtr<uint8_t>(), pmem_addr + pkt->addr - base_addr, - pkt->size); + case Packet::ReadReq: + memcpy(pkt->getPtr<uint8_t>(), + pmem_addr + pkt->getAddr() - base_addr, + pkt->getSize()); break; - case Write: - memcpy(pmem_addr + pkt->addr - base_addr, pkt->getPtr<uint8_t>(), - pkt->size); + case Packet::WriteReq: + memcpy(pmem_addr + pkt->getAddr() - base_addr, + pkt->getPtr<uint8_t>(), + pkt->getSize()); // temporary hack: will need to add real LL/SC implementation // for cacheless systems later. if (pkt->req->getFlags() & LOCKED) { @@ -165,7 +168,7 @@ PhysicalMemory::doFunctionalAccess(Packet *pkt) panic("unimplemented"); } - pkt->result = Success; + pkt->result = Packet::Success; } Port * @@ -174,11 +177,11 @@ PhysicalMemory::getPort(const std::string &if_name) if (if_name == "") { if (port != NULL) panic("PhysicalMemory::getPort: additional port requested to memory!"); - port = new MemoryPort(this); + port = new MemoryPort(name() + "-port", this); return port; } else if (if_name == "functional") { /* special port for functional writes at startup. */ - return new MemoryPort(this); + return new MemoryPort(name() + "-funcport", this); } else { panic("PhysicalMemory::getPort: unknown port %s requested", if_name); } @@ -189,8 +192,9 @@ PhysicalMemory::recvStatusChange(Port::Status status) { } -PhysicalMemory::MemoryPort::MemoryPort(PhysicalMemory *_memory) - : memory(_memory) +PhysicalMemory::MemoryPort::MemoryPort(const std::string &_name, + PhysicalMemory *_memory) + : Port(_name), memory(_memory) { } void diff --git a/src/mem/physical.hh b/src/mem/physical.hh index 1cf5444ab..2ced79045 100644 --- a/src/mem/physical.hh +++ b/src/mem/physical.hh @@ -51,7 +51,7 @@ class PhysicalMemory : public MemObject public: - MemoryPort(PhysicalMemory *_memory); + MemoryPort(const std::string &_name, PhysicalMemory *_memory); protected: diff --git a/src/mem/port.cc b/src/mem/port.cc index fb3103ed1..651cb739a 100644 --- a/src/mem/port.cc +++ b/src/mem/port.cc @@ -31,22 +31,28 @@ */ #include "base/chunk_generator.hh" +#include "base/trace.hh" #include "mem/packet_impl.hh" #include "mem/port.hh" void -Port::blobHelper(Addr addr, uint8_t *p, int size, Command cmd) +Port::setPeer(Port *port) +{ + DPRINTF(Config, "setting peer to %s\n", port->name()); + peer = port; +} + +void +Port::blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd) { Request req(false); - Packet pkt; - pkt.req = &req; - pkt.cmd = cmd; - pkt.dest = Packet::Broadcast; + Packet pkt(&req, cmd, Packet::Broadcast); for (ChunkGenerator gen(addr, size, peerBlockSize()); !gen.done(); gen.next()) { - req.setPaddr(pkt.addr = gen.addr()); - req.setSize(pkt.size = gen.size()); + req.setPaddr(gen.addr()); + req.setSize(gen.size()); + pkt.reinitFromRequest(); pkt.dataStatic(p); sendFunctional(&pkt); p += gen.size(); @@ -56,13 +62,13 @@ Port::blobHelper(Addr addr, uint8_t *p, int size, Command cmd) void Port::writeBlob(Addr addr, uint8_t *p, int size) { - blobHelper(addr, p, size, Write); + blobHelper(addr, p, size, Packet::WriteReq); } void Port::readBlob(Addr addr, uint8_t *p, int size) { - blobHelper(addr, p, size, Read); + blobHelper(addr, p, size, Packet::ReadReq); } void @@ -72,7 +78,7 @@ Port::memsetBlob(Addr addr, uint8_t val, int size) uint8_t *buf = new uint8_t[size]; memset(buf, val, size); - blobHelper(addr, buf, size, Write); + blobHelper(addr, buf, size, Packet::WriteReq); delete [] buf; } diff --git a/src/mem/port.hh b/src/mem/port.hh index 1b1920c03..f9103865e 100644 --- a/src/mem/port.hh +++ b/src/mem/port.hh @@ -69,9 +69,28 @@ typedef std::list<Range<Addr> >::iterator AddrRangeIter; */ class Port { + private: + + /** Descriptive name (for DPRINTF output) */ + const std::string portName; + public: + /** + * Constructor. + * + * @param _name Port name for DPRINTF output. Should include name + * of memory system object to which the port belongs. + */ + Port(const std::string &_name) + : portName(_name) + { } + + /** Return port name (for DPRINTF). */ + const std::string &name() const { return portName; } + virtual ~Port() {}; + // mey be better to use subclasses & RTTI? /** Holds the ports status. Keeps track if it is blocked, or has calculated a range change. */ @@ -93,9 +112,9 @@ class Port /** Function to set the pointer for the peer port. @todo should be called by the configuration stuff (python). */ - void setPeer(Port *port) { peer = port; } + void setPeer(Port *port); - /** Function to set the pointer for the peer port. + /** Function to set the pointer for the peer port. @todo should be called by the configuration stuff (python). */ Port *getPeer() { return peer; } @@ -213,7 +232,7 @@ class Port /** Internal helper function for read/writeBlob(). */ - void blobHelper(Addr addr, uint8_t *p, int size, Command cmd); + void blobHelper(Addr addr, uint8_t *p, int size, Packet::Command cmd); }; /** A simple functional port that is only meant for one way communication to @@ -224,6 +243,10 @@ class Port class FunctionalPort : public Port { public: + FunctionalPort(const std::string &_name) + : Port(_name) + {} + virtual bool recvTiming(Packet *pkt) { panic("FuncPort is UniDir"); } virtual Tick recvAtomic(Packet *pkt) { panic("FuncPort is UniDir"); } virtual void recvFunctional(Packet *pkt) { panic("FuncPort is UniDir"); } diff --git a/src/mem/request.hh b/src/mem/request.hh index 2db7b7779..10550e859 100644 --- a/src/mem/request.hh +++ b/src/mem/request.hh @@ -195,6 +195,7 @@ class Request /** Accesor function for pc.*/ void setPC(Addr _pc); + friend class Packet; }; #endif // __MEM_REQUEST_HH__ diff --git a/src/mem/translating_port.cc b/src/mem/translating_port.cc index 5dfeaff31..ee4d277b6 100644 --- a/src/mem/translating_port.cc +++ b/src/mem/translating_port.cc @@ -34,8 +34,9 @@ using namespace TheISA; -TranslatingPort::TranslatingPort(PageTable *p_table, bool alloc) - : pTable(p_table), allocating(alloc) +TranslatingPort::TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc) + : FunctionalPort(_name), pTable(p_table), allocating(alloc) { } TranslatingPort::~TranslatingPort() diff --git a/src/mem/translating_port.hh b/src/mem/translating_port.hh index 7611ac3c7..d078158a3 100644 --- a/src/mem/translating_port.hh +++ b/src/mem/translating_port.hh @@ -39,14 +39,11 @@ class TranslatingPort : public FunctionalPort PageTable *pTable; bool allocating; - TranslatingPort(const TranslatingPort &specmem); - const TranslatingPort &operator=(const TranslatingPort &specmem); - public: - TranslatingPort(PageTable *p_table, bool alloc = false); + TranslatingPort(const std::string &_name, + PageTable *p_table, bool alloc = false); virtual ~TranslatingPort(); - public: bool tryReadBlob(Addr addr, uint8_t *p, int size); bool tryWriteBlob(Addr addr, uint8_t *p, int size); bool tryMemsetBlob(Addr addr, uint8_t val, int size); @@ -56,9 +53,9 @@ class TranslatingPort : public FunctionalPort virtual void readBlob(Addr addr, uint8_t *p, int size); virtual void writeBlob(Addr addr, uint8_t *p, int size); virtual void memsetBlob(Addr addr, uint8_t val, int size); + void writeString(Addr addr, const char *str); void readString(std::string &str, Addr addr); - }; #endif diff --git a/src/mem/vport.hh b/src/mem/vport.hh index fbc230ba3..0f3b1f09e 100644 --- a/src/mem/vport.hh +++ b/src/mem/vport.hh @@ -53,8 +53,8 @@ class VirtualPort : public FunctionalPort ExecContext *xc; public: - VirtualPort(ExecContext *_xc = NULL) - : xc(_xc) + VirtualPort(const std::string &_name, ExecContext *_xc = NULL) + : FunctionalPort(_name), xc(_xc) {} /** Return true if we have an exec context. This is used to prevent someone |