summaryrefslogtreecommitdiff
path: root/src/mem/bus.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/mem/bus.cc')
-rw-r--r--src/mem/bus.cc151
1 files changed, 92 insertions, 59 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc
index 2e735e03b..a2ddc0b69 100644
--- a/src/mem/bus.cc
+++ b/src/mem/bus.cc
@@ -47,6 +47,7 @@
* Definition of a bus object.
*/
+#include "base/intmath.hh"
#include "base/misc.hh"
#include "base/trace.hh"
#include "debug/Bus.hh"
@@ -54,9 +55,9 @@
#include "mem/bus.hh"
BaseBus::BaseBus(const BaseBusParams *p)
- : MemObject(p), clock(p->clock),
- headerCycles(p->header_cycles), width(p->width), tickNextIdle(0),
- drainEvent(NULL), busIdleEvent(this), inRetry(false),
+ : MemObject(p), state(IDLE), clock(p->clock),
+ headerCycles(p->header_cycles), width(p->width),
+ drainEvent(NULL), busIdleEvent(this),
defaultPortID(InvalidPortID),
useDefaultRange(p->use_default_range),
defaultBlockSize(p->block_size),
@@ -113,10 +114,7 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
{
// determine the current time rounded to the closest following
// clock edge
- Tick now = curTick();
- if (now % clock != 0) {
- now = ((now / clock) + 1) * clock;
- }
+ Tick now = divCeil(curTick(), clock) * clock;
Tick headerTime = now + headerCycles * clock;
@@ -142,52 +140,91 @@ BaseBus::calcPacketTiming(PacketPtr pkt)
void BaseBus::occupyBus(Tick until)
{
- if (until == 0) {
- // shortcut for express snoop packets
- return;
- }
-
- tickNextIdle = until;
- reschedule(busIdleEvent, tickNextIdle, true);
-
- DPRINTF(BaseBus, "The bus is now occupied from tick %d to %d\n",
- curTick(), tickNextIdle);
+ // ensure the state is busy or in retry and never idle at this
+ // point, as the bus should transition from idle as soon as it has
+ // decided to forward the packet to prevent any follow-on calls to
+ // sendTiming seeing an unoccupied bus
+ assert(state != IDLE);
+
+ // note that we do not change the bus state here, if we are going
+ // from idle to busy it is handled by tryTiming, and if we
+ // are in retry we should remain in retry such that
+ // succeededTiming still sees the accurate state
+
+ // until should never be 0 as express snoops never occupy the bus
+ assert(until != 0);
+ schedule(busIdleEvent, until);
+
+ DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
+ curTick(), until);
}
bool
-BaseBus::isOccupied(Port* port)
+BaseBus::tryTiming(Port* port)
{
- // first we see if the next idle tick is in the future, next the
- // bus is considered occupied if there are ports on the retry list
- // and we are not in a retry with the current port
- if (tickNextIdle > curTick() ||
- (!retryList.empty() && !(inRetry && port == retryList.front()))) {
- addToRetryList(port);
- return true;
+ // first we see if the bus is busy, next we check if we are in a
+ // retry with a port other than the current one
+ if (state == BUSY || (state == RETRY && port != retryList.front())) {
+ // put the port at the end of the retry list
+ retryList.push_back(port);
+ return false;
}
- return false;
+
+ // update the state which is shared for request, response and
+ // snoop responses, if we were idle we are now busy, if we are in
+ // a retry, then do not change
+ if (state == IDLE)
+ state = BUSY;
+
+ return true;
}
void
BaseBus::succeededTiming(Tick busy_time)
{
- // occupy the bus accordingly
- occupyBus(busy_time);
-
// if a retrying port succeeded, also take it off the retry list
- if (inRetry) {
+ if (state == RETRY) {
DPRINTF(BaseBus, "Remove retry from list %s\n",
retryList.front()->name());
retryList.pop_front();
- inRetry = false;
+ state = BUSY;
+ }
+
+ // we should either have gone from idle to busy in the
+ // tryTiming test, or just gone from a retry to busy
+ assert(state == BUSY);
+
+ // occupy the bus accordingly
+ occupyBus(busy_time);
+}
+
+void
+BaseBus::failedTiming(SlavePort* port, Tick busy_time)
+{
+ // if we are not in a retry, i.e. busy (but never idle), or we are
+ // in a retry but not for the current port, then add the port at
+ // the end of the retry list
+ if (state != RETRY || port != retryList.front()) {
+ retryList.push_back(port);
}
+
+ // even if we retried the current one and did not succeed,
+ // we are no longer retrying but instead busy
+ state = BUSY;
+
+ // occupy the bus accordingly
+ occupyBus(busy_time);
}
void
BaseBus::releaseBus()
{
// releasing the bus means we should now be idle
- assert(curTick() >= tickNextIdle);
+ assert(state == BUSY);
+ assert(!busIdleEvent.scheduled());
+
+ // update the state
+ state = IDLE;
// bus is now idle, so if someone is waiting we can retry
if (!retryList.empty()) {
@@ -196,10 +233,8 @@ BaseBus::releaseBus()
// busy, and in the latter case the bus may be released before
// we see a retry from the destination
retryWaiting();
- }
-
- //If we weren't able to drain before, we might be able to now.
- if (drainEvent && retryList.empty() && curTick() >= tickNextIdle) {
+ } else if (drainEvent) {
+ //If we weren't able to drain before, do it now.
drainEvent->process();
// Clear the drain event once we're done with it.
drainEvent = NULL;
@@ -212,8 +247,12 @@ BaseBus::retryWaiting()
// this should never be called with an empty retry list
assert(!retryList.empty());
- // send a retry to the port at the head of the retry list
- inRetry = true;
+ // we always go to retrying from idle
+ assert(state == IDLE);
+
+ // update the state which is shared for request, response and
+ // snoop responses
+ state = RETRY;
// note that we might have blocked on the receiving port being
// busy (rather than the bus itself) and now call retry before the
@@ -223,20 +262,22 @@ BaseBus::retryWaiting()
else
(dynamic_cast<MasterPort*>(retryList.front()))->sendRetry();
- // If inRetry is still true, sendTiming wasn't called in zero time
- // (e.g. the cache does this)
- if (inRetry) {
+ // If the bus is still in the retry state, sendTiming wasn't
+ // called in zero time (e.g. the cache does this)
+ if (state == RETRY) {
retryList.pop_front();
- inRetry = false;
-
- //Bring tickNextIdle up to the present
- while (tickNextIdle < curTick())
- tickNextIdle += clock;
//Burn a cycle for the missed grant.
- tickNextIdle += clock;
- reschedule(busIdleEvent, tickNextIdle, true);
+ // update the state which is shared for request, response and
+ // snoop responses
+ state = BUSY;
+
+ // determine the current time rounded to the closest following
+ // clock edge
+ Tick now = divCeil(curTick(), clock) * clock;
+
+ occupyBus(now + clock);
}
}
@@ -252,8 +293,8 @@ BaseBus::recvRetry()
if (retryList.empty())
return;
- // if the bus isn't busy
- if (curTick() >= tickNextIdle) {
+ // if the bus is idle
+ if (state == IDLE) {
// note that we do not care who told us to retry at the moment, we
// merely let the first one on the retry list go
retryWaiting();
@@ -445,17 +486,9 @@ BaseBus::drain(Event * de)
//We should check that we're not "doing" anything, and that noone is
//waiting. We might be idle but have someone waiting if the device we
//contacted for a retry didn't actually retry.
- if (!retryList.empty() || (curTick() < tickNextIdle &&
- busIdleEvent.scheduled())) {
+ if (!retryList.empty() || state != IDLE) {
drainEvent = de;
return 1;
}
return 0;
}
-
-void
-BaseBus::startup()
-{
- if (tickNextIdle < curTick())
- tickNextIdle = (curTick() / clock) * clock + clock;
-}