/* * 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. * * Authors: Nathan Binkert * Ron Dreslinski */ /* @file * Device module for modelling a fixed bandwidth full duplex ethernet link */ #include #include #include #include #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 "params/EtherLink.hh" #include "sim/serialize.hh" #include "sim/system.hh" #include "sim/core.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 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) EtherLink * EtherLinkParams::create() { return new EtherLink(name, int1, int2, speed, delay, delay_var, dump); }