sinic.cc revision 1817
1/*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <cstdio>
30#include <deque>
31#include <string>
32
33#include "base/inet.hh"
34#include "cpu/exec_context.hh"
35#include "cpu/intr_control.hh"
36#include "dev/etherlink.hh"
37#include "dev/sinic.hh"
38#include "dev/pciconfigall.hh"
39#include "mem/bus/bus.hh"
40#include "mem/bus/dma_interface.hh"
41#include "mem/bus/pio_interface.hh"
42#include "mem/bus/pio_interface_impl.hh"
43#include "mem/functional/memory_control.hh"
44#include "mem/functional/physical.hh"
45#include "sim/builder.hh"
46#include "sim/debug.hh"
47#include "sim/eventq.hh"
48#include "sim/host.hh"
49#include "sim/stats.hh"
50#include "targetarch/vtophys.hh"
51
52using namespace Net;
53
54namespace Sinic {
55
56const char *RxStateStrings[] =
57{
58    "rxIdle",
59    "rxFifoBlock",
60    "rxBeginCopy",
61    "rxCopy",
62    "rxCopyDone"
63};
64
65const char *TxStateStrings[] =
66{
67    "txIdle",
68    "txFifoBlock",
69    "txBeginCopy",
70    "txCopy",
71    "txCopyDone"
72};
73
74
75///////////////////////////////////////////////////////////////////////
76//
77// Sinic PCI Device
78//
79Base::Base(Params *p)
80    : PciDev(p), rxEnable(false), txEnable(false), cycleTime(p->cycle_time),
81      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
82      cpuPendingIntr(false), intrEvent(0), interface(NULL)
83{
84}
85
86Device::Device(Params *p)
87    : Base(p), plat(p->plat), physmem(p->physmem),
88      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
89      rxKickTick(0), txKickTick(0),
90      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
91      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
92      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
93{
94    reset();
95
96    if (p->io_bus) {
97        pioInterface = newPioInterface(p->name, p->hier, p->io_bus, this,
98                                       &Device::cacheAccess);
99
100        pioLatency = p->pio_latency * p->io_bus->clockRate;
101
102        if (p->payload_bus)
103            dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->io_bus,
104                                                 p->payload_bus, 1,
105                                                 p->dma_no_allocate);
106        else
107            dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->io_bus,
108                                                 p->io_bus, 1,
109                                                 p->dma_no_allocate);
110    } else if (p->payload_bus) {
111        pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this,
112                                       &Device::cacheAccess);
113
114        pioLatency = p->pio_latency * p->payload_bus->clockRate;
115
116        dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus,
117                                             p->payload_bus, 1,
118                                             p->dma_no_allocate);
119    }
120}
121
122Device::~Device()
123{}
124
125void
126Device::regStats()
127{
128    rxBytes
129        .name(name() + ".rxBytes")
130        .desc("Bytes Received")
131        .prereq(rxBytes)
132        ;
133
134    rxBandwidth
135        .name(name() + ".rxBandwidth")
136        .desc("Receive Bandwidth (bits/s)")
137        .precision(0)
138        .prereq(rxBytes)
139        ;
140
141    rxPackets
142        .name(name() + ".rxPackets")
143        .desc("Number of Packets Received")
144        .prereq(rxBytes)
145        ;
146
147    rxPacketRate
148        .name(name() + ".rxPPS")
149        .desc("Packet Reception Rate (packets/s)")
150        .precision(0)
151        .prereq(rxBytes)
152        ;
153
154    rxIpPackets
155        .name(name() + ".rxIpPackets")
156        .desc("Number of IP Packets Received")
157        .prereq(rxBytes)
158        ;
159
160    rxTcpPackets
161        .name(name() + ".rxTcpPackets")
162        .desc("Number of Packets Received")
163        .prereq(rxBytes)
164        ;
165
166    rxUdpPackets
167        .name(name() + ".rxUdpPackets")
168        .desc("Number of UDP Packets Received")
169        .prereq(rxBytes)
170        ;
171
172    rxIpChecksums
173        .name(name() + ".rxIpChecksums")
174        .desc("Number of rx IP Checksums done by device")
175        .precision(0)
176        .prereq(rxBytes)
177        ;
178
179    rxTcpChecksums
180        .name(name() + ".rxTcpChecksums")
181        .desc("Number of rx TCP Checksums done by device")
182        .precision(0)
183        .prereq(rxBytes)
184        ;
185
186    rxUdpChecksums
187        .name(name() + ".rxUdpChecksums")
188        .desc("Number of rx UDP Checksums done by device")
189        .precision(0)
190        .prereq(rxBytes)
191        ;
192
193    totBandwidth
194        .name(name() + ".totBandwidth")
195        .desc("Total Bandwidth (bits/s)")
196        .precision(0)
197        .prereq(totBytes)
198        ;
199
200    totPackets
201        .name(name() + ".totPackets")
202        .desc("Total Packets")
203        .precision(0)
204        .prereq(totBytes)
205        ;
206
207    totBytes
208        .name(name() + ".totBytes")
209        .desc("Total Bytes")
210        .precision(0)
211        .prereq(totBytes)
212        ;
213
214    totPacketRate
215        .name(name() + ".totPPS")
216        .desc("Total Tranmission Rate (packets/s)")
217        .precision(0)
218        .prereq(totBytes)
219        ;
220
221    txBytes
222        .name(name() + ".txBytes")
223        .desc("Bytes Transmitted")
224        .prereq(txBytes)
225        ;
226
227    txBandwidth
228        .name(name() + ".txBandwidth")
229        .desc("Transmit Bandwidth (bits/s)")
230        .precision(0)
231        .prereq(txBytes)
232        ;
233
234    txPackets
235        .name(name() + ".txPackets")
236        .desc("Number of Packets Transmitted")
237        .prereq(txBytes)
238        ;
239
240    txPacketRate
241        .name(name() + ".txPPS")
242        .desc("Packet Tranmission Rate (packets/s)")
243        .precision(0)
244        .prereq(txBytes)
245        ;
246
247    txIpPackets
248        .name(name() + ".txIpPackets")
249        .desc("Number of IP Packets Transmitted")
250        .prereq(txBytes)
251        ;
252
253    txTcpPackets
254        .name(name() + ".txTcpPackets")
255        .desc("Number of TCP Packets Transmitted")
256        .prereq(txBytes)
257        ;
258
259    txUdpPackets
260        .name(name() + ".txUdpPackets")
261        .desc("Number of Packets Transmitted")
262        .prereq(txBytes)
263        ;
264
265    txIpChecksums
266        .name(name() + ".txIpChecksums")
267        .desc("Number of tx IP Checksums done by device")
268        .precision(0)
269        .prereq(txBytes)
270        ;
271
272    txTcpChecksums
273        .name(name() + ".txTcpChecksums")
274        .desc("Number of tx TCP Checksums done by device")
275        .precision(0)
276        .prereq(txBytes)
277        ;
278
279    txUdpChecksums
280        .name(name() + ".txUdpChecksums")
281        .desc("Number of tx UDP Checksums done by device")
282        .precision(0)
283        .prereq(txBytes)
284        ;
285
286    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
287    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
288    totBandwidth = txBandwidth + rxBandwidth;
289    totBytes = txBytes + rxBytes;
290    totPackets = txPackets + rxPackets;
291    txPacketRate = txPackets / simSeconds;
292    rxPacketRate = rxPackets / simSeconds;
293}
294
295/**
296 * This is to write to the PCI general configuration registers
297 */
298void
299Device::writeConfig(int offset, int size, const uint8_t *data)
300{
301    switch (offset) {
302      case PCI0_BASE_ADDR0:
303        // Need to catch writes to BARs to update the PIO interface
304        PciDev::writeConfig(offset, size, data);
305        if (BARAddrs[0] != 0) {
306            if (pioInterface)
307                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
308
309            BARAddrs[0] &= EV5::PAddrUncachedMask;
310        }
311        break;
312
313      default:
314        PciDev::writeConfig(offset, size, data);
315    }
316}
317
318/**
319 * This reads the device registers, which are detailed in the NS83820
320 * spec sheet
321 */
322Fault
323Device::read(MemReqPtr &req, uint8_t *data)
324{
325    assert(config.command & PCI_CMD_MSE);
326
327    //The mask is to give you only the offset into the device register file
328    Addr daddr = req->paddr & 0xfff;
329
330    if (Regs::regSize(daddr) == 0)
331        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
332              daddr, req->paddr, req->vaddr, req->size);
333
334    if (req->size != Regs::regSize(daddr))
335        panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
336              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
337
338    DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n",
339            Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
340
341    uint32_t &reg32 = *(uint32_t *)data;
342    uint64_t &reg64 = *(uint64_t *)data;
343
344    switch (daddr) {
345      case Regs::Config:
346        reg32 = regs.Config;
347        break;
348
349      case Regs::RxMaxCopy:
350        reg32 = regs.RxMaxCopy;
351        break;
352
353      case Regs::TxMaxCopy:
354        reg32 = regs.TxMaxCopy;
355        break;
356
357      case Regs::RxThreshold:
358        reg32 = regs.RxThreshold;
359        break;
360
361      case Regs::TxThreshold:
362        reg32 = regs.TxThreshold;
363        break;
364
365      case Regs::IntrStatus:
366        reg32 = regs.IntrStatus;
367        devIntrClear();
368        break;
369
370      case Regs::IntrMask:
371        reg32 = regs.IntrMask;
372        break;
373
374      case Regs::RxData:
375        reg64 = regs.RxData;
376        break;
377
378      case Regs::RxDone:
379      case Regs::RxWait:
380        reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
381                                         min(rxFifo.packets(), 255));
382        break;
383
384      case Regs::TxData:
385        reg64 = regs.TxData;
386        break;
387
388      case Regs::TxDone:
389      case Regs::TxWait:
390        reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
391                                         min(txFifo.packets(), 255));
392        break;
393
394      case Regs::HwAddr:
395        reg64 = params()->eaddr;
396        break;
397
398      default:
399        panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d",
400              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
401    }
402
403    DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
404            Regs::regSize(daddr) == 4 ? reg32 : reg64);
405
406    return No_Fault;
407}
408
409Fault
410Device::write(MemReqPtr &req, const uint8_t *data)
411{
412    assert(config.command & PCI_CMD_MSE);
413    Addr daddr = req->paddr & 0xfff;
414
415    if (Regs::regSize(daddr) == 0)
416        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
417              daddr, req->paddr, req->vaddr, req->size);
418
419    if (req->size != Regs::regSize(daddr))
420        panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d",
421              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
422
423    uint32_t reg32 = *(uint32_t *)data;
424    uint64_t reg64 = *(uint64_t *)data;
425
426    DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n",
427            Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64,
428            daddr, req->paddr, req->vaddr, req->size);
429
430
431    switch (daddr) {
432      case Regs::Config:
433        changeConfig(reg32);
434        break;
435
436      case Regs::RxThreshold:
437        regs.RxThreshold = reg32;
438        break;
439
440      case Regs::TxThreshold:
441        regs.TxThreshold = reg32;
442        break;
443
444      case Regs::IntrMask:
445        devIntrChangeMask(reg32);
446        break;
447
448      case Regs::RxData:
449        if (rxState != rxIdle)
450            panic("receive machine busy with another request!");
451
452        regs.RxDone = 0;
453        regs.RxData = reg64;
454        if (rxEnable) {
455            rxState = rxFifoBlock;
456            rxKick();
457        }
458        break;
459
460      case Regs::TxData:
461        if (txState != txIdle)
462            panic("transmit machine busy with another request!");
463
464        regs.TxDone = 0;
465        regs.TxData = reg64;
466        if (txEnable) {
467            txState = txFifoBlock;
468            txKick();
469        }
470        break;
471
472      default:
473        panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d",
474              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
475    }
476
477    return No_Fault;
478}
479
480void
481Device::devIntrPost(uint32_t interrupts)
482{
483    if ((interrupts & Regs::Intr_Res))
484        panic("Cannot set a reserved interrupt");
485
486    regs.IntrStatus |= interrupts;
487
488    DPRINTF(EthernetIntr,
489            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
490            interrupts, regs.IntrStatus, regs.IntrMask);
491
492    if ((regs.IntrStatus & regs.IntrMask)) {
493        Tick when = curTick;
494        if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0)
495            when += intrDelay;
496        cpuIntrPost(when);
497    }
498}
499
500void
501Device::devIntrClear(uint32_t interrupts)
502{
503    if ((interrupts & Regs::Intr_Res))
504        panic("Cannot clear a reserved interrupt");
505
506    regs.IntrStatus &= ~interrupts;
507
508    DPRINTF(EthernetIntr,
509            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
510            interrupts, regs.IntrStatus, regs.IntrMask);
511
512    if (!(regs.IntrStatus & regs.IntrMask))
513        cpuIntrClear();
514}
515
516void
517Device::devIntrChangeMask(uint32_t newmask)
518{
519    if (regs.IntrMask == newmask)
520        return;
521
522    regs.IntrMask = newmask;
523
524    DPRINTF(EthernetIntr,
525            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
526            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
527
528    if (regs.IntrStatus & regs.IntrMask)
529        cpuIntrPost(curTick);
530    else
531        cpuIntrClear();
532}
533
534void
535Base::cpuIntrPost(Tick when)
536{
537    // If the interrupt you want to post is later than an interrupt
538    // already scheduled, just let it post in the coming one and don't
539    // schedule another.
540    // HOWEVER, must be sure that the scheduled intrTick is in the
541    // future (this was formerly the source of a bug)
542    /**
543     * @todo this warning should be removed and the intrTick code should
544     * be fixed.
545     */
546    assert(when >= curTick);
547    assert(intrTick >= curTick || intrTick == 0);
548    if (!cpuIntrEnable) {
549        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
550                intrTick);
551        return;
552    }
553
554    if (when > intrTick && intrTick != 0) {
555        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
556                intrTick);
557        return;
558    }
559
560    intrTick = when;
561    if (intrTick < curTick) {
562        debug_break();
563        intrTick = curTick;
564    }
565
566    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
567            intrTick);
568
569    if (intrEvent)
570        intrEvent->squash();
571    intrEvent = new IntrEvent(this, true);
572    intrEvent->schedule(intrTick);
573}
574
575void
576Base::cpuInterrupt()
577{
578    assert(intrTick == curTick);
579
580    // Whether or not there's a pending interrupt, we don't care about
581    // it anymore
582    intrEvent = 0;
583    intrTick = 0;
584
585    // Don't send an interrupt if there's already one
586    if (cpuPendingIntr) {
587        DPRINTF(EthernetIntr,
588                "would send an interrupt now, but there's already pending\n");
589    } else {
590        // Send interrupt
591        cpuPendingIntr = true;
592
593        DPRINTF(EthernetIntr, "posting interrupt\n");
594        intrPost();
595    }
596}
597
598void
599Base::cpuIntrClear()
600{
601    if (!cpuPendingIntr)
602        return;
603
604    if (intrEvent) {
605        intrEvent->squash();
606        intrEvent = 0;
607    }
608
609    intrTick = 0;
610
611    cpuPendingIntr = false;
612
613    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
614    intrClear();
615}
616
617bool
618Base::cpuIntrPending() const
619{ return cpuPendingIntr; }
620
621void
622Device::changeConfig(uint32_t newconf)
623{
624    uint32_t changed = regs.Config ^ newconf;
625    if (!changed)
626        return;
627
628    regs.Config = newconf;
629
630    if ((changed & Regs::Config_Reset)) {
631        assert(regs.Config & Regs::Config_Reset);
632        reset();
633        regs.Config &= ~Regs::Config_Reset;
634    }
635
636    if ((changed & Regs::Config_IntEn)) {
637        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
638        if (cpuIntrEnable) {
639            if (regs.IntrStatus & regs.IntrMask)
640                cpuIntrPost(curTick);
641        } else {
642            cpuIntrClear();
643        }
644    }
645
646    if ((changed & Regs::Config_TxEn)) {
647        txEnable = regs.Config & Regs::Config_TxEn;
648        if (txEnable)
649            txKick();
650    }
651
652    if ((changed & Regs::Config_RxEn)) {
653        rxEnable = regs.Config & Regs::Config_RxEn;
654        if (rxEnable)
655            rxKick();
656    }
657}
658
659void
660Device::reset()
661{
662    using namespace Regs;
663    memset(&regs, 0, sizeof(regs));
664    regs.RxMaxCopy = params()->rx_max_copy;
665    regs.TxMaxCopy = params()->tx_max_copy;
666    regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData;
667
668    rxState = rxIdle;
669    txState = txIdle;
670
671    rxFifo.clear();
672    txFifo.clear();
673}
674
675void
676Device::rxDmaCopy()
677{
678    assert(rxState == rxCopy);
679    rxState = rxCopyDone;
680    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
681    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
682            rxDmaAddr, rxDmaLen);
683    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
684}
685
686void
687Device::rxDmaDone()
688{
689    rxDmaCopy();
690    rxKick();
691}
692
693void
694Device::rxKick()
695{
696    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
697            RxStateStrings[rxState], rxFifo.size());
698
699    if (rxKickTick > curTick) {
700        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
701                rxKickTick);
702        return;
703    }
704
705  next:
706    switch (rxState) {
707      case rxIdle:
708        if (rxPioRequest) {
709            pioInterface->respond(rxPioRequest, curTick);
710            rxPioRequest = 0;
711        }
712        goto exit;
713
714      case rxFifoBlock:
715        if (rxPacket) {
716            rxState = rxBeginCopy;
717            break;
718        }
719
720        if (rxFifo.empty()) {
721            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
722            goto exit;
723        }
724
725        // Grab a new packet from the fifo.
726        rxPacket = rxFifo.front();
727        rxPacketBufPtr = rxPacket->data;
728        rxPktBytes = rxPacket->length;
729        assert(rxPktBytes);
730
731        rxDoneData = 0;
732        /* scope for variables */ {
733            IpPtr ip(rxPacket);
734            if (ip) {
735                rxDoneData |= Regs::RxDone_IpPacket;
736                rxIpChecksums++;
737                if (cksum(ip) != 0) {
738                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
739                    rxDoneData |= Regs::RxDone_IpError;
740                }
741                TcpPtr tcp(ip);
742                UdpPtr udp(ip);
743                if (tcp) {
744                    rxDoneData |= Regs::RxDone_TcpPacket;
745                    rxTcpChecksums++;
746                    if (cksum(tcp) != 0) {
747                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
748                        rxDoneData |= Regs::RxDone_TcpError;
749                    }
750                } else if (udp) {
751                    rxDoneData |= Regs::RxDone_UdpPacket;
752                    rxUdpChecksums++;
753                    if (cksum(udp) != 0) {
754                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
755                        rxDoneData |= Regs::RxDone_UdpError;
756                    }
757                }
758            }
759        }
760        rxState = rxBeginCopy;
761        break;
762
763      case rxBeginCopy:
764        rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData));
765        rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes);
766        rxDmaData = rxPacketBufPtr;
767
768        if (dmaInterface) {
769            if (!dmaInterface->busy()) {
770                dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
771                                    curTick, &rxDmaEvent, true);
772                rxState = rxCopy;
773            }
774            goto exit;
775        }
776
777        rxState = rxCopy;
778        if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
779            Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
780            Tick start = curTick + dmaWriteDelay + factor;
781            rxDmaEvent.schedule(start);
782            goto exit;
783        }
784
785        rxDmaCopy();
786        break;
787
788      case rxCopy:
789        DPRINTF(EthernetSM, "receive machine still copying\n");
790        goto exit;
791
792      case rxCopyDone:
793        regs.RxDone = rxDoneData | rxDmaLen;
794
795        if (rxPktBytes == rxDmaLen) {
796            rxPacket = NULL;
797            rxFifo.pop();
798        } else {
799            regs.RxDone |= Regs::RxDone_More;
800            rxPktBytes -= rxDmaLen;
801            rxPacketBufPtr += rxDmaLen;
802        }
803
804        regs.RxDone |= Regs::RxDone_Complete;
805        devIntrPost(Regs::Intr_RxData);
806        rxState = rxIdle;
807        break;
808
809      default:
810        panic("Invalid rxState!");
811    }
812
813    DPRINTF(EthernetSM, "entering next rxState=%s\n",
814            RxStateStrings[rxState]);
815
816    goto next;
817
818  exit:
819    /**
820     * @todo do we want to schedule a future kick?
821     */
822    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
823            RxStateStrings[rxState]);
824}
825
826void
827Device::txDmaCopy()
828{
829    assert(txState == txCopy);
830    txState = txCopyDone;
831    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
832    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
833            txDmaAddr, txDmaLen);
834    DDUMP(EthernetDMA, txDmaData, txDmaLen);
835}
836
837void
838Device::txDmaDone()
839{
840    txDmaCopy();
841    txKick();
842}
843
844void
845Device::transmit()
846{
847    if (txFifo.empty()) {
848        DPRINTF(Ethernet, "nothing to transmit\n");
849        return;
850    }
851
852    PacketPtr packet = txFifo.front();
853    if (!interface->sendPacket(packet)) {
854        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
855                txFifo.avail());
856        goto reschedule;
857    }
858
859    txFifo.pop();
860
861#if TRACING_ON
862    if (DTRACE(Ethernet)) {
863        IpPtr ip(packet);
864        if (ip) {
865            DPRINTF(Ethernet, "ID is %d\n", ip->id());
866            TcpPtr tcp(ip);
867            if (tcp) {
868                DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
869                        tcp->sport(), tcp->dport());
870            }
871        }
872    }
873#endif
874
875    DDUMP(Ethernet, packet->data, packet->length);
876    txBytes += packet->length;
877    txPackets++;
878
879    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
880            txFifo.avail());
881
882    if (txFifo.size() <= params()->tx_fifo_threshold)
883        devIntrPost(Regs::Intr_TxFifo);
884
885    devIntrPost(Regs::Intr_TxDone);
886
887  reschedule:
888   if (!txFifo.empty() && !txEvent.scheduled()) {
889       DPRINTF(Ethernet, "reschedule transmit\n");
890       txEvent.schedule(curTick + retryTime);
891   }
892}
893
894void
895Device::txKick()
896{
897    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
898            TxStateStrings[txState], txFifo.size());
899
900    if (txKickTick > curTick) {
901        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
902                txKickTick);
903        return;
904    }
905
906  next:
907    switch (txState) {
908      case txIdle:
909        if (txPioRequest) {
910            pioInterface->respond(txPioRequest, curTick + pioLatency);
911            txPioRequest = 0;
912        }
913        goto exit;
914
915      case txFifoBlock:
916        if (!txPacket) {
917            // Grab a new packet from the fifo.
918            txPacket = new PacketData(16384);
919            txPacketBufPtr = txPacket->data;
920        }
921
922        if (txFifo.avail() - txPacket->length <
923            Regs::get_TxData_Len(regs.TxData)) {
924            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
925            goto exit;
926        }
927
928        txState = txBeginCopy;
929        break;
930
931      case txBeginCopy:
932        txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData));
933        txDmaLen = Regs::get_TxData_Len(regs.TxData);
934        txDmaData = txPacketBufPtr;
935
936        if (dmaInterface) {
937            if (!dmaInterface->busy()) {
938                dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
939                                    curTick, &txDmaEvent, true);
940                txState = txCopy;
941            }
942
943            goto exit;
944        }
945
946        txState = txCopy;
947        if (dmaReadDelay != 0 || dmaReadFactor != 0) {
948            Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
949            Tick start = curTick + dmaReadDelay + factor;
950            txDmaEvent.schedule(start);
951            goto exit;
952        }
953
954        txDmaCopy();
955        break;
956
957      case txCopy:
958        DPRINTF(EthernetSM, "transmit machine still copying\n");
959        goto exit;
960
961      case txCopyDone:
962        txPacket->length += txDmaLen;
963        if ((regs.TxData & Regs::TxData_More)) {
964            txPacketBufPtr += txDmaLen;
965        } else {
966            assert(txPacket->length <= txFifo.avail());
967            if ((regs.TxData & Regs::TxData_Checksum)) {
968                IpPtr ip(txPacket);
969                if (ip) {
970                    TcpPtr tcp(ip);
971                    if (tcp) {
972                        tcp->sum(0);
973                        tcp->sum(cksum(tcp));
974                        txTcpChecksums++;
975                    }
976
977                    UdpPtr udp(ip);
978                    if (udp) {
979                        udp->sum(0);
980                        udp->sum(cksum(udp));
981                        txUdpChecksums++;
982                    }
983
984                    ip->sum(0);
985                    ip->sum(cksum(ip));
986                    txIpChecksums++;
987                }
988            }
989            txFifo.push(txPacket);
990            txPacket = 0;
991            transmit();
992        }
993
994        regs.TxDone = txDmaLen | Regs::TxDone_Complete;
995        devIntrPost(Regs::Intr_TxData);
996        txState = txIdle;
997        break;
998
999      default:
1000        panic("Invalid txState!");
1001    }
1002
1003    DPRINTF(EthernetSM, "entering next txState=%s\n",
1004            TxStateStrings[txState]);
1005
1006    goto next;
1007
1008  exit:
1009    /**
1010     * @todo do we want to schedule a future kick?
1011     */
1012    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1013            TxStateStrings[txState]);
1014}
1015
1016void
1017Device::transferDone()
1018{
1019    if (txFifo.empty()) {
1020        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1021        return;
1022    }
1023
1024    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1025
1026    if (txEvent.scheduled())
1027        txEvent.reschedule(curTick + cycles(1));
1028    else
1029        txEvent.schedule(curTick + cycles(1));
1030}
1031
1032bool
1033Device::rxFilter(const PacketPtr &packet)
1034{
1035    if (!Regs::get_Config_Filter(regs.Config))
1036        return false;
1037
1038    panic("receive filter not implemented\n");
1039    bool drop = true;
1040
1041#if 0
1042    string type;
1043
1044    EthHdr *eth = packet->eth();
1045    if (eth->unicast()) {
1046        // If we're accepting all unicast addresses
1047        if (acceptUnicast)
1048            drop = false;
1049
1050        // If we make a perfect match
1051        if (acceptPerfect && params->eaddr == eth.dst())
1052            drop = false;
1053
1054        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1055            drop = false;
1056
1057    } else if (eth->broadcast()) {
1058        // if we're accepting broadcasts
1059        if (acceptBroadcast)
1060            drop = false;
1061
1062    } else if (eth->multicast()) {
1063        // if we're accepting all multicasts
1064        if (acceptMulticast)
1065            drop = false;
1066
1067    }
1068
1069    if (drop) {
1070        DPRINTF(Ethernet, "rxFilter drop\n");
1071        DDUMP(EthernetData, packet->data, packet->length);
1072    }
1073#endif
1074    return drop;
1075}
1076
1077bool
1078Device::recvPacket(PacketPtr packet)
1079{
1080    rxBytes += packet->length;
1081    rxPackets++;
1082
1083    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1084            rxFifo.avail());
1085
1086    if (!rxEnable) {
1087        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1088        interface->recvDone();
1089        return true;
1090    }
1091
1092    if (rxFilter(packet)) {
1093        DPRINTF(Ethernet, "packet filtered...dropped\n");
1094        interface->recvDone();
1095        return true;
1096    }
1097
1098    if (rxFifo.size() >= params()->rx_fifo_threshold)
1099        devIntrPost(Regs::Intr_RxFifo);
1100
1101    if (!rxFifo.push(packet)) {
1102        DPRINTF(Ethernet,
1103                "packet will not fit in receive buffer...packet dropped\n");
1104        return false;
1105    }
1106
1107    interface->recvDone();
1108    devIntrPost(Regs::Intr_RxDone);
1109    rxKick();
1110    return true;
1111}
1112
1113//=====================================================================
1114//
1115//
1116void
1117Base::serialize(ostream &os)
1118{
1119    // Serialize the PciDev base class
1120    PciDev::serialize(os);
1121
1122    SERIALIZE_SCALAR(rxEnable);
1123    SERIALIZE_SCALAR(txEnable);
1124    SERIALIZE_SCALAR(cpuIntrEnable);
1125
1126    /*
1127     * Keep track of pending interrupt status.
1128     */
1129    SERIALIZE_SCALAR(intrTick);
1130    SERIALIZE_SCALAR(cpuPendingIntr);
1131    Tick intrEventTick = 0;
1132    if (intrEvent)
1133        intrEventTick = intrEvent->when();
1134    SERIALIZE_SCALAR(intrEventTick);
1135}
1136
1137void
1138Base::unserialize(Checkpoint *cp, const std::string &section)
1139{
1140    // Unserialize the PciDev base class
1141    PciDev::unserialize(cp, section);
1142
1143    UNSERIALIZE_SCALAR(rxEnable);
1144    UNSERIALIZE_SCALAR(txEnable);
1145    UNSERIALIZE_SCALAR(cpuIntrEnable);
1146
1147    /*
1148     * Keep track of pending interrupt status.
1149     */
1150    UNSERIALIZE_SCALAR(intrTick);
1151    UNSERIALIZE_SCALAR(cpuPendingIntr);
1152    Tick intrEventTick;
1153    UNSERIALIZE_SCALAR(intrEventTick);
1154    if (intrEventTick) {
1155        intrEvent = new IntrEvent(this, true);
1156        intrEvent->schedule(intrEventTick);
1157    }
1158}
1159
1160void
1161Device::serialize(ostream &os)
1162{
1163    // Serialize the PciDev base class
1164    Base::serialize(os);
1165
1166    if (rxDmaEvent.scheduled())
1167        rxDmaCopy();
1168
1169    if (txDmaEvent.scheduled())
1170        txDmaCopy();
1171
1172    /*
1173     * Serialize the device registers
1174     */
1175    SERIALIZE_SCALAR(regs.Config);
1176    SERIALIZE_SCALAR(regs.RxMaxCopy);
1177    SERIALIZE_SCALAR(regs.TxMaxCopy);
1178    SERIALIZE_SCALAR(regs.RxThreshold);
1179    SERIALIZE_SCALAR(regs.TxThreshold);
1180    SERIALIZE_SCALAR(regs.IntrStatus);
1181    SERIALIZE_SCALAR(regs.IntrMask);
1182    SERIALIZE_SCALAR(regs.RxData);
1183    SERIALIZE_SCALAR(regs.RxDone);
1184    SERIALIZE_SCALAR(regs.TxData);
1185    SERIALIZE_SCALAR(regs.TxDone);
1186
1187    /*
1188     * Serialize rx state machine
1189     */
1190    int rxState = this->rxState;
1191    SERIALIZE_SCALAR(rxState);
1192    rxFifo.serialize("rxFifo", os);
1193    bool rxPacketExists = rxPacket;
1194    SERIALIZE_SCALAR(rxPacketExists);
1195    if (rxPacketExists) {
1196        rxPacket->serialize("rxPacket", os);
1197        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
1198        SERIALIZE_SCALAR(rxPktBufPtr);
1199        SERIALIZE_SCALAR(rxPktBytes);
1200    }
1201    SERIALIZE_SCALAR(rxDoneData);
1202
1203    /*
1204     * Serialize tx state machine
1205     */
1206    int txState = this->txState;
1207    SERIALIZE_SCALAR(txState);
1208    txFifo.serialize("txFifo", os);
1209    bool txPacketExists = txPacket;
1210    SERIALIZE_SCALAR(txPacketExists);
1211    if (txPacketExists) {
1212        txPacket->serialize("txPacket", os);
1213        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
1214        SERIALIZE_SCALAR(txPktBufPtr);
1215        SERIALIZE_SCALAR(txPktBytes);
1216    }
1217
1218    /*
1219     * If there's a pending transmit, store the time so we can
1220     * reschedule it later
1221     */
1222    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1223    SERIALIZE_SCALAR(transmitTick);
1224}
1225
1226void
1227Device::unserialize(Checkpoint *cp, const std::string &section)
1228{
1229    // Unserialize the PciDev base class
1230    Base::unserialize(cp, section);
1231
1232    /*
1233     * Unserialize the device registers
1234     */
1235    UNSERIALIZE_SCALAR(regs.Config);
1236    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1237    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1238    UNSERIALIZE_SCALAR(regs.RxThreshold);
1239    UNSERIALIZE_SCALAR(regs.TxThreshold);
1240    UNSERIALIZE_SCALAR(regs.IntrStatus);
1241    UNSERIALIZE_SCALAR(regs.IntrMask);
1242    UNSERIALIZE_SCALAR(regs.RxData);
1243    UNSERIALIZE_SCALAR(regs.RxDone);
1244    UNSERIALIZE_SCALAR(regs.TxData);
1245    UNSERIALIZE_SCALAR(regs.TxDone);
1246
1247    /*
1248     * Unserialize rx state machine
1249     */
1250    int rxState;
1251    UNSERIALIZE_SCALAR(rxState);
1252    this->rxState = (RxState) rxState;
1253    rxFifo.unserialize("rxFifo", cp, section);
1254    bool rxPacketExists;
1255    UNSERIALIZE_SCALAR(rxPacketExists);
1256    rxPacket = 0;
1257    if (rxPacketExists) {
1258        rxPacket = new PacketData(16384);
1259        rxPacket->unserialize("rxPacket", cp, section);
1260        uint32_t rxPktBufPtr;
1261        UNSERIALIZE_SCALAR(rxPktBufPtr);
1262        this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
1263        UNSERIALIZE_SCALAR(rxPktBytes);
1264    }
1265    UNSERIALIZE_SCALAR(rxDoneData);
1266
1267    /*
1268     * Unserialize tx state machine
1269     */
1270    int txState;
1271    UNSERIALIZE_SCALAR(txState);
1272    this->txState = (TxState) txState;
1273    txFifo.unserialize("txFifo", cp, section);
1274    bool txPacketExists;
1275    UNSERIALIZE_SCALAR(txPacketExists);
1276    txPacket = 0;
1277    if (txPacketExists) {
1278        txPacket = new PacketData(16384);
1279        txPacket->unserialize("txPacket", cp, section);
1280        uint32_t txPktBufPtr;
1281        UNSERIALIZE_SCALAR(txPktBufPtr);
1282        this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
1283        UNSERIALIZE_SCALAR(txPktBytes);
1284    }
1285
1286    /*
1287     * If there's a pending transmit, reschedule it now
1288     */
1289    Tick transmitTick;
1290    UNSERIALIZE_SCALAR(transmitTick);
1291    if (transmitTick)
1292        txEvent.schedule(curTick + transmitTick);
1293
1294    /*
1295     * re-add addrRanges to bus bridges
1296     */
1297    if (pioInterface)
1298        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
1299}
1300
1301Tick
1302Device::cacheAccess(MemReqPtr &req)
1303{
1304    //The mask is to give you only the offset into the device register file
1305    Addr daddr = req->paddr - addr;
1306
1307    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
1308            req->paddr, daddr);
1309
1310    Tick when = curTick + pioLatency;
1311
1312    switch (daddr) {
1313      case Regs::RxDone:
1314        if (rxState != rxIdle) {
1315            rxPioRequest = req;
1316            when = 0;
1317        }
1318        break;
1319
1320      case Regs::TxDone:
1321        if (txState != txIdle) {
1322            txPioRequest = req;
1323            when = 0;
1324        }
1325        break;
1326    }
1327
1328    return when;
1329}
1330
1331BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
1332
1333    SimObjectParam<EtherInt *> peer;
1334    SimObjectParam<Device *> device;
1335
1336END_DECLARE_SIM_OBJECT_PARAMS(Interface)
1337
1338BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
1339
1340    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1341    INIT_PARAM(device, "Ethernet device of this interface")
1342
1343END_INIT_SIM_OBJECT_PARAMS(Interface)
1344
1345CREATE_SIM_OBJECT(Interface)
1346{
1347    Interface *dev_int = new Interface(getInstanceName(), device);
1348
1349    EtherInt *p = (EtherInt *)peer;
1350    if (p) {
1351        dev_int->setPeer(p);
1352        p->setPeer(dev_int);
1353    }
1354
1355    return dev_int;
1356}
1357
1358REGISTER_SIM_OBJECT("SinicInt", Interface)
1359
1360
1361BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
1362
1363    Param<Addr> addr;
1364    Param<Tick> cycle_time;
1365    Param<Tick> tx_delay;
1366    Param<Tick> rx_delay;
1367    Param<Tick> intr_delay;
1368    SimObjectParam<MemoryController *> mmu;
1369    SimObjectParam<PhysicalMemory *> physmem;
1370    Param<bool> rx_filter;
1371    Param<string> hardware_address;
1372    SimObjectParam<Bus*> io_bus;
1373    SimObjectParam<Bus*> payload_bus;
1374    SimObjectParam<HierParams *> hier;
1375    Param<Tick> pio_latency;
1376    SimObjectParam<PciConfigAll *> configspace;
1377    SimObjectParam<PciConfigData *> configdata;
1378    SimObjectParam<Platform *> platform;
1379    Param<uint32_t> pci_bus;
1380    Param<uint32_t> pci_dev;
1381    Param<uint32_t> pci_func;
1382    Param<uint32_t> rx_max_copy;
1383    Param<uint32_t> tx_max_copy;
1384    Param<uint32_t> rx_fifo_size;
1385    Param<uint32_t> tx_fifo_size;
1386    Param<uint32_t> rx_fifo_threshold;
1387    Param<uint32_t> tx_fifo_threshold;
1388    Param<Tick> dma_read_delay;
1389    Param<Tick> dma_read_factor;
1390    Param<Tick> dma_write_delay;
1391    Param<Tick> dma_write_factor;
1392    Param<bool> dma_no_allocate;
1393
1394END_DECLARE_SIM_OBJECT_PARAMS(Device)
1395
1396BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1397
1398    INIT_PARAM(addr, "Device Address"),
1399    INIT_PARAM(cycle_time, "State machine cycle time"),
1400    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
1401    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
1402    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
1403    INIT_PARAM(mmu, "Memory Controller"),
1404    INIT_PARAM(physmem, "Physical Memory"),
1405    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
1406    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
1407                    "00:99:00:00:00:01"),
1408    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to for headers", NULL),
1409    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
1410    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
1411    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
1412    INIT_PARAM(configspace, "PCI Configspace"),
1413    INIT_PARAM(configdata, "PCI Config data"),
1414    INIT_PARAM(platform, "Platform"),
1415    INIT_PARAM(pci_bus, "PCI bus"),
1416    INIT_PARAM(pci_dev, "PCI device number"),
1417    INIT_PARAM(pci_func, "PCI function code"),
1418    INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024),
1419    INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024),
1420    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024),
1421    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024),
1422    INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024),
1423    INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024),
1424    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
1425    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
1426    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
1427    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
1428    INIT_PARAM_DFLT(dma_no_allocate, "Should we allocat on read in cache", true)
1429
1430END_INIT_SIM_OBJECT_PARAMS(Device)
1431
1432
1433CREATE_SIM_OBJECT(Device)
1434{
1435    Device::Params *params = new Device::Params;
1436    params->name = getInstanceName();
1437    params->intr_delay = intr_delay;
1438    params->physmem = physmem;
1439    params->cycle_time = cycle_time;
1440    params->tx_delay = tx_delay;
1441    params->rx_delay = rx_delay;
1442    params->mmu = mmu;
1443    params->hier = hier;
1444    params->io_bus = io_bus;
1445    params->payload_bus = payload_bus;
1446    params->pio_latency = pio_latency;
1447    params->configSpace = configspace;
1448    params->configData = configdata;
1449    params->plat = platform;
1450    params->busNum = pci_bus;
1451    params->deviceNum = pci_dev;
1452    params->functionNum = pci_func;
1453    params->rx_filter = rx_filter;
1454    params->eaddr = hardware_address;
1455    params->rx_max_copy = rx_max_copy;
1456    params->tx_max_copy = tx_max_copy;
1457    params->rx_fifo_size = rx_fifo_size;
1458    params->tx_fifo_size = tx_fifo_size;
1459    params->rx_fifo_threshold = rx_fifo_threshold;
1460    params->tx_fifo_threshold = tx_fifo_threshold;
1461    params->dma_read_delay = dma_read_delay;
1462    params->dma_read_factor = dma_read_factor;
1463    params->dma_write_delay = dma_write_delay;
1464    params->dma_write_factor = dma_write_factor;
1465    params->dma_no_allocate = dma_no_allocate;
1466    return new Device(params);
1467}
1468
1469REGISTER_SIM_OBJECT("Sinic", Device)
1470
1471/* namespace Sinic */ }
1472