etherlink.cc revision 8232
1712SN/A/*
21762SN/A * Copyright (c) 2002-2005 The Regents of The University of Michigan
3712SN/A * All rights reserved.
4712SN/A *
5712SN/A * Redistribution and use in source and binary forms, with or without
6712SN/A * modification, are permitted provided that the following conditions are
7712SN/A * met: redistributions of source code must retain the above copyright
8712SN/A * notice, this list of conditions and the following disclaimer;
9712SN/A * redistributions in binary form must reproduce the above copyright
10712SN/A * notice, this list of conditions and the following disclaimer in the
11712SN/A * documentation and/or other materials provided with the distribution;
12712SN/A * neither the name of the copyright holders nor the names of its
13712SN/A * contributors may be used to endorse or promote products derived from
14712SN/A * this software without specific prior written permission.
15712SN/A *
16712SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17712SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18712SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19712SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20712SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21712SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22712SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23712SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24712SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25712SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26712SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665Ssaidi@eecs.umich.edu *
282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert
29712SN/A *          Ron Dreslinski
30712SN/A */
311354SN/A
321354SN/A/* @file
33712SN/A * Device module for modelling a fixed bandwidth full duplex ethernet link
348706Sandreas.hansson@arm.com */
35712SN/A
362680Sktlim@umich.edu#include <cmath>
37712SN/A#include <deque>
38712SN/A#include <string>
39712SN/A#include <vector>
40712SN/A
41712SN/A#include "base/random.hh"
42712SN/A#include "base/trace.hh"
43712SN/A#include "debug/Ethernet.hh"
445191Ssaidi@eecs.umich.edu#include "debug/EthernetData.hh"
452680Sktlim@umich.edu#include "dev/etherdump.hh"
46712SN/A#include "dev/etherint.hh"
475191Ssaidi@eecs.umich.edu#include "dev/etherlink.hh"
48712SN/A#include "dev/etherpkt.hh"
49712SN/A#include "params/EtherLink.hh"
505191Ssaidi@eecs.umich.edu#include "sim/core.hh"
515191Ssaidi@eecs.umich.edu#include "sim/serialize.hh"
525191Ssaidi@eecs.umich.edu#include "sim/system.hh"
535191Ssaidi@eecs.umich.edu
545191Ssaidi@eecs.umich.eduusing namespace std;
55712SN/A
56712SN/AEtherLink::EtherLink(const Params *p)
575191Ssaidi@eecs.umich.edu    : EtherObject(p)
585191Ssaidi@eecs.umich.edu{
595191Ssaidi@eecs.umich.edu    link[0] = new Link(name() + ".link0", this, 0, p->speed,
605191Ssaidi@eecs.umich.edu                       p->delay, p->delay_var, p->dump);
615191Ssaidi@eecs.umich.edu    link[1] = new Link(name() + ".link1", this, 1, p->speed,
62712SN/A                       p->delay, p->delay_var, p->dump);
635191Ssaidi@eecs.umich.edu
645191Ssaidi@eecs.umich.edu    interface[0] = new Interface(name() + ".int0", link[0], link[1]);
655191Ssaidi@eecs.umich.edu    interface[1] = new Interface(name() + ".int1", link[1], link[0]);
665191Ssaidi@eecs.umich.edu}
675191Ssaidi@eecs.umich.edu
685191Ssaidi@eecs.umich.edu
695191Ssaidi@eecs.umich.eduEtherLink::~EtherLink()
705191Ssaidi@eecs.umich.edu{
715191Ssaidi@eecs.umich.edu    delete link[0];
7214020Sgabeblack@google.com    delete link[1];
738852Sandreas.hansson@arm.com
745191Ssaidi@eecs.umich.edu    delete interface[0];
755191Ssaidi@eecs.umich.edu    delete interface[1];
765191Ssaidi@eecs.umich.edu}
775191Ssaidi@eecs.umich.edu
78712SN/AEtherInt*
79712SN/AEtherLink::getEthPort(const std::string &if_name, int idx)
80712SN/A{
81712SN/A    Interface *i;
825191Ssaidi@eecs.umich.edu    if (if_name == "int0")
835191Ssaidi@eecs.umich.edu        i = interface[0];
84712SN/A    else if (if_name == "int1")
855191Ssaidi@eecs.umich.edu        i = interface[1];
86712SN/A    else
87712SN/A        return NULL;
885191Ssaidi@eecs.umich.edu    if (i->getPeer())
895191Ssaidi@eecs.umich.edu        panic("interface already connected to\n");
90712SN/A
91712SN/A    return i;
925191Ssaidi@eecs.umich.edu}
93712SN/A
94712SN/A
95712SN/AEtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
96712SN/A    : EtherInt(name), txlink(tx)
975191Ssaidi@eecs.umich.edu{
985191Ssaidi@eecs.umich.edu    tx->setTxInt(this);
99712SN/A    rx->setRxInt(this);
100712SN/A}
1015191Ssaidi@eecs.umich.edu
102712SN/AEtherLink::Link::Link(const string &name, EtherLink *p, int num,
103712SN/A                      double rate, Tick delay, Tick delay_var, EtherDump *d)
104712SN/A    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
105712SN/A      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
106712SN/A      doneEvent(this)
1075191Ssaidi@eecs.umich.edu{ }
1085191Ssaidi@eecs.umich.edu
109712SN/Avoid
1105191Ssaidi@eecs.umich.eduEtherLink::serialize(ostream &os)
1115191Ssaidi@eecs.umich.edu{
1125191Ssaidi@eecs.umich.edu    link[0]->serialize("link0", os);
113712SN/A    link[1]->serialize("link1", os);
114712SN/A}
115712SN/A
116712SN/Avoid
117712SN/AEtherLink::unserialize(Checkpoint *cp, const string &section)
118712SN/A{
1195191Ssaidi@eecs.umich.edu    link[0]->unserialize("link0", cp, section);
120712SN/A    link[1]->unserialize("link1", cp, section);
121712SN/A}
1225191Ssaidi@eecs.umich.edu
1235191Ssaidi@eecs.umich.eduvoid
124712SN/AEtherLink::Link::txComplete(EthPacketPtr packet)
1255191Ssaidi@eecs.umich.edu{
126712SN/A    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
127712SN/A    DDUMP(EthernetData, packet->data, packet->length);
1285191Ssaidi@eecs.umich.edu    rxint->sendPacket(packet);
1295191Ssaidi@eecs.umich.edu}
130712SN/A
1315191Ssaidi@eecs.umich.educlass LinkDelayEvent : public Event
132712SN/A{
133712SN/A  protected:
134712SN/A    EtherLink::Link *link;
1351354SN/A    EthPacketPtr packet;
136
137  public:
138    // non-scheduling version for createForUnserialize()
139    LinkDelayEvent();
140    LinkDelayEvent(EtherLink::Link *link, EthPacketPtr pkt);
141
142    void process();
143
144    virtual void serialize(ostream &os);
145    virtual void unserialize(Checkpoint *cp, const string &section);
146    static Serializable *createForUnserialize(Checkpoint *cp,
147                                              const string &section);
148};
149
150void
151EtherLink::Link::txDone()
152{
153    if (dump)
154        dump->dump(packet);
155
156    if (linkDelay > 0) {
157        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
158        Event *event = new LinkDelayEvent(this, packet);
159        parent->schedule(event, curTick() + linkDelay);
160    } else {
161        txComplete(packet);
162    }
163
164    packet = 0;
165    assert(!busy());
166
167    txint->sendDone();
168}
169
170bool
171EtherLink::Link::transmit(EthPacketPtr pkt)
172{
173    if (busy()) {
174        DPRINTF(Ethernet, "packet not sent, link busy\n");
175        return false;
176    }
177
178    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
179    DDUMP(EthernetData, pkt->data, pkt->length);
180
181    packet = pkt;
182    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
183    if (delayVar != 0)
184        delay += random_mt.random<Tick>(0, delayVar);
185
186    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
187            delay, ticksPerByte);
188    parent->schedule(doneEvent, curTick() + delay);
189
190    return true;
191}
192
193void
194EtherLink::Link::serialize(const string &base, ostream &os)
195{
196    bool packet_exists = packet;
197    paramOut(os, base + ".packet_exists", packet_exists);
198    if (packet_exists)
199        packet->serialize(base + ".packet", os);
200
201    bool event_scheduled = doneEvent.scheduled();
202    paramOut(os, base + ".event_scheduled", event_scheduled);
203    if (event_scheduled) {
204        Tick event_time = doneEvent.when();
205        paramOut(os, base + ".event_time", event_time);
206    }
207
208}
209
210void
211EtherLink::Link::unserialize(const string &base, Checkpoint *cp,
212                             const string &section)
213{
214    bool packet_exists;
215    paramIn(cp, section, base + ".packet_exists", packet_exists);
216    if (packet_exists) {
217        packet = new EthPacketData(16384);
218        packet->unserialize(base + ".packet", cp, section);
219    }
220
221    bool event_scheduled;
222    paramIn(cp, section, base + ".event_scheduled", event_scheduled);
223    if (event_scheduled) {
224        Tick event_time;
225        paramIn(cp, section, base + ".event_time", event_time);
226        parent->schedule(doneEvent, event_time);
227    }
228}
229
230LinkDelayEvent::LinkDelayEvent()
231    : link(NULL)
232{
233    setFlags(AutoSerialize);
234    setFlags(AutoDelete);
235}
236
237LinkDelayEvent::LinkDelayEvent(EtherLink::Link *l, EthPacketPtr p)
238    : link(l), packet(p)
239{
240    setFlags(AutoSerialize);
241    setFlags(AutoDelete);
242}
243
244void
245LinkDelayEvent::process()
246{
247    link->txComplete(packet);
248}
249
250void
251LinkDelayEvent::serialize(ostream &os)
252{
253    paramOut(os, "type", string("LinkDelayEvent"));
254    Event::serialize(os);
255
256    EtherLink *parent = link->parent;
257    bool number = link->number;
258    SERIALIZE_OBJPTR(parent);
259    SERIALIZE_SCALAR(number);
260
261    packet->serialize("packet", os);
262}
263
264
265void
266LinkDelayEvent::unserialize(Checkpoint *cp, const string &section)
267{
268    Event::unserialize(cp, section);
269
270    EtherLink *parent;
271    bool number;
272    UNSERIALIZE_OBJPTR(parent);
273    UNSERIALIZE_SCALAR(number);
274
275    link = parent->link[number];
276
277    packet = new EthPacketData(16384);
278    packet->unserialize("packet", cp, section);
279}
280
281
282Serializable *
283LinkDelayEvent::createForUnserialize(Checkpoint *cp, const string &section)
284{
285    return new LinkDelayEvent();
286}
287
288REGISTER_SERIALIZEABLE("LinkDelayEvent", LinkDelayEvent)
289
290EtherLink *
291EtherLinkParams::create()
292{
293    return new EtherLink(this);
294}
295