etherlink.cc revision 5034
112697Santhony.gutierrez@amd.com/*
212697Santhony.gutierrez@amd.com * Copyright (c) 2002-2005 The Regents of The University of Michigan
311308Santhony.gutierrez@amd.com * All rights reserved.
412697Santhony.gutierrez@amd.com *
511308Santhony.gutierrez@amd.com * Redistribution and use in source and binary forms, with or without
612697Santhony.gutierrez@amd.com * modification, are permitted provided that the following conditions are
712697Santhony.gutierrez@amd.com * met: redistributions of source code must retain the above copyright
811308Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer;
912697Santhony.gutierrez@amd.com * redistributions in binary form must reproduce the above copyright
1012697Santhony.gutierrez@amd.com * notice, this list of conditions and the following disclaimer in the
1111308Santhony.gutierrez@amd.com * documentation and/or other materials provided with the distribution;
1212697Santhony.gutierrez@amd.com * neither the name of the copyright holders nor the names of its
1312697Santhony.gutierrez@amd.com * contributors may be used to endorse or promote products derived from
1412697Santhony.gutierrez@amd.com * this software without specific prior written permission.
1511308Santhony.gutierrez@amd.com *
1612697Santhony.gutierrez@amd.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1712697Santhony.gutierrez@amd.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1812697Santhony.gutierrez@amd.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
1911308Santhony.gutierrez@amd.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2012697Santhony.gutierrez@amd.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2112697Santhony.gutierrez@amd.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2212697Santhony.gutierrez@amd.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2312697Santhony.gutierrez@amd.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2412697Santhony.gutierrez@amd.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2512697Santhony.gutierrez@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2612697Santhony.gutierrez@amd.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2712697Santhony.gutierrez@amd.com *
2812697Santhony.gutierrez@amd.com * Authors: Nathan Binkert
2912697Santhony.gutierrez@amd.com *          Ron Dreslinski
3012697Santhony.gutierrez@amd.com */
3111308Santhony.gutierrez@amd.com
3212697Santhony.gutierrez@amd.com/* @file
3311308Santhony.gutierrez@amd.com * Device module for modelling a fixed bandwidth full duplex ethernet link
3411308Santhony.gutierrez@amd.com */
3511308Santhony.gutierrez@amd.com
3611308Santhony.gutierrez@amd.com#include <cmath>
3711308Santhony.gutierrez@amd.com#include <deque>
3811308Santhony.gutierrez@amd.com#include <string>
3911308Santhony.gutierrez@amd.com#include <vector>
4011308Santhony.gutierrez@amd.com
4111670Sandreas.hansson@arm.com#include "base/random.hh"
4211670Sandreas.hansson@arm.com#include "base/trace.hh"
4311308Santhony.gutierrez@amd.com#include "dev/etherdump.hh"
4411308Santhony.gutierrez@amd.com#include "dev/etherint.hh"
4511308Santhony.gutierrez@amd.com#include "dev/etherlink.hh"
4611308Santhony.gutierrez@amd.com#include "dev/etherpkt.hh"
4711308Santhony.gutierrez@amd.com#include "params/EtherLink.hh"
4811308Santhony.gutierrez@amd.com#include "sim/serialize.hh"
4911308Santhony.gutierrez@amd.com#include "sim/system.hh"
5011308Santhony.gutierrez@amd.com#include "sim/core.hh"
5111308Santhony.gutierrez@amd.com
5211308Santhony.gutierrez@amd.comusing namespace std;
5311308Santhony.gutierrez@amd.com
5411308Santhony.gutierrez@amd.comEtherLink::EtherLink(const Params *p)
5511308Santhony.gutierrez@amd.com    : EtherObject(p)
5611308Santhony.gutierrez@amd.com{
5711308Santhony.gutierrez@amd.com    link[0] = new Link(name() + ".link0", this, 0, p->speed,
5811308Santhony.gutierrez@amd.com                       p->delay, p->delay_var, p->dump);
5911308Santhony.gutierrez@amd.com    link[1] = new Link(name() + ".link1", this, 1, p->speed,
6011308Santhony.gutierrez@amd.com                       p->delay, p->delay_var, p->dump);
6111308Santhony.gutierrez@amd.com
6211308Santhony.gutierrez@amd.com    interface[0] = new Interface(name() + ".int0", link[0], link[1]);
6311308Santhony.gutierrez@amd.com    interface[1] = new Interface(name() + ".int1", link[1], link[0]);
6411308Santhony.gutierrez@amd.com}
6511308Santhony.gutierrez@amd.com
6611308Santhony.gutierrez@amd.com
6711308Santhony.gutierrez@amd.comEtherLink::~EtherLink()
6811308Santhony.gutierrez@amd.com{
6911308Santhony.gutierrez@amd.com    delete link[0];
7011308Santhony.gutierrez@amd.com    delete link[1];
7111308Santhony.gutierrez@amd.com
7211308Santhony.gutierrez@amd.com    delete interface[0];
7311308Santhony.gutierrez@amd.com    delete interface[1];
7411308Santhony.gutierrez@amd.com}
7511308Santhony.gutierrez@amd.com
7611308Santhony.gutierrez@amd.comEtherInt*
7711308Santhony.gutierrez@amd.comEtherLink::getEthPort(const std::string &if_name, int idx)
7811308Santhony.gutierrez@amd.com{
7911308Santhony.gutierrez@amd.com    Interface *i;
8011308Santhony.gutierrez@amd.com    if (if_name == "int0")
8111308Santhony.gutierrez@amd.com        i = interface[0];
8211308Santhony.gutierrez@amd.com    else if (if_name == "int1")
8311308Santhony.gutierrez@amd.com        i = interface[1];
8411308Santhony.gutierrez@amd.com    else
8511308Santhony.gutierrez@amd.com        return NULL;
8611308Santhony.gutierrez@amd.com    if (i->getPeer())
8711308Santhony.gutierrez@amd.com        panic("interface already connected to\n");
8811308Santhony.gutierrez@amd.com
8911308Santhony.gutierrez@amd.com    return i;
9011308Santhony.gutierrez@amd.com}
9111308Santhony.gutierrez@amd.com
9211308Santhony.gutierrez@amd.com
9311308Santhony.gutierrez@amd.comEtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
9411308Santhony.gutierrez@amd.com    : EtherInt(name), txlink(tx)
9511308Santhony.gutierrez@amd.com{
9611308Santhony.gutierrez@amd.com    tx->setTxInt(this);
9711308Santhony.gutierrez@amd.com    rx->setRxInt(this);
9811308Santhony.gutierrez@amd.com}
9911308Santhony.gutierrez@amd.com
10011308Santhony.gutierrez@amd.comEtherLink::Link::Link(const string &name, EtherLink *p, int num,
10111308Santhony.gutierrez@amd.com                      double rate, Tick delay, Tick delay_var, EtherDump *d)
10211308Santhony.gutierrez@amd.com    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
10311308Santhony.gutierrez@amd.com      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
10411308Santhony.gutierrez@amd.com      doneEvent(this)
10511308Santhony.gutierrez@amd.com{ }
10611308Santhony.gutierrez@amd.com
10711308Santhony.gutierrez@amd.comvoid
10811308Santhony.gutierrez@amd.comEtherLink::serialize(ostream &os)
10911308Santhony.gutierrez@amd.com{
11011308Santhony.gutierrez@amd.com    link[0]->serialize("link0", os);
11111308Santhony.gutierrez@amd.com    link[1]->serialize("link1", os);
11211308Santhony.gutierrez@amd.com}
11311308Santhony.gutierrez@amd.com
11411308Santhony.gutierrez@amd.comvoid
11511308Santhony.gutierrez@amd.comEtherLink::unserialize(Checkpoint *cp, const string &section)
11611308Santhony.gutierrez@amd.com{
11711308Santhony.gutierrez@amd.com    link[0]->unserialize("link0", cp, section);
11811308Santhony.gutierrez@amd.com    link[1]->unserialize("link1", cp, section);
11911308Santhony.gutierrez@amd.com}
12011308Santhony.gutierrez@amd.com
12111308Santhony.gutierrez@amd.comvoid
12211308Santhony.gutierrez@amd.comEtherLink::Link::txComplete(EthPacketPtr packet)
12311308Santhony.gutierrez@amd.com{
12411308Santhony.gutierrez@amd.com    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
12511308Santhony.gutierrez@amd.com    DDUMP(EthernetData, packet->data, packet->length);
12611308Santhony.gutierrez@amd.com    rxint->sendPacket(packet);
12711308Santhony.gutierrez@amd.com}
12811308Santhony.gutierrez@amd.com
12911308Santhony.gutierrez@amd.comclass LinkDelayEvent : public Event
13011308Santhony.gutierrez@amd.com{
13111308Santhony.gutierrez@amd.com  protected:
13211308Santhony.gutierrez@amd.com    EtherLink::Link *link;
13311308Santhony.gutierrez@amd.com    EthPacketPtr packet;
13411308Santhony.gutierrez@amd.com
13511308Santhony.gutierrez@amd.com  public:
13611308Santhony.gutierrez@amd.com    // non-scheduling version for createForUnserialize()
13711308Santhony.gutierrez@amd.com    LinkDelayEvent();
13811308Santhony.gutierrez@amd.com    LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt, Tick when);
13911308Santhony.gutierrez@amd.com
14011308Santhony.gutierrez@amd.com    void process();
14111308Santhony.gutierrez@amd.com
14211308Santhony.gutierrez@amd.com    virtual void serialize(ostream &os);
14311308Santhony.gutierrez@amd.com    virtual void unserialize(Checkpoint *cp, const string &section);
14411308Santhony.gutierrez@amd.com    static Serializable *createForUnserialize(Checkpoint *cp,
14511308Santhony.gutierrez@amd.com                                              const string &section);
14611308Santhony.gutierrez@amd.com};
14711308Santhony.gutierrez@amd.com
14811308Santhony.gutierrez@amd.comvoid
14911308Santhony.gutierrez@amd.comEtherLink::Link::txDone()
15011308Santhony.gutierrez@amd.com{
15111308Santhony.gutierrez@amd.com    if (dump)
15211308Santhony.gutierrez@amd.com        dump->dump(packet);
15311308Santhony.gutierrez@amd.com
15411308Santhony.gutierrez@amd.com    if (linkDelay > 0) {
15511308Santhony.gutierrez@amd.com        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
15611308Santhony.gutierrez@amd.com        new LinkDelayEvent(this, packet, curTick + linkDelay);
15711308Santhony.gutierrez@amd.com    } else {
15811308Santhony.gutierrez@amd.com        txComplete(packet);
15911308Santhony.gutierrez@amd.com    }
16011308Santhony.gutierrez@amd.com
16111308Santhony.gutierrez@amd.com    packet = 0;
16211308Santhony.gutierrez@amd.com    assert(!busy());
16311308Santhony.gutierrez@amd.com
16411308Santhony.gutierrez@amd.com    txint->sendDone();
16511308Santhony.gutierrez@amd.com}
16611308Santhony.gutierrez@amd.com
16711308Santhony.gutierrez@amd.combool
16812065Snikos.nikoleris@arm.comEtherLink::Link::transmit(EthPacketPtr pkt)
16911308Santhony.gutierrez@amd.com{
17011308Santhony.gutierrez@amd.com    if (busy()) {
17111308Santhony.gutierrez@amd.com        DPRINTF(Ethernet, "packet not sent, link busy\n");
17211308Santhony.gutierrez@amd.com        return false;
17312065Snikos.nikoleris@arm.com    }
17412065Snikos.nikoleris@arm.com
17511308Santhony.gutierrez@amd.com    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
17611308Santhony.gutierrez@amd.com    DDUMP(EthernetData, pkt->data, pkt->length);
17711308Santhony.gutierrez@amd.com
17811308Santhony.gutierrez@amd.com    packet = pkt;
17911308Santhony.gutierrez@amd.com    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
18011308Santhony.gutierrez@amd.com    if (delayVar != 0) {
18111308Santhony.gutierrez@amd.com        Random<Tick> var;
18211308Santhony.gutierrez@amd.com        delay +=  var.uniform(0, delayVar);
18311308Santhony.gutierrez@amd.com    }
18411308Santhony.gutierrez@amd.com    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
18511308Santhony.gutierrez@amd.com            delay, ticksPerByte);
18611308Santhony.gutierrez@amd.com    doneEvent.schedule(curTick + delay);
18711308Santhony.gutierrez@amd.com
18811308Santhony.gutierrez@amd.com    return true;
18911308Santhony.gutierrez@amd.com}
19011308Santhony.gutierrez@amd.com
19111308Santhony.gutierrez@amd.comvoid
19211308Santhony.gutierrez@amd.comEtherLink::Link::serialize(const string &base, ostream &os)
19311308Santhony.gutierrez@amd.com{
19411308Santhony.gutierrez@amd.com    bool packet_exists = packet;
19511308Santhony.gutierrez@amd.com    paramOut(os, base + ".packet_exists", packet_exists);
19611308Santhony.gutierrez@amd.com    if (packet_exists)
19711308Santhony.gutierrez@amd.com        packet->serialize(base + ".packet", os);
19811308Santhony.gutierrez@amd.com
19911308Santhony.gutierrez@amd.com    bool event_scheduled = doneEvent.scheduled();
20011308Santhony.gutierrez@amd.com    paramOut(os, base + ".event_scheduled", event_scheduled);
20111308Santhony.gutierrez@amd.com    if (event_scheduled) {
20211308Santhony.gutierrez@amd.com        Tick event_time = doneEvent.when();
20311308Santhony.gutierrez@amd.com        paramOut(os, base + ".event_time", event_time);
20411308Santhony.gutierrez@amd.com    }
20511308Santhony.gutierrez@amd.com
20611308Santhony.gutierrez@amd.com}
20711308Santhony.gutierrez@amd.com
20811308Santhony.gutierrez@amd.comvoid
20911308Santhony.gutierrez@amd.comEtherLink::Link::unserialize(const string &base, Checkpoint *cp,
21012598Snikos.nikoleris@arm.com                             const string &section)
21112598Snikos.nikoleris@arm.com{
21211308Santhony.gutierrez@amd.com    bool packet_exists;
21311308Santhony.gutierrez@amd.com    paramIn(cp, section, base + ".packet_exists", packet_exists);
21411308Santhony.gutierrez@amd.com    if (packet_exists) {
21511308Santhony.gutierrez@amd.com        packet = new EthPacketData(16384);
21611308Santhony.gutierrez@amd.com        packet->unserialize(base + ".packet", cp, section);
21711308Santhony.gutierrez@amd.com    }
21811308Santhony.gutierrez@amd.com
21911308Santhony.gutierrez@amd.com    bool event_scheduled;
22011308Santhony.gutierrez@amd.com    paramIn(cp, section, base + ".event_scheduled", event_scheduled);
22111308Santhony.gutierrez@amd.com    if (event_scheduled) {
22211308Santhony.gutierrez@amd.com        Tick event_time;
22311308Santhony.gutierrez@amd.com        paramIn(cp, section, base + ".event_time", event_time);
22411308Santhony.gutierrez@amd.com        doneEvent.schedule(event_time);
22511308Santhony.gutierrez@amd.com    }
22611308Santhony.gutierrez@amd.com}
22711308Santhony.gutierrez@amd.com
22811308Santhony.gutierrez@amd.comLinkDelayEvent::LinkDelayEvent()
22911308Santhony.gutierrez@amd.com    : Event(&mainEventQueue), link(NULL)
23011308Santhony.gutierrez@amd.com{
23111308Santhony.gutierrez@amd.com    setFlags(AutoSerialize);
23211308Santhony.gutierrez@amd.com    setFlags(AutoDelete);
23311308Santhony.gutierrez@amd.com}
23411308Santhony.gutierrez@amd.com
23511308Santhony.gutierrez@amd.comLinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p, Tick when)
23611308Santhony.gutierrez@amd.com    : Event(&mainEventQueue), link(l), packet(p)
23712065Snikos.nikoleris@arm.com{
23812065Snikos.nikoleris@arm.com    setFlags(AutoSerialize);
23912065Snikos.nikoleris@arm.com    setFlags(AutoDelete);
24012065Snikos.nikoleris@arm.com    schedule(when);
24112065Snikos.nikoleris@arm.com}
24212065Snikos.nikoleris@arm.com
24312065Snikos.nikoleris@arm.comvoid
24412065Snikos.nikoleris@arm.comLinkDelayEvent::process()
24512065Snikos.nikoleris@arm.com{
24612065Snikos.nikoleris@arm.com    link->txComplete(packet);
24712065Snikos.nikoleris@arm.com}
24811308Santhony.gutierrez@amd.com
24912065Snikos.nikoleris@arm.comvoid
25012065Snikos.nikoleris@arm.comLinkDelayEvent::serialize(ostream &os)
25112065Snikos.nikoleris@arm.com{
25212065Snikos.nikoleris@arm.com    paramOut(os, "type", string("LinkDelayEvent"));
25312065Snikos.nikoleris@arm.com    Event::serialize(os);
25412065Snikos.nikoleris@arm.com
25512065Snikos.nikoleris@arm.com    EtherLink *parent = link->parent;
25612065Snikos.nikoleris@arm.com    bool number = link->number;
25711308Santhony.gutierrez@amd.com    SERIALIZE_OBJPTR(parent);
25811308Santhony.gutierrez@amd.com    SERIALIZE_SCALAR(number);
25912065Snikos.nikoleris@arm.com
26011308Santhony.gutierrez@amd.com    packet->serialize("packet", os);
26111308Santhony.gutierrez@amd.com}
26211308Santhony.gutierrez@amd.com
26311308Santhony.gutierrez@amd.com
26411308Santhony.gutierrez@amd.comvoid
26511308Santhony.gutierrez@amd.comLinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
26611308Santhony.gutierrez@amd.com{
26711308Santhony.gutierrez@amd.com    Event::unserialize(cp, section);
26811308Santhony.gutierrez@amd.com
26911308Santhony.gutierrez@amd.com    EtherLink *parent;
27011308Santhony.gutierrez@amd.com    bool number;
27111308Santhony.gutierrez@amd.com    UNSERIALIZE_OBJPTR(parent);
27211308Santhony.gutierrez@amd.com    UNSERIALIZE_SCALAR(number);
27311308Santhony.gutierrez@amd.com
27411308Santhony.gutierrez@amd.com    link = parent->link[number];
27511308Santhony.gutierrez@amd.com
27611308Santhony.gutierrez@amd.com    packet = new EthPacketData(16384);
27711308Santhony.gutierrez@amd.com    packet->unserialize("packet", cp, section);
27811308Santhony.gutierrez@amd.com}
27911308Santhony.gutierrez@amd.com
28011308Santhony.gutierrez@amd.com
28111308Santhony.gutierrez@amd.comSerializable *
28211308Santhony.gutierrez@amd.comLinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
28311308Santhony.gutierrez@amd.com{
28411308Santhony.gutierrez@amd.com    return new LinkDelayEvent();
28511308Santhony.gutierrez@amd.com}
28611308Santhony.gutierrez@amd.com
28711308Santhony.gutierrez@amd.comREGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
28811308Santhony.gutierrez@amd.com
28911308Santhony.gutierrez@amd.comEtherLink *
29011308Santhony.gutierrez@amd.comEtherLinkParams::create()
29111308Santhony.gutierrez@amd.com{
29211308Santhony.gutierrez@amd.com    return new EtherLink(this);
29311308Santhony.gutierrez@amd.com}
29411308Santhony.gutierrez@amd.com