diff options
author | Gabe Black <gblack@eecs.umich.edu> | 2006-10-08 14:09:13 -0400 |
---|---|---|
committer | Gabe Black <gblack@eecs.umich.edu> | 2006-10-08 14:09:13 -0400 |
commit | 63023ba4c21e293e93d799815b94f41024da0f97 (patch) | |
tree | 5a0d9a9f72f761a55d71953146035d33a9e2807c /src/mem/bus.cc | |
parent | c2f954ac692e664ba105f94c64c8c408cf1b4380 (diff) | |
parent | 00481d1f192c832d654379c2296d5b6020c12b1a (diff) | |
download | gem5-63023ba4c21e293e93d799815b94f41024da0f97.tar.xz |
Merge zizzer.eecs.umich.edu:/bk/newmem
into zeep.eecs.umich.edu:/home/gblack/m5/newmem_bus
--HG--
extra : convert_revision : 1749397443ccb320d32f8dd23c71ed0431d30cb7
Diffstat (limited to 'src/mem/bus.cc')
-rw-r--r-- | src/mem/bus.cc | 145 |
1 files changed, 112 insertions, 33 deletions
diff --git a/src/mem/bus.cc b/src/mem/bus.cc index 3c5283a77..2a38cb635 100644 --- a/src/mem/bus.cc +++ b/src/mem/bus.cc @@ -67,6 +67,44 @@ Bus::init() (*intIter)->sendStatusChange(Port::RangeChange); } +Bus::BusFreeEvent::BusFreeEvent(Bus *_bus) : Event(&mainEventQueue), bus(_bus) +{} + +void Bus::BusFreeEvent::process() +{ + bus->recvRetry(0); +} + +const char * Bus::BusFreeEvent::description() +{ + return "bus became available"; +} + +void +Bus::occupyBus(int numCycles) +{ + //Move up when the bus will next be free + //We avoid the use of divide by adding repeatedly + //This should be faster if the value is updated frequently, but should + //be may be slower otherwise. + + //Bring tickNextIdle up to the present tick + //There is some potential ambiguity where a cycle starts, which might make + //a difference when devices are acting right around a cycle boundary. Using + //a < allows things which happen exactly on a cycle boundary to take up only + //the following cycle. Anthing that happens later will have to "wait" for the + //end of that cycle, and then start using the bus after that. + while (tickNextIdle < curTick) + tickNextIdle += clock; + //Advance it numCycles bus cycles. + //XXX Should this use the repeating add trick as well? + tickNextIdle += (numCycles * clock); + if (!busIdle.scheduled()) { + busIdle.schedule(tickNextIdle); + } else { + busIdle.reschedule(tickNextIdle); + } +} /** Function called by the port when the bus is receiving a Timing * transaction.*/ @@ -77,52 +115,89 @@ Bus::recvTiming(Packet *pkt) 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) { - if ( timingSnoopPhase1(pkt) ) - { - timingSnoopPhase2(pkt); - port = findPort(pkt->getAddr(), pkt->getSrc()); - } - else - { - //Snoop didn't succeed - retryList.push_back(interfaces[pkt->getSrc()]); - return false; + Port *pktPort = interfaces[pkt->getSrc()]; + + // If the bus is busy, or other devices are in line ahead of the current one, + // put this device on the retry list. + if (tickNextIdle > curTick || (retryList.size() && pktPort != retryingPort)) { + addToRetryList(pktPort); + return false; + } + + // If the bus is blocked, make the device wait. + if (!(port = findDestPort(pkt, pkt->getSrc()))) { + addToRetryList(pktPort); + return false; + } + + // The packet will be sent. Figure out how long it occupies the bus. + int numCycles = 0; + // Requests need one cycle to send an address + if (pkt->isRequest()) + numCycles++; + else if (pkt->isResponse() || pkt->hasData()) { + // If a packet has data, it needs ceil(size/width) cycles to send it + // We're using the "adding instead of dividing" trick again here + if (pkt->hasData()) { + int dataSize = pkt->getSize(); + for (int transmitted = 0; transmitted < dataSize; + transmitted += width) { + numCycles++; + } + } else { + // If the packet didn't have data, it must have been a response. + // Those use the bus for one cycle to send their data. + numCycles++; } - } else { - assert(dest >= 0 && dest < interfaces.size()); - assert(dest != pkt->getSrc()); // catch infinite loops - port = interfaces[dest]; } + + occupyBus(numCycles); + if (port->sendTiming(pkt)) { - // packet was successfully sent, just return true. + // Packet was successfully sent. Return true. return true; } - // packet not successfully sent - retryList.push_back(interfaces[pkt->getSrc()]); + // Packet not successfully sent. Leave or put it on the retry list. + addToRetryList(pktPort); return false; } void Bus::recvRetry(int id) { - // Go through all the elements on the list calling sendRetry on each - // This is not very efficient at all but it works. Ultimately we should end - // up with something that is more intelligent. - int initialSize = retryList.size(); - int i; - Port *p; - - for (i = 0; i < initialSize; i++) { - assert(retryList.size() > 0); - p = retryList.front(); - retryList.pop_front(); - p->sendRetry(); + //If there's anything waiting... + if (retryList.size()) { + retryingPort = retryList.front(); + retryingPort->sendRetry(); + //If the retryingPort pointer isn't null, either sendTiming wasn't + //called, or it was and the packet was successfully sent. + if (retryingPort) { + retryList.pop_front(); + retryingPort = 0; + } } } +Port * +Bus::findDestPort(PacketPtr pkt, int id) +{ + Port * port = NULL; + short dest = pkt->getDest(); + + if (dest == Packet::Broadcast) { + if (timingSnoopPhase1(pkt)) { + timingSnoopPhase2(pkt); + port = findPort(pkt->getAddr(), pkt->getSrc()); + } + //else, port stays NULL + } else { + assert(dest >= 0 && dest < interfaces.size()); + assert(dest != pkt->getSrc()); // catch infinite loops + port = interfaces[dest]; + } + return port; +} Port * Bus::findPort(Addr addr, int id) @@ -381,16 +456,20 @@ Bus::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, int id) BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bus) Param<int> bus_id; + Param<int> clock; + Param<int> width; END_DECLARE_SIM_OBJECT_PARAMS(Bus) BEGIN_INIT_SIM_OBJECT_PARAMS(Bus) - INIT_PARAM(bus_id, "a globally unique bus id") + INIT_PARAM(bus_id, "a globally unique bus id"), + INIT_PARAM(clock, "bus clock speed"), + INIT_PARAM(width, "width of the bus (bits)") END_INIT_SIM_OBJECT_PARAMS(Bus) CREATE_SIM_OBJECT(Bus) { - return new Bus(getInstanceName(), bus_id); + return new Bus(getInstanceName(), bus_id, clock, width); } REGISTER_SIM_OBJECT("Bus", Bus) |