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