etherlink.cc revision 4762
16892SBrad.Beckmann@amd.com/*
26892SBrad.Beckmann@amd.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
36892SBrad.Beckmann@amd.com * All rights reserved.
46892SBrad.Beckmann@amd.com *
56892SBrad.Beckmann@amd.com * Redistribution and use in source and binary forms, with or without
66892SBrad.Beckmann@amd.com * modification, are permitted provided that the following conditions are
76892SBrad.Beckmann@amd.com * met: redistributions of source code must retain the above copyright
86892SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer;
96892SBrad.Beckmann@amd.com * redistributions in binary form must reproduce the above copyright
106892SBrad.Beckmann@amd.com * notice, this list of conditions and the following disclaimer in the
116892SBrad.Beckmann@amd.com * documentation and/or other materials provided with the distribution;
126892SBrad.Beckmann@amd.com * neither the name of the copyright holders nor the names of its
136892SBrad.Beckmann@amd.com * contributors may be used to endorse or promote products derived from
146892SBrad.Beckmann@amd.com * this software without specific prior written permission.
156892SBrad.Beckmann@amd.com *
166892SBrad.Beckmann@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176892SBrad.Beckmann@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186892SBrad.Beckmann@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196892SBrad.Beckmann@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206892SBrad.Beckmann@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216892SBrad.Beckmann@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226892SBrad.Beckmann@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236892SBrad.Beckmann@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246892SBrad.Beckmann@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256892SBrad.Beckmann@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266892SBrad.Beckmann@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276892SBrad.Beckmann@amd.com *
286892SBrad.Beckmann@amd.com * Authors: Nathan Binkert
296892SBrad.Beckmann@amd.com *          Ron Dreslinski
307563SBrad.Beckmann@amd.com */
316892SBrad.Beckmann@amd.com
326892SBrad.Beckmann@amd.com/* @file
336892SBrad.Beckmann@amd.com * Device module for modelling a fixed bandwidth full duplex ethernet link
346892SBrad.Beckmann@amd.com */
357538SBrad.Beckmann@amd.com
367538SBrad.Beckmann@amd.com#include <cmath>
377538SBrad.Beckmann@amd.com#include <deque>
387538SBrad.Beckmann@amd.com#include <string>
397538SBrad.Beckmann@amd.com#include <vector>
407538SBrad.Beckmann@amd.com
417661Snate@binkert.org#include "base/random.hh"
427538SBrad.Beckmann@amd.com#include "base/trace.hh"
437538SBrad.Beckmann@amd.com#include "dev/etherdump.hh"
447538SBrad.Beckmann@amd.com#include "dev/etherint.hh"
457917SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
467563SBrad.Beckmann@amd.com#include "dev/etherpkt.hh"
477563SBrad.Beckmann@amd.com#include "params/EtherLink.hh"
487538SBrad.Beckmann@amd.com#include "sim/serialize.hh"
497538SBrad.Beckmann@amd.com#include "sim/system.hh"
507538SBrad.Beckmann@amd.com#include "sim/core.hh"
517538SBrad.Beckmann@amd.com
527538SBrad.Beckmann@amd.comusing namespace std;
537566SBrad.Beckmann@amd.com
547566SBrad.Beckmann@amd.comEtherLink::EtherLink(const string &name, EtherInt *peer0, EtherInt *peer1,
557809Snilay@cs.wisc.edu                     double rate, Tick delay, Tick delayVar, EtherDump *dump)
567809Snilay@cs.wisc.edu    : SimObject(name)
577809Snilay@cs.wisc.edu{
587809Snilay@cs.wisc.edu    link[0] = new Link(name + ".link0", this, 0, rate, delay, delayVar, dump);
597538SBrad.Beckmann@amd.com    link[1] = new Link(name + ".link1", this, 1, rate, delay, delayVar, dump);
607538SBrad.Beckmann@amd.com
617538SBrad.Beckmann@amd.com    interface[0] = new Interface(name + ".int0", link[0], link[1]);
627538SBrad.Beckmann@amd.com    interface[1] = new Interface(name + ".int1", link[1], link[0]);
637541SBrad.Beckmann@amd.com
646892SBrad.Beckmann@amd.com    interface[0]->setPeer(peer0);
657032SBrad.Beckmann@amd.com    peer0->setPeer(interface[0]);
667032SBrad.Beckmann@amd.com    interface[1]->setPeer(peer1);
676923SBrad.Beckmann@amd.com    peer1->setPeer(interface[1]);
686893SBrad.Beckmann@amd.com}
697557SBrad.Beckmann@amd.com
707557SBrad.Beckmann@amd.comEtherLink::~EtherLink()
716923SBrad.Beckmann@amd.com{
726923SBrad.Beckmann@amd.com    delete link[0];
737557SBrad.Beckmann@amd.com    delete link[1];
748257SBrad.Beckmann@amd.com
758257SBrad.Beckmann@amd.com    delete interface[0];
768257SBrad.Beckmann@amd.com    delete interface[1];
778257SBrad.Beckmann@amd.com}
788257SBrad.Beckmann@amd.com
798257SBrad.Beckmann@amd.comEtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
808257SBrad.Beckmann@amd.com    : EtherInt(name), txlink(tx)
818257SBrad.Beckmann@amd.com{
828257SBrad.Beckmann@amd.com    tx->setTxInt(this);
838257SBrad.Beckmann@amd.com    rx->setRxInt(this);
848257SBrad.Beckmann@amd.com}
858257SBrad.Beckmann@amd.com
868257SBrad.Beckmann@amd.comEtherLink::Link::Link(const string &name, EtherLink *p, int num,
878257SBrad.Beckmann@amd.com                      double rate, Tick delay, Tick delay_var, EtherDump *d)
888257SBrad.Beckmann@amd.com    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
898257SBrad.Beckmann@amd.com      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
908258SBrad.Beckmann@amd.com      doneEvent(this)
918258SBrad.Beckmann@amd.com{ }
928257SBrad.Beckmann@amd.com
938257SBrad.Beckmann@amd.comvoid
946892SBrad.Beckmann@amd.comEtherLink::serialize(ostream &os)
957032SBrad.Beckmann@amd.com{
967032SBrad.Beckmann@amd.com    link[0]->serialize("link0", os);
976892SBrad.Beckmann@amd.com    link[1]->serialize("link1", os);
987032SBrad.Beckmann@amd.com}
997032SBrad.Beckmann@amd.com
1008257SBrad.Beckmann@amd.comvoid
1018257SBrad.Beckmann@amd.comEtherLink::unserialize(Checkpoint *cp, const string &section)
1028257SBrad.Beckmann@amd.com{
1037557SBrad.Beckmann@amd.com    link[0]->unserialize("link0", cp, section);
1047032SBrad.Beckmann@amd.com    link[1]->unserialize("link1", cp, section);
1057032SBrad.Beckmann@amd.com}
1067557SBrad.Beckmann@amd.com
1078257SBrad.Beckmann@amd.comvoid
1088257SBrad.Beckmann@amd.comEtherLink::Link::txComplete(EthPacketPtr packet)
1096892SBrad.Beckmann@amd.com{
1106903SBrad.Beckmann@amd.com    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
1117563SBrad.Beckmann@amd.com    DDUMP(EthernetData, packet->data, packet->length);
1127025SBrad.Beckmann@amd.com    rxint->sendPacket(packet);
1137025SBrad.Beckmann@amd.com}
1147025SBrad.Beckmann@amd.com
1157025SBrad.Beckmann@amd.comclass LinkDelayEvent : public Event
1167563SBrad.Beckmann@amd.com{
1176903SBrad.Beckmann@amd.com  protected:
1186903SBrad.Beckmann@amd.com    EtherLink::Link *link;
1197563SBrad.Beckmann@amd.com    EthPacketPtr packet;
1207563SBrad.Beckmann@amd.com
1217563SBrad.Beckmann@amd.com  public:
1227563SBrad.Beckmann@amd.com    // non-scheduling version for createForUnserialize()
1237563SBrad.Beckmann@amd.com    LinkDelayEvent();
1247563SBrad.Beckmann@amd.com    LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when);
1257563SBrad.Beckmann@amd.com
1267663SBrad.Beckmann@amd.com    void process();
1277663SBrad.Beckmann@amd.com
1287663SBrad.Beckmann@amd.com    virtual void serialize(ostream &os);
1297663SBrad.Beckmann@amd.com    virtual void unserialize(Checkpoint *cp, const string &section);
1307663SBrad.Beckmann@amd.com    static Serializable *createForUnserialize(Checkpoint *cp,
1317563SBrad.Beckmann@amd.com                                              const string &section);
1326903SBrad.Beckmann@amd.com};
1336903SBrad.Beckmann@amd.com
1347563SBrad.Beckmann@amd.comvoid
1357563SBrad.Beckmann@amd.comEtherLink::Link::txDone()
1367541SBrad.Beckmann@amd.com{
1377541SBrad.Beckmann@amd.com    if (dump)
1386905SBrad.Beckmann@amd.com        dump->dump(packet);
1396892SBrad.Beckmann@amd.com
1406897SBrad.Beckmann@amd.com    if (linkDelay > 0) {
1416892SBrad.Beckmann@amd.com        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
1426893SBrad.Beckmann@amd.com        new LinkDelayEvent(this, packet, curTick + linkDelay);
1436892SBrad.Beckmann@amd.com    } else {
1446892SBrad.Beckmann@amd.com        txComplete(packet);
1456892SBrad.Beckmann@amd.com    }
1466903SBrad.Beckmann@amd.com
1476892SBrad.Beckmann@amd.com    packet = 0;
1486893SBrad.Beckmann@amd.com    assert(!busy());
1497809Snilay@cs.wisc.edu
1506892SBrad.Beckmann@amd.com    txint->sendDone();
1516892SBrad.Beckmann@amd.com}
152
153bool
154EtherLink::Link::transmit(EthPacketPtr pkt)
155{
156    if (busy()) {
157        DPRINTF(Ethernet, "packet not sent, link busy\n");
158        return false;
159    }
160
161    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
162    DDUMP(EthernetData, pkt->data, pkt->length);
163
164    packet = pkt;
165    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
166    if (delayVar != 0) {
167        Random<Tick> var;
168        delay +=  var.uniform(0, delayVar);
169    }
170    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
171            delay, ticksPerByte);
172    doneEvent.schedule(curTick + delay);
173
174    return true;
175}
176
177void
178EtherLink::Link::serialize(const string &base, ostream &os)
179{
180    bool packet_exists = packet;
181    paramOut(os, base + ".packet_exists", packet_exists);
182    if (packet_exists)
183        packet->serialize(base + ".packet", os);
184
185    bool event_scheduled = doneEvent.scheduled();
186    paramOut(os, base + ".event_scheduled", event_scheduled);
187    if (event_scheduled) {
188        Tick event_time = doneEvent.when();
189        paramOut(os, base + ".event_time", event_time);
190    }
191
192}
193
194void
195EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
196                             const string &section)
197{
198    bool packet_exists;
199    paramIn(cp, section, base + ".packet_exists", packet_exists);
200    if (packet_exists) {
201        packet = new EthPacketData(16384);
202        packet->unserialize(base + ".packet", cp, section);
203    }
204
205    bool event_scheduled;
206    paramIn(cp, section, base + ".event_scheduled", event_scheduled);
207    if (event_scheduled) {
208        Tick event_time;
209        paramIn(cp, section, base + ".event_time", event_time);
210        doneEvent.schedule(event_time);
211    }
212}
213
214LinkDelayEvent::LinkDelayEvent()
215    : Event(&mainEventQueue), link(NULL)
216{
217    setFlags(AutoSerialize);
218    setFlags(AutoDelete);
219}
220
221LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when)
222    : Event(&mainEventQueue), link(l), packet(p)
223{
224    setFlags(AutoSerialize);
225    setFlags(AutoDelete);
226    schedule(when);
227}
228
229void
230LinkDelayEvent::process()
231{
232    link->txComplete(packet);
233}
234
235void
236LinkDelayEvent::serialize(ostream &os)
237{
238    paramOut(os, "type", string("LinkDelayEvent"));
239    Event::serialize(os);
240
241    EtherLink *parent = link->parent;
242    bool number = link->number;
243    SERIALIZE_OBJPTR(parent);
244    SERIALIZE_SCALAR(number);
245
246    packet->serialize("packet", os);
247}
248
249
250void
251LinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
252{
253    Event::unserialize(cp, section);
254
255    EtherLink *parent;
256    bool number;
257    UNSERIALIZE_OBJPTR(parent);
258    UNSERIALIZE_SCALAR(number);
259
260    link = parent->link[number];
261
262    packet = new EthPacketData(16384);
263    packet->unserialize("packet", cp, section);
264}
265
266
267Serializable *
268LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
269{
270    return new LinkDelayEvent();
271}
272
273REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
274
275EtherLink *
276EtherLinkParams::create()
277{
278    return new EtherLink(name, int1, int2, speed, delay, delay_var, dump);
279}
280