sinic.cc revision 1634
16019Shines@cs.fsu.edu/*
26019Shines@cs.fsu.edu * Copyright (c) 2004 The Regents of The University of Michigan
37178Sgblack@eecs.umich.edu * All rights reserved.
47178Sgblack@eecs.umich.edu *
57178Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67178Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77178Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97178Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117178Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127178Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137178Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147178Sgblack@eecs.umich.edu * this software without specific prior written permission.
156019Shines@cs.fsu.edu *
166019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276019Shines@cs.fsu.edu */
286019Shines@cs.fsu.edu
296019Shines@cs.fsu.edu#include <cstdio>
306019Shines@cs.fsu.edu#include <deque>
316019Shines@cs.fsu.edu#include <string>
326019Shines@cs.fsu.edu
336019Shines@cs.fsu.edu#include "base/inet.hh"
346019Shines@cs.fsu.edu#include "cpu/exec_context.hh"
356019Shines@cs.fsu.edu#include "cpu/intr_control.hh"
366019Shines@cs.fsu.edu#include "dev/dma.hh"
376019Shines@cs.fsu.edu#include "dev/etherlink.hh"
386019Shines@cs.fsu.edu#include "dev/sinic.hh"
396019Shines@cs.fsu.edu#include "dev/pciconfigall.hh"
406019Shines@cs.fsu.edu#include "mem/bus/bus.hh"
416019Shines@cs.fsu.edu#include "mem/bus/dma_interface.hh"
426019Shines@cs.fsu.edu#include "mem/bus/pio_interface.hh"
436019Shines@cs.fsu.edu#include "mem/bus/pio_interface_impl.hh"
446019Shines@cs.fsu.edu#include "mem/functional_mem/memory_control.hh"
456019Shines@cs.fsu.edu#include "mem/functional_mem/physical_memory.hh"
466019Shines@cs.fsu.edu#include "sim/builder.hh"
476019Shines@cs.fsu.edu#include "sim/debug.hh"
486019Shines@cs.fsu.edu#include "sim/eventq.hh"
496019Shines@cs.fsu.edu#include "sim/host.hh"
506019Shines@cs.fsu.edu#include "sim/stats.hh"
516019Shines@cs.fsu.edu#include "targetarch/vtophys.hh"
526019Shines@cs.fsu.edu
536019Shines@cs.fsu.eduusing namespace Net;
546019Shines@cs.fsu.edu
556019Shines@cs.fsu.edunamespace Sinic {
566019Shines@cs.fsu.edu
576019Shines@cs.fsu.educonst char *RxStateStrings[] =
586243Sgblack@eecs.umich.edu{
596243Sgblack@eecs.umich.edu    "rxIdle",
606243Sgblack@eecs.umich.edu    "rxFifoBlock",
616243Sgblack@eecs.umich.edu    "rxBeginCopy",
626243Sgblack@eecs.umich.edu    "rxCopy",
636019Shines@cs.fsu.edu    "rxCopyDone"
646019Shines@cs.fsu.edu};
656019Shines@cs.fsu.edu
666019Shines@cs.fsu.educonst char *TxStateStrings[] =
676019Shines@cs.fsu.edu{
686019Shines@cs.fsu.edu    "txIdle",
696019Shines@cs.fsu.edu    "txFifoBlock",
706019Shines@cs.fsu.edu    "txBeginCopy",
716019Shines@cs.fsu.edu    "txCopy",
726019Shines@cs.fsu.edu    "txCopyDone"
736019Shines@cs.fsu.edu};
746019Shines@cs.fsu.edu
756019Shines@cs.fsu.edu
766019Shines@cs.fsu.edu///////////////////////////////////////////////////////////////////////
776019Shines@cs.fsu.edu//
786019Shines@cs.fsu.edu// Sinic PCI Device
796019Shines@cs.fsu.edu//
806019Shines@cs.fsu.eduBase::Base(Params *p)
816019Shines@cs.fsu.edu    : PciDev(p), rxEnable(false), txEnable(false), cycleTime(p->cycle_time),
826019Shines@cs.fsu.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
836019Shines@cs.fsu.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
846019Shines@cs.fsu.edu{
856019Shines@cs.fsu.edu}
866019Shines@cs.fsu.edu
876019Shines@cs.fsu.eduDevice::Device(Params *p)
886019Shines@cs.fsu.edu    : Base(p), plat(p->plat), physmem(p->physmem),
896019Shines@cs.fsu.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
906019Shines@cs.fsu.edu      rxKickTick(0), txKickTick(0),
916019Shines@cs.fsu.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
926019Shines@cs.fsu.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
936019Shines@cs.fsu.edu      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
946252Sgblack@eecs.umich.edu{
956243Sgblack@eecs.umich.edu    reset();
966243Sgblack@eecs.umich.edu
976243Sgblack@eecs.umich.edu    if (p->header_bus) {
986019Shines@cs.fsu.edu        pioInterface = newPioInterface(p->name, p->hier, p->header_bus, this,
996019Shines@cs.fsu.edu                                       &Device::cacheAccess);
1006019Shines@cs.fsu.edu
1016019Shines@cs.fsu.edu        pioLatency = p->pio_latency * p->header_bus->clockRatio;
1026019Shines@cs.fsu.edu
1036252Sgblack@eecs.umich.edu        if (p->payload_bus)
1046243Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
1056243Sgblack@eecs.umich.edu                                                 p->header_bus, p->payload_bus,
1066243Sgblack@eecs.umich.edu                                                 1);
1076019Shines@cs.fsu.edu        else
1086019Shines@cs.fsu.edu            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
1096019Shines@cs.fsu.edu                                                 p->header_bus, p->header_bus,
1106019Shines@cs.fsu.edu                                                 1);
1116019Shines@cs.fsu.edu    } else if (p->payload_bus) {
1126019Shines@cs.fsu.edu        pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this,
1136019Shines@cs.fsu.edu                                       &Device::cacheAccess);
1146252Sgblack@eecs.umich.edu
1156243Sgblack@eecs.umich.edu        pioLatency = p->pio_latency * p->payload_bus->clockRatio;
1166243Sgblack@eecs.umich.edu
1176243Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus,
1186019Shines@cs.fsu.edu                                             p->payload_bus, 1);
1196019Shines@cs.fsu.edu    }
1206019Shines@cs.fsu.edu}
1216019Shines@cs.fsu.edu
1226019Shines@cs.fsu.eduDevice::~Device()
1236019Shines@cs.fsu.edu{}
1246019Shines@cs.fsu.edu
1256019Shines@cs.fsu.eduvoid
1266019Shines@cs.fsu.eduDevice::regStats()
1276019Shines@cs.fsu.edu{
1286019Shines@cs.fsu.edu    rxBytes
1296019Shines@cs.fsu.edu        .name(name() + ".rxBytes")
1306019Shines@cs.fsu.edu        .desc("Bytes Received")
1316019Shines@cs.fsu.edu        .prereq(rxBytes)
1326019Shines@cs.fsu.edu        ;
1336019Shines@cs.fsu.edu
1346724Sgblack@eecs.umich.edu    rxBandwidth
1356724Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
1366019Shines@cs.fsu.edu        .desc("Receive Bandwidth (bits/s)")
1376019Shines@cs.fsu.edu        .precision(0)
1386019Shines@cs.fsu.edu        .prereq(rxBytes)
1396019Shines@cs.fsu.edu        ;
1406019Shines@cs.fsu.edu
1416252Sgblack@eecs.umich.edu    rxPackets
1426243Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1436243Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1446243Sgblack@eecs.umich.edu        .prereq(rxBytes)
1456019Shines@cs.fsu.edu        ;
1466019Shines@cs.fsu.edu
1476019Shines@cs.fsu.edu    rxPacketRate
1486019Shines@cs.fsu.edu        .name(name() + ".rxPPS")
1496019Shines@cs.fsu.edu        .desc("Packet Reception Rate (packets/s)")
1506019Shines@cs.fsu.edu        .precision(0)
1517356Sgblack@eecs.umich.edu        .prereq(rxBytes)
1527356Sgblack@eecs.umich.edu        ;
1537356Sgblack@eecs.umich.edu
1547356Sgblack@eecs.umich.edu    rxIpPackets
1557356Sgblack@eecs.umich.edu        .name(name() + ".rxIpPackets")
1567356Sgblack@eecs.umich.edu        .desc("Number of IP Packets Received")
1577356Sgblack@eecs.umich.edu        .prereq(rxBytes)
1587356Sgblack@eecs.umich.edu        ;
1597178Sgblack@eecs.umich.edu
1607178Sgblack@eecs.umich.edu    rxTcpPackets
1617178Sgblack@eecs.umich.edu        .name(name() + ".rxTcpPackets")
1627337Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1637178Sgblack@eecs.umich.edu        .prereq(rxBytes)
1647178Sgblack@eecs.umich.edu        ;
1657178Sgblack@eecs.umich.edu
1667178Sgblack@eecs.umich.edu    rxUdpPackets
1677178Sgblack@eecs.umich.edu        .name(name() + ".rxUdpPackets")
1687178Sgblack@eecs.umich.edu        .desc("Number of UDP Packets Received")
1697178Sgblack@eecs.umich.edu        .prereq(rxBytes)
1707178Sgblack@eecs.umich.edu        ;
1717178Sgblack@eecs.umich.edu
1727178Sgblack@eecs.umich.edu    rxIpChecksums
1737178Sgblack@eecs.umich.edu        .name(name() + ".rxIpChecksums")
1747335Sgblack@eecs.umich.edu        .desc("Number of rx IP Checksums done by device")
1757335Sgblack@eecs.umich.edu        .precision(0)
1767335Sgblack@eecs.umich.edu        .prereq(rxBytes)
1777335Sgblack@eecs.umich.edu        ;
1787335Sgblack@eecs.umich.edu
1797335Sgblack@eecs.umich.edu    rxTcpChecksums
1807335Sgblack@eecs.umich.edu        .name(name() + ".rxTcpChecksums")
1817335Sgblack@eecs.umich.edu        .desc("Number of rx TCP Checksums done by device")
1827335Sgblack@eecs.umich.edu        .precision(0)
1837335Sgblack@eecs.umich.edu        .prereq(rxBytes)
1847335Sgblack@eecs.umich.edu        ;
1857335Sgblack@eecs.umich.edu
1867337Sgblack@eecs.umich.edu    rxUdpChecksums
1877335Sgblack@eecs.umich.edu        .name(name() + ".rxUdpChecksums")
1887335Sgblack@eecs.umich.edu        .desc("Number of rx UDP Checksums done by device")
1897335Sgblack@eecs.umich.edu        .precision(0)
1907335Sgblack@eecs.umich.edu        .prereq(rxBytes)
1917335Sgblack@eecs.umich.edu        ;
1927335Sgblack@eecs.umich.edu
1937335Sgblack@eecs.umich.edu    totBandwidth
1947335Sgblack@eecs.umich.edu        .name(name() + ".totBandwidth")
1957335Sgblack@eecs.umich.edu        .desc("Total Bandwidth (bits/s)")
1967335Sgblack@eecs.umich.edu        .precision(0)
1977335Sgblack@eecs.umich.edu        .prereq(totBytes)
1987335Sgblack@eecs.umich.edu        ;
1997178Sgblack@eecs.umich.edu
2007178Sgblack@eecs.umich.edu    totPackets
2017178Sgblack@eecs.umich.edu        .name(name() + ".totPackets")
2027178Sgblack@eecs.umich.edu        .desc("Total Packets")
2037178Sgblack@eecs.umich.edu        .precision(0)
2047178Sgblack@eecs.umich.edu        .prereq(totBytes)
2057178Sgblack@eecs.umich.edu        ;
2067178Sgblack@eecs.umich.edu
2077178Sgblack@eecs.umich.edu    totBytes
2087178Sgblack@eecs.umich.edu        .name(name() + ".totBytes")
2097178Sgblack@eecs.umich.edu        .desc("Total Bytes")
2107178Sgblack@eecs.umich.edu        .precision(0)
2117178Sgblack@eecs.umich.edu        .prereq(totBytes)
2127178Sgblack@eecs.umich.edu        ;
2137178Sgblack@eecs.umich.edu
2147178Sgblack@eecs.umich.edu    totPacketRate
2157178Sgblack@eecs.umich.edu        .name(name() + ".totPPS")
2167178Sgblack@eecs.umich.edu        .desc("Total Tranmission Rate (packets/s)")
2177178Sgblack@eecs.umich.edu        .precision(0)
2187178Sgblack@eecs.umich.edu        .prereq(totBytes)
2197178Sgblack@eecs.umich.edu        ;
2207178Sgblack@eecs.umich.edu
2217178Sgblack@eecs.umich.edu    txBytes
2227178Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
2237178Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
2247178Sgblack@eecs.umich.edu        .prereq(txBytes)
2257178Sgblack@eecs.umich.edu        ;
2267178Sgblack@eecs.umich.edu
2277178Sgblack@eecs.umich.edu    txBandwidth
2287346Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
2297346Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
2307346Sgblack@eecs.umich.edu        .precision(0)
2317346Sgblack@eecs.umich.edu        .prereq(txBytes)
2327346Sgblack@eecs.umich.edu        ;
2337346Sgblack@eecs.umich.edu
2347346Sgblack@eecs.umich.edu    txPackets
2357346Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
2367346Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
2377346Sgblack@eecs.umich.edu        .prereq(txBytes)
2387178Sgblack@eecs.umich.edu        ;
2397346Sgblack@eecs.umich.edu
2407346Sgblack@eecs.umich.edu    txPacketRate
2417346Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2427346Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2437346Sgblack@eecs.umich.edu        .precision(0)
2447346Sgblack@eecs.umich.edu        .prereq(txBytes)
2457346Sgblack@eecs.umich.edu        ;
2467346Sgblack@eecs.umich.edu
2477346Sgblack@eecs.umich.edu    txIpPackets
2487346Sgblack@eecs.umich.edu        .name(name() + ".txIpPackets")
2497346Sgblack@eecs.umich.edu        .desc("Number of IP Packets Transmitted")
2507346Sgblack@eecs.umich.edu        .prereq(txBytes)
2517346Sgblack@eecs.umich.edu        ;
2527346Sgblack@eecs.umich.edu
2537346Sgblack@eecs.umich.edu    txTcpPackets
2547178Sgblack@eecs.umich.edu        .name(name() + ".txTcpPackets")
2557337Sgblack@eecs.umich.edu        .desc("Number of TCP Packets Transmitted")
2567337Sgblack@eecs.umich.edu        .prereq(txBytes)
2577337Sgblack@eecs.umich.edu        ;
2587337Sgblack@eecs.umich.edu
2597337Sgblack@eecs.umich.edu    txUdpPackets
2607337Sgblack@eecs.umich.edu        .name(name() + ".txUdpPackets")
2617337Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
2627337Sgblack@eecs.umich.edu        .prereq(txBytes)
2637337Sgblack@eecs.umich.edu        ;
2647337Sgblack@eecs.umich.edu
2657337Sgblack@eecs.umich.edu    txIpChecksums
2667337Sgblack@eecs.umich.edu        .name(name() + ".txIpChecksums")
2677337Sgblack@eecs.umich.edu        .desc("Number of tx IP Checksums done by device")
2687337Sgblack@eecs.umich.edu        .precision(0)
2697337Sgblack@eecs.umich.edu        .prereq(txBytes)
2707178Sgblack@eecs.umich.edu        ;
2717178Sgblack@eecs.umich.edu
2727178Sgblack@eecs.umich.edu    txTcpChecksums
2737178Sgblack@eecs.umich.edu        .name(name() + ".txTcpChecksums")
2747337Sgblack@eecs.umich.edu        .desc("Number of tx TCP Checksums done by device")
2757337Sgblack@eecs.umich.edu        .precision(0)
2767337Sgblack@eecs.umich.edu        .prereq(txBytes)
2777337Sgblack@eecs.umich.edu        ;
2787346Sgblack@eecs.umich.edu
2797346Sgblack@eecs.umich.edu    txUdpChecksums
2807346Sgblack@eecs.umich.edu        .name(name() + ".txUdpChecksums")
2817346Sgblack@eecs.umich.edu        .desc("Number of tx UDP Checksums done by device")
2827346Sgblack@eecs.umich.edu        .precision(0)
2837337Sgblack@eecs.umich.edu        .prereq(txBytes)
2847178Sgblack@eecs.umich.edu        ;
2857321Sgblack@eecs.umich.edu
2867356Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2877321Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2887356Sgblack@eecs.umich.edu    totBandwidth = txBandwidth + rxBandwidth;
2897356Sgblack@eecs.umich.edu    totBytes = txBytes + rxBytes;
2907356Sgblack@eecs.umich.edu    totPackets = txPackets + rxPackets;
2917356Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2927356Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2937356Sgblack@eecs.umich.edu}
2947356Sgblack@eecs.umich.edu
2957356Sgblack@eecs.umich.edu/**
2967356Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
2977356Sgblack@eecs.umich.edu */
2987356Sgblack@eecs.umich.eduvoid
2997356Sgblack@eecs.umich.eduDevice::WriteConfig(int offset, int size, uint32_t data)
3007321Sgblack@eecs.umich.edu{
3017321Sgblack@eecs.umich.edu    switch (offset) {
3027321Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
3037321Sgblack@eecs.umich.edu        // Need to catch writes to BARs to update the PIO interface
3047321Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
3057321Sgblack@eecs.umich.edu        if (BARAddrs[0] != 0) {
3067321Sgblack@eecs.umich.edu            if (pioInterface)
3077321Sgblack@eecs.umich.edu                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
3087321Sgblack@eecs.umich.edu
3097321Sgblack@eecs.umich.edu            BARAddrs[0] &= EV5::PAddrUncachedMask;
3107321Sgblack@eecs.umich.edu        }
3117335Sgblack@eecs.umich.edu        break;
3127335Sgblack@eecs.umich.edu
3137335Sgblack@eecs.umich.edu      default:
3147335Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
3157335Sgblack@eecs.umich.edu    }
3167335Sgblack@eecs.umich.edu}
3177335Sgblack@eecs.umich.edu
3187335Sgblack@eecs.umich.edu/**
3197335Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
3207321Sgblack@eecs.umich.edu * spec sheet
3217323Sgblack@eecs.umich.edu */
3227323Sgblack@eecs.umich.eduFault
3237323Sgblack@eecs.umich.eduDevice::read(MemReqPtr &req, uint8_t *data)
3247323Sgblack@eecs.umich.edu{
3257323Sgblack@eecs.umich.edu    assert(config.hdr.command & PCI_CMD_MSE);
3267323Sgblack@eecs.umich.edu
3277323Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
3287323Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
3297323Sgblack@eecs.umich.edu
3307323Sgblack@eecs.umich.edu    if (Regs::regSize(daddr) == 0)
3317323Sgblack@eecs.umich.edu        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
3327323Sgblack@eecs.umich.edu              daddr, req->paddr, req->vaddr, req->size);
3337323Sgblack@eecs.umich.edu
3347323Sgblack@eecs.umich.edu    if (req->size != Regs::regSize(daddr))
3357323Sgblack@eecs.umich.edu        panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
3367323Sgblack@eecs.umich.edu              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
3377323Sgblack@eecs.umich.edu
3387321Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n",
3397321Sgblack@eecs.umich.edu            Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
3407321Sgblack@eecs.umich.edu
3417335Sgblack@eecs.umich.edu    uint32_t &reg32 = *(uint32_t *)data;
3427335Sgblack@eecs.umich.edu    uint64_t &reg64 = *(uint64_t *)data;
3437335Sgblack@eecs.umich.edu
3447335Sgblack@eecs.umich.edu    switch (daddr) {
3457335Sgblack@eecs.umich.edu      case Regs::Config:
3467335Sgblack@eecs.umich.edu        reg32 = regs.Config;
3477335Sgblack@eecs.umich.edu        break;
3487335Sgblack@eecs.umich.edu
3497335Sgblack@eecs.umich.edu      case Regs::RxMaxCopy:
3507335Sgblack@eecs.umich.edu        reg32 = regs.RxMaxCopy;
3517335Sgblack@eecs.umich.edu        break;
3527335Sgblack@eecs.umich.edu
3537335Sgblack@eecs.umich.edu      case Regs::TxMaxCopy:
3547335Sgblack@eecs.umich.edu        reg32 = regs.TxMaxCopy;
3557335Sgblack@eecs.umich.edu        break;
3567335Sgblack@eecs.umich.edu
3577335Sgblack@eecs.umich.edu      case Regs::RxThreshold:
3587335Sgblack@eecs.umich.edu        reg32 = regs.RxThreshold;
3597335Sgblack@eecs.umich.edu        break;
3607335Sgblack@eecs.umich.edu
3617335Sgblack@eecs.umich.edu      case Regs::TxThreshold:
3627335Sgblack@eecs.umich.edu        reg32 = regs.TxThreshold;
3637335Sgblack@eecs.umich.edu        break;
3647335Sgblack@eecs.umich.edu
3657335Sgblack@eecs.umich.edu      case Regs::IntrStatus:
3667335Sgblack@eecs.umich.edu        reg32 = regs.IntrStatus;
3677335Sgblack@eecs.umich.edu        devIntrClear();
3687335Sgblack@eecs.umich.edu        break;
3697335Sgblack@eecs.umich.edu
3707335Sgblack@eecs.umich.edu      case Regs::IntrMask:
3717335Sgblack@eecs.umich.edu        reg32 = regs.IntrMask;
3727335Sgblack@eecs.umich.edu        break;
3737335Sgblack@eecs.umich.edu
3747321Sgblack@eecs.umich.edu      case Regs::RxData:
3757321Sgblack@eecs.umich.edu        reg64 = regs.RxData;
3767321Sgblack@eecs.umich.edu        break;
3777321Sgblack@eecs.umich.edu
3787321Sgblack@eecs.umich.edu      case Regs::RxDone:
3797321Sgblack@eecs.umich.edu      case Regs::RxWait:
3807335Sgblack@eecs.umich.edu        reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
3817335Sgblack@eecs.umich.edu                                         min(rxFifo.packets(), 255));
3827335Sgblack@eecs.umich.edu        break;
3837335Sgblack@eecs.umich.edu
3847335Sgblack@eecs.umich.edu      case Regs::TxData:
3857335Sgblack@eecs.umich.edu        reg64 = regs.TxData;
3867335Sgblack@eecs.umich.edu        break;
3877335Sgblack@eecs.umich.edu
3887335Sgblack@eecs.umich.edu      case Regs::TxDone:
3897321Sgblack@eecs.umich.edu      case Regs::TxWait:
3907326Sgblack@eecs.umich.edu        reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
3917326Sgblack@eecs.umich.edu                                         min(txFifo.packets(), 255));
3927326Sgblack@eecs.umich.edu        break;
3937326Sgblack@eecs.umich.edu
3947326Sgblack@eecs.umich.edu      case Regs::HwAddr:
3957326Sgblack@eecs.umich.edu        reg64 = params()->eaddr;
3967326Sgblack@eecs.umich.edu        break;
3977326Sgblack@eecs.umich.edu
3987326Sgblack@eecs.umich.edu      default:
3997326Sgblack@eecs.umich.edu        panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d",
4007326Sgblack@eecs.umich.edu              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
4017326Sgblack@eecs.umich.edu    }
4027326Sgblack@eecs.umich.edu
4037326Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
4047326Sgblack@eecs.umich.edu            Regs::regSize(daddr) == 4 ? reg32 : reg64);
4057326Sgblack@eecs.umich.edu
4067326Sgblack@eecs.umich.edu    return No_Fault;
4077326Sgblack@eecs.umich.edu}
4087326Sgblack@eecs.umich.edu
4097326Sgblack@eecs.umich.eduFault
4107326Sgblack@eecs.umich.eduDevice::write(MemReqPtr &req, const uint8_t *data)
4117326Sgblack@eecs.umich.edu{
4127326Sgblack@eecs.umich.edu    assert(config.hdr.command & PCI_CMD_MSE);
4137321Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
4147321Sgblack@eecs.umich.edu
4157335Sgblack@eecs.umich.edu    if (Regs::regSize(daddr) == 0)
4167335Sgblack@eecs.umich.edu        panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
4177335Sgblack@eecs.umich.edu              daddr, req->paddr, req->vaddr, req->size);
4187335Sgblack@eecs.umich.edu
4197335Sgblack@eecs.umich.edu    if (req->size != Regs::regSize(daddr))
4207335Sgblack@eecs.umich.edu        panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d",
4217335Sgblack@eecs.umich.edu              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
4227335Sgblack@eecs.umich.edu
4237335Sgblack@eecs.umich.edu    uint32_t reg32 = *(uint32_t *)data;
4247335Sgblack@eecs.umich.edu    uint64_t reg64 = *(uint64_t *)data;
4257335Sgblack@eecs.umich.edu
4267335Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n",
4277335Sgblack@eecs.umich.edu            Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64,
4287335Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
4297335Sgblack@eecs.umich.edu
4307335Sgblack@eecs.umich.edu
4317335Sgblack@eecs.umich.edu    switch (daddr) {
4327335Sgblack@eecs.umich.edu      case Regs::Config:
4337335Sgblack@eecs.umich.edu        changeConfig(reg32);
4347335Sgblack@eecs.umich.edu        break;
4357335Sgblack@eecs.umich.edu
4367335Sgblack@eecs.umich.edu      case Regs::RxThreshold:
4377335Sgblack@eecs.umich.edu        regs.RxThreshold = reg32;
4387335Sgblack@eecs.umich.edu        break;
4397335Sgblack@eecs.umich.edu
4407335Sgblack@eecs.umich.edu      case Regs::TxThreshold:
4417335Sgblack@eecs.umich.edu        regs.TxThreshold = reg32;
4427335Sgblack@eecs.umich.edu        break;
4437335Sgblack@eecs.umich.edu
4447335Sgblack@eecs.umich.edu      case Regs::IntrMask:
4457335Sgblack@eecs.umich.edu        devIntrChangeMask(reg32);
4467335Sgblack@eecs.umich.edu        break;
4477335Sgblack@eecs.umich.edu
4487335Sgblack@eecs.umich.edu      case Regs::RxData:
4497335Sgblack@eecs.umich.edu        if (rxState != rxIdle)
4507335Sgblack@eecs.umich.edu            panic("receive machine busy with another request!");
4517335Sgblack@eecs.umich.edu
4527335Sgblack@eecs.umich.edu        regs.RxDone = 0;
4537335Sgblack@eecs.umich.edu        regs.RxData = reg64;
4547335Sgblack@eecs.umich.edu        if (rxEnable) {
4557335Sgblack@eecs.umich.edu            rxState = rxFifoBlock;
4567335Sgblack@eecs.umich.edu            rxKick();
4577335Sgblack@eecs.umich.edu        }
4587335Sgblack@eecs.umich.edu        break;
4597321Sgblack@eecs.umich.edu
4607321Sgblack@eecs.umich.edu      case Regs::TxData:
4617321Sgblack@eecs.umich.edu        if (txState != txIdle)
4627321Sgblack@eecs.umich.edu            panic("transmit machine busy with another request!");
4637321Sgblack@eecs.umich.edu
4647356Sgblack@eecs.umich.edu        regs.TxDone = 0;
4657356Sgblack@eecs.umich.edu        regs.TxData = reg64;
4667356Sgblack@eecs.umich.edu        if (txEnable) {
4677356Sgblack@eecs.umich.edu            txState = txFifoBlock;
4687356Sgblack@eecs.umich.edu            txKick();
4697356Sgblack@eecs.umich.edu        }
4707363Sgblack@eecs.umich.edu        break;
4717363Sgblack@eecs.umich.edu
4727363Sgblack@eecs.umich.edu      default:
4737363Sgblack@eecs.umich.edu        panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d",
4747363Sgblack@eecs.umich.edu              Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
4757363Sgblack@eecs.umich.edu    }
4767363Sgblack@eecs.umich.edu
4777363Sgblack@eecs.umich.edu    return No_Fault;
4787363Sgblack@eecs.umich.edu}
4797363Sgblack@eecs.umich.edu
4807363Sgblack@eecs.umich.eduvoid
4817363Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts)
4827363Sgblack@eecs.umich.edu{
4837363Sgblack@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
4847363Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
4857363Sgblack@eecs.umich.edu
4867363Sgblack@eecs.umich.edu    regs.IntrStatus |= interrupts;
4877363Sgblack@eecs.umich.edu
4887363Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
4897364Sgblack@eecs.umich.edu            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
4907364Sgblack@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
4917364Sgblack@eecs.umich.edu
4927364Sgblack@eecs.umich.edu    if ((regs.IntrStatus & regs.IntrMask)) {
4937364Sgblack@eecs.umich.edu        Tick when = curTick;
4947364Sgblack@eecs.umich.edu        if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0)
4957364Sgblack@eecs.umich.edu            when += intrDelay;
4967364Sgblack@eecs.umich.edu        cpuIntrPost(when);
4977364Sgblack@eecs.umich.edu    }
4987364Sgblack@eecs.umich.edu}
4997364Sgblack@eecs.umich.edu
5007364Sgblack@eecs.umich.eduvoid
5017364Sgblack@eecs.umich.eduDevice::devIntrClear(uint32_t interrupts)
5027364Sgblack@eecs.umich.edu{
5037364Sgblack@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
5047364Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
5057364Sgblack@eecs.umich.edu
5067364Sgblack@eecs.umich.edu    regs.IntrStatus &= ~interrupts;
5077364Sgblack@eecs.umich.edu
5087363Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
5097363Sgblack@eecs.umich.edu            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
5107363Sgblack@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
5117363Sgblack@eecs.umich.edu
5127363Sgblack@eecs.umich.edu    if (!(regs.IntrStatus & regs.IntrMask))
5137367Sgblack@eecs.umich.edu        cpuIntrClear();
5147367Sgblack@eecs.umich.edu}
5157367Sgblack@eecs.umich.edu
5167367Sgblack@eecs.umich.eduvoid
5177367Sgblack@eecs.umich.eduDevice::devIntrChangeMask(uint32_t newmask)
5187367Sgblack@eecs.umich.edu{
5197367Sgblack@eecs.umich.edu    if (regs.IntrMask == newmask)
5207367Sgblack@eecs.umich.edu        return;
5217367Sgblack@eecs.umich.edu
5227367Sgblack@eecs.umich.edu    regs.IntrMask = newmask;
5237367Sgblack@eecs.umich.edu
5247367Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
5257367Sgblack@eecs.umich.edu            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
5267367Sgblack@eecs.umich.edu            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
5277367Sgblack@eecs.umich.edu
5287367Sgblack@eecs.umich.edu    if (regs.IntrStatus & regs.IntrMask)
5297367Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
5307367Sgblack@eecs.umich.edu    else
5317367Sgblack@eecs.umich.edu        cpuIntrClear();
5327363Sgblack@eecs.umich.edu}
5337368Sgblack@eecs.umich.edu
5347368Sgblack@eecs.umich.eduvoid
5357368Sgblack@eecs.umich.eduBase::cpuIntrPost(Tick when)
5367368Sgblack@eecs.umich.edu{
5377368Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
5387368Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
5397368Sgblack@eecs.umich.edu    // schedule another.
5407368Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
5417368Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
5427368Sgblack@eecs.umich.edu    /**
5437368Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
5447368Sgblack@eecs.umich.edu     * be fixed.
5457368Sgblack@eecs.umich.edu     */
5467368Sgblack@eecs.umich.edu    assert(when >= curTick);
5477368Sgblack@eecs.umich.edu    assert(intrTick >= curTick || intrTick == 0);
5487368Sgblack@eecs.umich.edu    if (!cpuIntrEnable) {
5497368Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
5507368Sgblack@eecs.umich.edu                intrTick);
5517368Sgblack@eecs.umich.edu        return;
5527363Sgblack@eecs.umich.edu    }
5537363Sgblack@eecs.umich.edu
5547363Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
5557369Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
5567369Sgblack@eecs.umich.edu                intrTick);
5577369Sgblack@eecs.umich.edu        return;
5587369Sgblack@eecs.umich.edu    }
5597369Sgblack@eecs.umich.edu
5607369Sgblack@eecs.umich.edu    intrTick = when;
5617369Sgblack@eecs.umich.edu    if (intrTick < curTick) {
5627369Sgblack@eecs.umich.edu        debug_break();
5637369Sgblack@eecs.umich.edu        intrTick = curTick;
5647369Sgblack@eecs.umich.edu    }
5657369Sgblack@eecs.umich.edu
5667369Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5677369Sgblack@eecs.umich.edu            intrTick);
5687369Sgblack@eecs.umich.edu
5697369Sgblack@eecs.umich.edu    if (intrEvent)
5707369Sgblack@eecs.umich.edu        intrEvent->squash();
5717369Sgblack@eecs.umich.edu    intrEvent = new IntrEvent(this, true);
5727369Sgblack@eecs.umich.edu    intrEvent->schedule(intrTick);
5737369Sgblack@eecs.umich.edu}
5747363Sgblack@eecs.umich.edu
5757363Sgblack@eecs.umich.eduvoid
5767363Sgblack@eecs.umich.eduBase::cpuInterrupt()
5777363Sgblack@eecs.umich.edu{
5787363Sgblack@eecs.umich.edu    assert(intrTick == curTick);
5797363Sgblack@eecs.umich.edu
5807363Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
5817363Sgblack@eecs.umich.edu    // it anymore
5827363Sgblack@eecs.umich.edu    intrEvent = 0;
5837363Sgblack@eecs.umich.edu    intrTick = 0;
5847363Sgblack@eecs.umich.edu
5857363Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
5867363Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
5877363Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
5887363Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
5897363Sgblack@eecs.umich.edu    } else {
5907363Sgblack@eecs.umich.edu        // Send interrupt
5917363Sgblack@eecs.umich.edu        cpuPendingIntr = true;
5927363Sgblack@eecs.umich.edu
5937363Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
5947363Sgblack@eecs.umich.edu        intrPost();
5957363Sgblack@eecs.umich.edu    }
5967363Sgblack@eecs.umich.edu}
5977363Sgblack@eecs.umich.edu
5987363Sgblack@eecs.umich.eduvoid
5997363Sgblack@eecs.umich.eduBase::cpuIntrClear()
6007363Sgblack@eecs.umich.edu{
6017363Sgblack@eecs.umich.edu    if (!cpuPendingIntr)
6027363Sgblack@eecs.umich.edu        return;
6037363Sgblack@eecs.umich.edu
6047363Sgblack@eecs.umich.edu    if (intrEvent) {
6057363Sgblack@eecs.umich.edu        intrEvent->squash();
6067363Sgblack@eecs.umich.edu        intrEvent = 0;
6077363Sgblack@eecs.umich.edu    }
6087363Sgblack@eecs.umich.edu
6097363Sgblack@eecs.umich.edu    intrTick = 0;
6107363Sgblack@eecs.umich.edu
6117366Sgblack@eecs.umich.edu    cpuPendingIntr = false;
6127366Sgblack@eecs.umich.edu
6137366Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
6147366Sgblack@eecs.umich.edu    intrClear();
6157366Sgblack@eecs.umich.edu}
6167366Sgblack@eecs.umich.edu
6177366Sgblack@eecs.umich.edubool
6187366Sgblack@eecs.umich.eduBase::cpuIntrPending() const
6197366Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
6207366Sgblack@eecs.umich.edu
6217366Sgblack@eecs.umich.eduvoid
6227366Sgblack@eecs.umich.eduDevice::changeConfig(uint32_t newconf)
6237366Sgblack@eecs.umich.edu{
6247366Sgblack@eecs.umich.edu    uint32_t changed = regs.Config ^ newconf;
6257366Sgblack@eecs.umich.edu    if (!changed)
6267363Sgblack@eecs.umich.edu        return;
6277363Sgblack@eecs.umich.edu
6287363Sgblack@eecs.umich.edu    regs.Config = newconf;
6297365Sgblack@eecs.umich.edu
6307365Sgblack@eecs.umich.edu    if ((changed & Regs::Config_Reset)) {
6317365Sgblack@eecs.umich.edu        assert(regs.Config & Regs::Config_Reset);
6327365Sgblack@eecs.umich.edu        reset();
6337365Sgblack@eecs.umich.edu        regs.Config &= ~Regs::Config_Reset;
6347365Sgblack@eecs.umich.edu    }
6357365Sgblack@eecs.umich.edu
6367365Sgblack@eecs.umich.edu    if ((changed & Regs::Config_IntEn)) {
6377365Sgblack@eecs.umich.edu        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
6387365Sgblack@eecs.umich.edu        if (cpuIntrEnable) {
6397365Sgblack@eecs.umich.edu            if (regs.IntrStatus & regs.IntrMask)
6407365Sgblack@eecs.umich.edu                cpuIntrPost(curTick);
6417365Sgblack@eecs.umich.edu        } else {
6427365Sgblack@eecs.umich.edu            cpuIntrClear();
6437365Sgblack@eecs.umich.edu        }
6447363Sgblack@eecs.umich.edu    }
6457369Sgblack@eecs.umich.edu
6467369Sgblack@eecs.umich.edu    if ((changed & Regs::Config_TxEn)) {
6477369Sgblack@eecs.umich.edu        txEnable = regs.Config & Regs::Config_TxEn;
6487369Sgblack@eecs.umich.edu        if (txEnable)
6497369Sgblack@eecs.umich.edu            txKick();
6507369Sgblack@eecs.umich.edu    }
6517369Sgblack@eecs.umich.edu
6527369Sgblack@eecs.umich.edu    if ((changed & Regs::Config_RxEn)) {
6537369Sgblack@eecs.umich.edu        rxEnable = regs.Config & Regs::Config_RxEn;
6547369Sgblack@eecs.umich.edu        if (rxEnable)
6557369Sgblack@eecs.umich.edu            rxKick();
6567369Sgblack@eecs.umich.edu    }
6577369Sgblack@eecs.umich.edu}
6587369Sgblack@eecs.umich.edu
6597369Sgblack@eecs.umich.eduvoid
6607363Sgblack@eecs.umich.eduDevice::reset()
6617363Sgblack@eecs.umich.edu{
6627363Sgblack@eecs.umich.edu    using namespace Regs;
6637363Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
6647363Sgblack@eecs.umich.edu    regs.RxMaxCopy = params()->rx_max_copy;
6657363Sgblack@eecs.umich.edu    regs.TxMaxCopy = params()->tx_max_copy;
6667363Sgblack@eecs.umich.edu    regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData;
6677363Sgblack@eecs.umich.edu
6687363Sgblack@eecs.umich.edu    rxState = rxIdle;
6697363Sgblack@eecs.umich.edu    txState = txIdle;
6707363Sgblack@eecs.umich.edu
6717363Sgblack@eecs.umich.edu    rxFifo.clear();
6727363Sgblack@eecs.umich.edu    txFifo.clear();
6737363Sgblack@eecs.umich.edu}
6747363Sgblack@eecs.umich.edu
6757363Sgblack@eecs.umich.eduvoid
6767363Sgblack@eecs.umich.eduDevice::rxDmaCopy()
6777363Sgblack@eecs.umich.edu{
6787363Sgblack@eecs.umich.edu    assert(rxState == rxCopy);
6797363Sgblack@eecs.umich.edu    rxState = rxCopyDone;
6807363Sgblack@eecs.umich.edu    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
6817363Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
6827363Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
6837363Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
6847363Sgblack@eecs.umich.edu}
6857363Sgblack@eecs.umich.edu
6867363Sgblack@eecs.umich.eduvoid
6877363Sgblack@eecs.umich.eduDevice::rxDmaDone()
6887363Sgblack@eecs.umich.edu{
6897363Sgblack@eecs.umich.edu    rxDmaCopy();
6907363Sgblack@eecs.umich.edu    rxKick();
6917363Sgblack@eecs.umich.edu}
6927363Sgblack@eecs.umich.edu
6937363Sgblack@eecs.umich.eduvoid
6947363Sgblack@eecs.umich.eduDevice::rxKick()
6957363Sgblack@eecs.umich.edu{
6967363Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
6977363Sgblack@eecs.umich.edu            RxStateStrings[rxState], rxFifo.size());
6987363Sgblack@eecs.umich.edu
6997363Sgblack@eecs.umich.edu    if (rxKickTick > curTick) {
7007363Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
7017363Sgblack@eecs.umich.edu                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<Tick> cycle_time;
1364    Param<Tick> tx_delay;
1365    Param<Tick> rx_delay;
1366    Param<Tick> intr_delay;
1367    SimObjectParam<MemoryController *> mmu;
1368    SimObjectParam<PhysicalMemory *> physmem;
1369    Param<bool> rx_filter;
1370    Param<string> hardware_address;
1371    SimObjectParam<Bus*> header_bus;
1372    SimObjectParam<Bus*> payload_bus;
1373    SimObjectParam<HierParams *> hier;
1374    Param<Tick> pio_latency;
1375    SimObjectParam<PciConfigAll *> configspace;
1376    SimObjectParam<PciConfigData *> configdata;
1377    SimObjectParam<Platform *> platform;
1378    Param<uint32_t> pci_bus;
1379    Param<uint32_t> pci_dev;
1380    Param<uint32_t> pci_func;
1381    Param<uint32_t> rx_max_copy;
1382    Param<uint32_t> tx_max_copy;
1383    Param<uint32_t> rx_fifo_size;
1384    Param<uint32_t> tx_fifo_size;
1385    Param<uint32_t> rx_fifo_threshold;
1386    Param<uint32_t> tx_fifo_threshold;
1387    Param<Tick> dma_read_delay;
1388    Param<Tick> dma_read_factor;
1389    Param<Tick> dma_write_delay;
1390    Param<Tick> dma_write_factor;
1391
1392END_DECLARE_SIM_OBJECT_PARAMS(Device)
1393
1394BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1395
1396    INIT_PARAM(cycle_time, "State machine cycle time"),
1397    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
1398    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
1399    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
1400    INIT_PARAM(mmu, "Memory Controller"),
1401    INIT_PARAM(physmem, "Physical Memory"),
1402    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
1403    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
1404                    "00:99:00:00:00:01"),
1405    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
1406    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
1407    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
1408    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
1409    INIT_PARAM(configspace, "PCI Configspace"),
1410    INIT_PARAM(configdata, "PCI Config data"),
1411    INIT_PARAM(platform, "Platform"),
1412    INIT_PARAM(pci_bus, "PCI bus"),
1413    INIT_PARAM(pci_dev, "PCI device number"),
1414    INIT_PARAM(pci_func, "PCI function code"),
1415    INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024),
1416    INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024),
1417    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024),
1418    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024),
1419    INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024),
1420    INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024),
1421    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
1422    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
1423    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
1424    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0)
1425
1426END_INIT_SIM_OBJECT_PARAMS(Device)
1427
1428
1429CREATE_SIM_OBJECT(Device)
1430{
1431    Device::Params *params = new Device::Params;
1432    params->name = getInstanceName();
1433    params->intr_delay = intr_delay;
1434    params->physmem = physmem;
1435    params->cycle_time = cycle_time;
1436    params->tx_delay = tx_delay;
1437    params->rx_delay = rx_delay;
1438    params->mmu = mmu;
1439    params->hier = hier;
1440    params->header_bus = header_bus;
1441    params->payload_bus = payload_bus;
1442    params->pio_latency = pio_latency;
1443    params->configSpace = configspace;
1444    params->configData = configdata;
1445    params->plat = platform;
1446    params->busNum = pci_bus;
1447    params->deviceNum = pci_dev;
1448    params->functionNum = pci_func;
1449    params->rx_filter = rx_filter;
1450    params->eaddr = hardware_address;
1451    params->rx_max_copy = rx_max_copy;
1452    params->tx_max_copy = tx_max_copy;
1453    params->rx_fifo_size = rx_fifo_size;
1454    params->tx_fifo_size = tx_fifo_size;
1455    params->rx_fifo_threshold = rx_fifo_threshold;
1456    params->tx_fifo_threshold = tx_fifo_threshold;
1457    params->dma_read_delay = dma_read_delay;
1458    params->dma_read_factor = dma_read_factor;
1459    params->dma_write_delay = dma_write_delay;
1460    params->dma_write_factor = dma_write_factor;
1461    return new Device(params);
1462}
1463
1464REGISTER_SIM_OBJECT("Sinic", Device)
1465
1466/* namespace Sinic */ }
1467