diff options
Diffstat (limited to 'src/dev/etherlink.cc')
-rw-r--r-- | src/dev/etherlink.cc | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc new file mode 100644 index 000000000..5b6531c2e --- /dev/null +++ b/src/dev/etherlink.cc @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2002-2005 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 + * Device module for modelling a fixed bandwidth full duplex ethernet link + */ + +#include <cmath> +#include <deque> +#include <string> +#include <vector> + +#include "base/random.hh" +#include "base/trace.hh" +#include "dev/etherdump.hh" +#include "dev/etherint.hh" +#include "dev/etherlink.hh" +#include "dev/etherpkt.hh" +#include "sim/builder.hh" +#include "sim/serialize.hh" +#include "sim/system.hh" +#include "sim/root.hh" + +using namespace std; + +EtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1, + double rate, Tick delay, Tick delayVar, EtherDump *dump) + : SimObject(name) +{ + link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump); + link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump); + + interface[0] = new Interface(name + ".int0", link[0], link[1]); + interface[1] = new Interface(name + ".int1", link[1], link[0]); + + interface[0]->setPeer(peer0); + peer0->setPeer(interface[0]); + interface[1]->setPeer(peer1); + peer1->setPeer(interface[1]); +} + +EtherLink::~EtherLink() +{ + delete link[0]; + delete link[1]; + + delete interface[0]; + delete interface[1]; +} + +EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx) + : EtherInt(name), txlink(tx) +{ + tx->setTxInt(this); + rx->setRxInt(this); +} + +EtherLink::Link::Link(const string &name, EtherLink *p, int num, + double rate, Tick delay, Tick delay_var, EtherDump *d) + : objName(name), parent(p), number(num), txint(NULL), rxint(NULL), + ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d), + doneEvent(this) +{ } + +void +EtherLink::serialize(ostream &os) +{ + link[0]->serialize("link0", os); + link[1]->serialize("link1", os); +} + +void +EtherLink::unserialize(Checkpoint *cp, const string §ion) +{ + link[0]->unserialize("link0", cp, section); + link[1]->unserialize("link1", cp, section); +} + +void +EtherLink::Link::txComplete(EthPacketPtr packet) +{ + DPRINTF(Ethernet, "packet received: len=%d\n", packet->length); + DDUMP(EthernetData, packet->data, packet->length); + rxint->sendPacket(packet); +} + +class LinkDelayEvent : public Event +{ + protected: + EtherLink::Link *link; + EthPacketPtr packet; + + public: + // non-scheduling version for createForUnserialize() + LinkDelayEvent(); + LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when); + + void process(); + + virtual void serialize(ostream &os); + virtual void unserialize(Checkpoint *cp, const string §ion); + static Serializable *createForUnserialize(Checkpoint *cp, + const string §ion); +}; + +void +EtherLink::Link::txDone() +{ + if (dump) + dump->dump(packet); + + if (linkDelay > 0) { + DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay); + new LinkDelayEvent(this, packet, curTick + linkDelay); + } else { + txComplete(packet); + } + + packet = 0; + assert(!busy()); + + txint->sendDone(); +} + +bool +EtherLink::Link::transmit(EthPacketPtr pkt) +{ + if (busy()) { + DPRINTF(Ethernet, "packet not sent, link busy\n"); + return false; + } + + DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length); + DDUMP(EthernetData, pkt->data, pkt->length); + + packet = pkt; + Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0); + if (delayVar != 0) { + Random<Tick> var; + delay += var.uniform(0, delayVar); + } + DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n", + delay, ticksPerByte); + doneEvent.schedule(curTick + delay); + + return true; +} + +void +EtherLink::Link::serialize(const string &base, ostream &os) +{ + bool packet_exists = packet; + paramOut(os, base + ".packet_exists", packet_exists); + if (packet_exists) + packet->serialize(base + ".packet", os); + + bool event_scheduled = doneEvent.scheduled(); + paramOut(os, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time = doneEvent.when(); + paramOut(os, base + ".event_time", event_time); + } + +} + +void +EtherLink::Link::unserialize(const string &base, Checkpoint *cp, + const string §ion) +{ + bool packet_exists; + paramIn(cp, section, base + ".packet_exists", packet_exists); + if (packet_exists) { + packet = new EthPacketData(16384); + packet->unserialize(base + ".packet", cp, section); + } + + bool event_scheduled; + paramIn(cp, section, base + ".event_scheduled", event_scheduled); + if (event_scheduled) { + Tick event_time; + paramIn(cp, section, base + ".event_time", event_time); + doneEvent.schedule(event_time); + } +} + +LinkDelayEvent::LinkDelayEvent() + : Event(&mainEventQueue), link(NULL) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); +} + +LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when) + : Event(&mainEventQueue), link(l), packet(p) +{ + setFlags(AutoSerialize); + setFlags(AutoDelete); + schedule(when); +} + +void +LinkDelayEvent::process() +{ + link->txComplete(packet); +} + +void +LinkDelayEvent::serialize(ostream &os) +{ + paramOut(os, "type", string("LinkDelayEvent")); + Event::serialize(os); + + EtherLink *parent = link->parent; + bool number = link->number; + SERIALIZE_OBJPTR(parent); + SERIALIZE_SCALAR(number); + + packet->serialize("packet", os); +} + + +void +LinkDelayEvent::unserialize(Checkpoint *cp, const string §ion) +{ + Event::unserialize(cp, section); + + EtherLink *parent; + bool number; + UNSERIALIZE_OBJPTR(parent); + UNSERIALIZE_SCALAR(number); + + link = parent->link[number]; + + packet = new EthPacketData(16384); + packet->unserialize("packet", cp, section); +} + + +Serializable * +LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string §ion) +{ + return new LinkDelayEvent(); +} + +REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent) + +BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + + SimObjectParam<EtherInt *> int1; + SimObjectParam<EtherInt *> int2; + Param<double> speed; + Param<Tick> delay; + Param<Tick> delay_var; + SimObjectParam<EtherDump *> dump; + +END_DECLARE_SIM_OBJECT_PARAMS(EtherLink) + +BEGIN_INIT_SIM_OBJECT_PARAMS(EtherLink) + + INIT_PARAM(int1, "interface 1"), + INIT_PARAM(int2, "interface 2"), + INIT_PARAM(speed, "link speed in bits per second"), + INIT_PARAM(delay, "transmit delay of packets in us"), + INIT_PARAM(delay_var, "Difference in amount of time to traverse wire"), + INIT_PARAM(dump, "object to dump network packets to") + +END_INIT_SIM_OBJECT_PARAMS(EtherLink) + +CREATE_SIM_OBJECT(EtherLink) +{ + return new EtherLink(getInstanceName(), int1, int2, speed, delay, delay_var, + dump); +} + +REGISTER_SIM_OBJECT("EtherLink", EtherLink) |