Fix simple timing port keep a list of all packets, have only one event, and scan all packets on a functional access.
--HG-- extra : convert_revision : c735a6408443b5cc90d1c1841c7aeb61e02ec6ae
This commit is contained in:
@@ -33,15 +33,16 @@
|
||||
void
|
||||
SimpleTimingPort::recvFunctional(PacketPtr pkt)
|
||||
{
|
||||
std::list<PacketPtr>::iterator i = transmitList.begin();
|
||||
std::list<PacketPtr>::iterator end = transmitList.end();
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator i = transmitList.begin();
|
||||
std::list<std::pair<Tick,PacketPtr> >::iterator end = transmitList.end();
|
||||
bool done = false;
|
||||
|
||||
while (i != end) {
|
||||
PacketPtr target = *i;
|
||||
while (i != end && !done) {
|
||||
PacketPtr target = i->second;
|
||||
// If the target contains data, and it overlaps the
|
||||
// probed request, need to update data
|
||||
if (target->intersect(pkt))
|
||||
fixPacket(pkt, target);
|
||||
done = fixPacket(pkt, target);
|
||||
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
|
||||
// turn packet around to go back to requester if response expected
|
||||
if (pkt->needsResponse()) {
|
||||
pkt->makeTimingResponse();
|
||||
sendTimingLater(pkt, latency);
|
||||
sendTiming(pkt, latency);
|
||||
}
|
||||
else {
|
||||
if (pkt->cmd != Packet::UpgradeReq)
|
||||
@@ -78,14 +79,14 @@ SimpleTimingPort::recvTiming(PacketPtr pkt)
|
||||
void
|
||||
SimpleTimingPort::recvRetry()
|
||||
{
|
||||
assert(outTiming > 0);
|
||||
assert(!transmitList.empty());
|
||||
if (sendTiming(transmitList.front())) {
|
||||
if (Port::sendTiming(transmitList.front().second)) {
|
||||
transmitList.pop_front();
|
||||
outTiming--;
|
||||
DPRINTF(Bus, "No Longer waiting on retry\n");
|
||||
if (!transmitList.empty())
|
||||
sendTimingLater(transmitList.front(), 1);
|
||||
if (!transmitList.empty()) {
|
||||
Tick time = transmitList.front().first;
|
||||
sendEvent.schedule(time <= curTick ? curTick+1 : time);
|
||||
}
|
||||
}
|
||||
|
||||
if (transmitList.empty() && drainEvent) {
|
||||
@@ -94,39 +95,44 @@ SimpleTimingPort::recvRetry()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SimpleTimingPort::sendTiming(PacketPtr pkt, Tick time)
|
||||
{
|
||||
if (transmitList.empty()) {
|
||||
assert(!sendEvent.scheduled());
|
||||
sendEvent.schedule(curTick+time);
|
||||
}
|
||||
transmitList.push_back(std::pair<Tick,PacketPtr>(time+curTick,pkt));
|
||||
}
|
||||
|
||||
void
|
||||
SimpleTimingPort::SendEvent::process()
|
||||
{
|
||||
assert(port->outTiming > 0);
|
||||
if (!port->transmitList.empty() && port->transmitList.front() != packet) {
|
||||
//We are not the head of the list
|
||||
port->transmitList.push_back(packet);
|
||||
} else if (port->sendTiming(packet)) {
|
||||
// send successful
|
||||
if (port->transmitList.size()) {
|
||||
port->transmitList.pop_front();
|
||||
port->outTiming--;
|
||||
if (!port->transmitList.empty())
|
||||
port->sendTimingLater(port->transmitList.front(), 1);
|
||||
assert(port->transmitList.size());
|
||||
assert(port->transmitList.front().first <= curTick);
|
||||
if (port->Port::sendTiming(port->transmitList.front().second)) {
|
||||
//send successful, remove packet
|
||||
port->transmitList.pop_front();
|
||||
if (!port->transmitList.empty()) {
|
||||
Tick time = port->transmitList.front().first;
|
||||
schedule(time <= curTick ? curTick+1 : time);
|
||||
}
|
||||
if (port->transmitList.empty() && port->drainEvent) {
|
||||
port->drainEvent->process();
|
||||
port->drainEvent = NULL;
|
||||
}
|
||||
} else {
|
||||
// send unsuccessful (due to flow control). Will get retry
|
||||
// callback later; save for then if not already
|
||||
DPRINTF(Bus, "Waiting on retry\n");
|
||||
if (!(port->transmitList.front() == packet))
|
||||
port->transmitList.push_back(packet);
|
||||
return;
|
||||
}
|
||||
// send unsuccessful (due to flow control). Will get retry
|
||||
// callback later; save for then if not already
|
||||
DPRINTF(Bus, "Waiting on retry\n");
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
SimpleTimingPort::drain(Event *de)
|
||||
{
|
||||
if (outTiming == 0 && transmitList.size() == 0)
|
||||
if (transmitList.size() == 0)
|
||||
return 0;
|
||||
drainEvent = de;
|
||||
return 1;
|
||||
|
||||
@@ -60,23 +60,22 @@ class SimpleTimingPort : public Port
|
||||
protected:
|
||||
/** A list of outgoing timing response packets that haven't been
|
||||
* serviced yet. */
|
||||
std::list<PacketPtr> transmitList;
|
||||
std::list<std::pair<Tick,PacketPtr> > transmitList;
|
||||
|
||||
/**
|
||||
* This class is used to implemented sendTiming() with a delay. When
|
||||
* a delay is requested a new event is created. When the event time
|
||||
* expires it attempts to send the packet. If it cannot, the packet
|
||||
* is pushed onto the transmit list to be sent when recvRetry() is
|
||||
* called. */
|
||||
* a delay is requested a the event is scheduled if it isn't already.
|
||||
* When the event time expires it attempts to send the packet.
|
||||
* If it cannot, the packet sent when recvRetry() is called.
|
||||
**/
|
||||
class SendEvent : public Event
|
||||
{
|
||||
SimpleTimingPort *port;
|
||||
PacketPtr packet;
|
||||
|
||||
public:
|
||||
SendEvent(SimpleTimingPort *p, PacketPtr pkt, Tick t)
|
||||
: Event(&mainEventQueue), port(p), packet(pkt)
|
||||
{ setFlags(AutoDelete); schedule(curTick + t); }
|
||||
SendEvent(SimpleTimingPort *p)
|
||||
: Event(&mainEventQueue), port(p)
|
||||
{ }
|
||||
|
||||
virtual void process();
|
||||
|
||||
@@ -84,19 +83,17 @@ class SimpleTimingPort : public Port
|
||||
{ return "Future scheduled sendTiming event"; }
|
||||
};
|
||||
|
||||
|
||||
/** Number of timing requests that are emulating the device timing before
|
||||
* attempting to end up on the bus.
|
||||
*/
|
||||
int outTiming;
|
||||
SendEvent sendEvent;
|
||||
|
||||
/** If we need to drain, keep the drain event around until we're done
|
||||
* here.*/
|
||||
Event *drainEvent;
|
||||
|
||||
/** Schedule a sendTiming() event to be called in the future. */
|
||||
void sendTimingLater(PacketPtr pkt, Tick time)
|
||||
{ outTiming++; new SendEvent(this, pkt, time); }
|
||||
/** Schedule a sendTiming() event to be called in the future.
|
||||
* @param pkt packet to send
|
||||
* @param time increment from now (in ticks) to send packet
|
||||
*/
|
||||
void sendTiming(PacketPtr pkt, Tick time);
|
||||
|
||||
/** This function is notification that the device should attempt to send a
|
||||
* packet again. */
|
||||
@@ -118,7 +115,7 @@ class SimpleTimingPort : public Port
|
||||
public:
|
||||
|
||||
SimpleTimingPort(std::string pname)
|
||||
: Port(pname), outTiming(0), drainEvent(NULL)
|
||||
: Port(pname), sendEvent(this), drainEvent(NULL)
|
||||
{}
|
||||
|
||||
/** Hook for draining timing accesses from the system. The
|
||||
|
||||
Reference in New Issue
Block a user