diff options
Diffstat (limited to 'mem/bridge.cc')
-rw-r--r-- | mem/bridge.cc | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/mem/bridge.cc b/mem/bridge.cc new file mode 100644 index 000000000..d358ef77b --- /dev/null +++ b/mem/bridge.cc @@ -0,0 +1,263 @@ + +/* + * Copyright (c) 2006 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file Definition of a simple bus bridge without buffering. + */ + + +#include "base/trace.hh" +#include "mem/bridge.hh" +#include "sim/builder.hh" + +void +Bridge::init() +{ + // Make sure that both sides are connected to. + if (sideA == NULL || sideB == 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 + * transaction.*/ +bool +Bridge::recvTiming(Packet &pkt, Side id) +{ + 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); + } + } + return true; + +} + +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() +{ + Tick t = 0; + + 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?"); + } + + if (t != 0) + sendEvent.schedule(t); +} + + +void +Bridge::BridgePort::sendPkt(Packet &pkt) +{ + if (!sendTiming(pkt)) + outbound.push_back(std::make_pair<Packet*,Tick>(&pkt, curTick)); +} + +void +Bridge::BridgePort::sendPkt(std::pair<Packet*, Tick> p) +{ + if (!sendTiming(*p.first)) + outbound.push_back(p); +} + + +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); + return pkt; +} + +/** Function called by the port when the bus is recieving a Atomic + * transaction.*/ +Tick +Bridge::recvAtomic(Packet &pkt, Side id) +{ + pkt.time += delay; + + if (id == SideA) + return sideB->sendAtomic(pkt); + else + return sideA->sendAtomic(pkt); +} + +/** Function called by the port when the bus is recieving a Functional + * transaction.*/ +void +Bridge::recvFunctional(Packet &pkt, Side id) +{ + pkt.time += delay; + std::list<std::pair<Packet*, Tick> >::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); + } + } + + if (pktContinue) { + if (id == SideA) + sideB->sendFunctional(pkt); + else + sideA->sendFunctional(pkt); + } +} + +/** Function called by the port when the bus is recieving a status change.*/ +void +Bridge::recvStatusChange(Port::Status status, Side id) +{ + if (status == Port::Blocked || status == Port::Unblocked) + return ; + + if (id == SideA) + sideB->sendStatusChange(status); + else + sideA->sendStatusChange(status); +} + +void +Bridge::addressRanges(AddrRangeList &resp, AddrRangeList &snoop, Side id) +{ + if (id == SideA) + sideB->getPeerAddressRanges(resp, snoop); + else + sideA->getPeerAddressRanges(resp, snoop); +} + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(Bridge) + + Param<int> queue_size_a; + Param<int> queue_size_b; + Param<Tick> delay; + Param<bool> write_ack; + +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(delay, "The miminum delay to cross this bridge"), + INIT_PARAM(write_ack, "Acknowledge any writes that are received.") + +END_INIT_SIM_OBJECT_PARAMS(Bridge) + +CREATE_SIM_OBJECT(Bridge) +{ + return new Bridge(getInstanceName(), queue_size_a, queue_size_b, delay, + write_ack); +} + +REGISTER_SIM_OBJECT("Bridge", Bridge) |