first pass at ns_ethernet device. more will come later as i merge in nate's new...
authorLisa Hsu <hsul@eecs.umich.edu>
Fri, 12 Mar 2004 16:04:58 +0000 (11:04 -0500)
committerLisa Hsu <hsul@eecs.umich.edu>
Fri, 12 Mar 2004 16:04:58 +0000 (11:04 -0500)
dev/etherpkt.hh:
    add some stuff for support of the NS ethernet device.

--HG--
extra : convert_revision : 51f6508463b6394055e3428a42b7de490a9ae6c1

dev/etherpkt.hh
dev/ns_gige.cc [new file with mode: 0644]
dev/ns_gige.hh [new file with mode: 0644]
dev/ns_gige_reg.h [new file with mode: 0644]

index c91322526022b3703960ab7c8c7b9fd9a3f9d2da..312d98f640ec29d8b3fb012dbd575058be6c2b30 100644 (file)
 #include <memory>
 
 #include "sim/host.hh"
-
 #include "base/refcnt.hh"
 
+#define EADDR_LEN 6
+
 class Checkpoint;
 
+struct pseudo_header
+{
+    uint32_t src_ip_addr;
+    uint32_t dest_ip_addr;
+    uint16_t protocol;
+    uint16_t len;
+};
+
+/** Ethernet header struct for casting purposes */
+struct eth_header
+{
+    uint8_t dest[EADDR_LEN];
+    uint8_t src[EADDR_LEN];
+    uint16_t type;
+};
+
+struct ip_header
+{
+    uint8_t vers_len;
+    uint8_t service_type;
+    uint16_t dgram_len;
+    uint16_t ID;
+    uint16_t flags_frag_offset;
+    uint8_t TTL;
+    uint8_t protocol;
+    uint16_t hdr_chksum;
+    uint32_t src_ip_addr;
+    uint32_t dest_ip_addr;
+    uint8_t *options;
+    uint8_t *transport_header;
+};
+
+struct tcp_header
+{
+    uint16_t src_port_num;
+    uint16_t dest_port_num;
+    uint32_t seq_num;
+    uint32_t ack_num;
+    uint8_t hdr_len;
+    uint8_t flags;
+    uint16_t rcv_window;
+    uint16_t chksum;
+    uint16_t urgent;
+    uint8_t *options;
+    uint8_t *data;
+};
+
+struct udp_header
+{
+    uint16_t src_port_num;
+    uint16_t dest_port_num;
+    uint16_t len;
+    uint16_t chksum;
+    uint8_t *data;
+};
+
 /*
  * Reference counted class containing ethernet packet data
  */
@@ -61,6 +118,16 @@ class EtherPacket : public RefCounted
     bool IsMulticast() { return data[0] == 0x01; }
     bool IsBroadcast() { return data[0] == 0xff; }
 
+    ip_header *getIpHdr() { return (ip_header *) (data + 14); }
+
+    void *getTransportHdr() {
+        ip_header *ip = getIpHdr();
+        return (void *) (ip + (ip->vers_len & 0xf));
+    }
+
+
+    typedef RefCountingPtr<EtherPacket> PacketPtr;
+
     void serialize(std::ostream &os);
     void unserialize(Checkpoint *cp, const std::string &section);
 };
diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc
new file mode 100644 (file)
index 0000000..e3c3159
--- /dev/null
@@ -0,0 +1,1933 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller.  Does not support priority queueing
+ */
+#include <cstdio>
+#include <deque>
+#include <string>
+
+#include "base/inet.hh"
+#include "cpu/exec_context.hh"
+#include "cpu/intr_control.hh"
+#include "dev/dma.hh"
+#include "dev/ns_gige.hh"
+#include "dev/etherlink.hh"
+#include "mem/functional_mem/memory_control.hh"
+#include "mem/functional_mem/physical_memory.hh"
+#include "sim/builder.hh"
+#include "sim/host.hh"
+#include "sim/sim_stats.hh"
+#include "targetarch/vtophys.hh"
+
+using namespace std;
+
+///////////////////////////////////////////////////////////////////////
+//
+// EtherDev PCI Device
+//
+EtherDev::EtherDev(const string &_name, DmaEngine *de, bool use_interface,
+                   IntrControl *i, MemoryController *mmu, PhysicalMemory *pmem,
+                   PCIConfigAll *cf, PciConfigData *cd, Tsunami *t, uint32_t bus,
+                   uint32_t dev, uint32_t func, bool rx_filter,
+                   const int eaddr[6], Tick tx_delay, Tick rx_delay, Addr addr,
+                   Addr mask)
+    : PciDev(_name, mmu, cf, cd, bus, dev, func), tsunami(t),
+      addr(addr), mask(mask), txPacketLen(0),
+      txPacketBufPtr(NULL), rxPacketBufPtr(NULL), rxDescBufPtr(NULL),
+      fragLen(0), rxCopied(0), txState(txIdle), CTDD(false), txFifoCnt(0),
+      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), txPacketFlag(false),
+      txFragPtr(0), txDescCnt(0), rxState(rxIdle), CRDD(false),
+      rxPktBytes(0), rxFifoCnt(0), rxHalt(false), rxPacketFlag(false),
+      rxFragPtr(0), rxDescCnt(0), extstsEnable(false), maxTxBurst(0),
+      maxRxBurst(0), physmem(pmem),
+      rxDescDoneCB(this), rxDoneCB(this), txDescDoneCB(this), txDoneCB(this),
+      dma(de), readRequest(use_interface), writeRequest(use_interface),
+      readDescRequest(use_interface), writeDescRequest(use_interface),
+      interface(NULL), intctrl(i), txDelay(tx_delay), rxDelay(rx_delay),
+      txEvent(this), cpuPendingIntr(false), rxFilterEnable(rx_filter),
+      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
+      acceptPerfect(false), acceptArp(false)
+{
+    tsunami->ethernet = this;
+
+    memset(&regs, 0, sizeof(regs));
+    regsReset();
+    regs.perfectMatch[0] = eaddr[0];
+    regs.perfectMatch[1] = eaddr[1];
+    regs.perfectMatch[2] = eaddr[2];
+    regs.perfectMatch[3] = eaddr[3];
+    regs.perfectMatch[4] = eaddr[4];
+    regs.perfectMatch[5] = eaddr[5];
+
+}
+
+EtherDev::~EtherDev()
+{}
+
+void
+EtherDev::regStats()
+{
+    txBytes
+        .name(name() + ".txBytes")
+        .desc("Bytes Transmitted")
+        .prereq(txBytes)
+        ;
+
+    rxBytes
+        .name(name() + ".rxBytes")
+        .desc("Bytes Received")
+        .prereq(rxBytes)
+        ;
+
+    txPackets
+        .name(name() + ".txPackets")
+        .desc("Number of Packets Transmitted")
+        .prereq(txBytes)
+        ;
+
+    rxPackets
+        .name(name() + ".rxPackets")
+        .desc("Number of Packets Received")
+        .prereq(rxBytes)
+        ;
+
+    txBandwidth
+        .name(name() + ".txBandwidth")
+        .desc("Transmit Bandwidth (bits/s)")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxBandwidth
+        .name(name() + ".rxBandwidth")
+        .desc("Receive Bandwidth (bits/s)")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    txPacketRate
+        .name(name() + ".txPPS")
+        .desc("Packet Tranmission Rate (packets/s)")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxPacketRate
+        .name(name() + ".rxPPS")
+        .desc("Packet Reception Rate (packets/s)")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    txBandwidth = txBytes * Statistics::constant(8) / simSeconds;
+    rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds;
+    txPacketRate = txPackets / simSeconds;
+    rxPacketRate = rxPackets / simSeconds;
+}
+
+void
+EtherDev::ReadConfig(int offset, int size, uint8_t *data)
+{
+    if (offset < PCI_DEVICE_SPECIFIC)
+        PciDev::ReadConfig(offset, size, data);
+    else {
+        panic("need to do this\n");
+    }
+}
+
+void
+EtherDev::WriteConfig(int offset, int size, uint32_t data)
+{
+    if (offset < PCI_DEVICE_SPECIFIC)
+        PciDev::WriteConfig(offset, size, data);
+    else
+        panic("Need to do that\n");
+}
+
+Fault
+EtherDev::read(MemReqPtr req, uint8_t *data)
+{
+    DPRINTF(Ethernet, "read  va=%#x size=%d\n", req->vaddr, req->size);
+
+    Addr daddr = req->paddr - addr;
+
+    if (daddr > LAST)
+        panic("Accessing reserved register");
+
+    switch (req->size) {
+      case sizeof(uint32_t):
+        {
+            uint32_t &reg = *(uint32_t *)data;
+
+            switch (daddr) {
+              case CR:
+                reg = regs.command;
+                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
+                break;
+
+              case CFG:
+                reg = regs.config;
+                break;
+
+              case MEAR:
+                reg = regs.mear;
+                break;
+
+              case PTSCR:
+                reg = regs.ptscr;
+                break;
+
+              case ISR:
+                reg = regs.isr;
+                regs.isr = 0;
+                break;
+
+              case IMR:
+                reg = regs.imr;
+                break;
+
+              case IER:
+                reg = regs.ier;
+                break;
+
+              case IHR:
+                reg = regs.ihr;
+                break;
+
+              case TXDP:
+                reg = regs.txdp;
+                break;
+
+              case TXDP_HI:
+                reg = regs.txdp_hi;
+                break;
+
+              case TXCFG:
+                reg = regs.txcfg;
+                break;
+
+              case GPIOR:
+                reg = regs.gpior;
+                break;
+
+              case RXDP:
+                reg = regs.rxdp;
+                break;
+
+              case RXDP_HI:
+                reg = regs.rxdp_hi;
+                break;
+
+              case RXCFG:
+                reg = regs.rxcfg;
+                break;
+
+              case PQCR:
+                reg = regs.pqcr;
+                break;
+
+              case WCSR:
+                reg = regs.wcsr;
+                break;
+
+              case PCR:
+                reg = regs.pcr;
+                break;
+
+              case RFCR:
+                reg = regs.rfcr;
+                break;
+
+              case RFDR:
+
+                switch (regs.rfcr & RFCR_RFADDR) {
+                  case 0x000:
+                    reg = regs.perfectMatch[1] << 8;
+                    reg += regs.perfectMatch[0];
+                    break;
+                  case 0x002:
+                    reg = regs.perfectMatch[3] << 8;
+                    reg += regs.perfectMatch[2];
+                    break;
+                  case 0x004:
+                    reg = regs.perfectMatch[5] << 8;
+                    reg += regs.perfectMatch[4];
+                    break;
+                  default:
+                    panic("reading from RFDR for something for other than PMATCH!\n");
+                    //didn't implement other RFDR functionality b/c driver didn't use
+                }
+                break;
+
+              case SRR:
+                reg = regs.srr;
+                break;
+
+              case MIBC:
+                reg = regs.mibc;
+                reg &= ~(MIBC_MIBS | MIBC_ACLR);
+                break;
+
+              case VRCR:
+                reg = regs.vrcr;
+                break;
+
+              case VTCR:
+                reg = regs.vtcr;
+                break;
+
+              case VDR:
+                reg = regs.vdr;
+                break;
+
+              case CCSR:
+                reg = regs.ccsr;
+                break;
+
+              case TBICR:
+                reg = regs.tbicr;
+                break;
+
+              case TBISR:
+                reg = regs.tbisr;
+                break;
+
+              case TANAR:
+                reg = regs.tanar;
+                break;
+
+              case TANLPAR:
+                reg = regs.tanlpar;
+                break;
+
+              case TANER:
+                reg = regs.taner;
+                break;
+
+              case TESR:
+                reg = regs.tesr;
+                break;
+
+              default:
+                panic("reading unimplemented register: addr = %#x", daddr);
+            }
+
+            DPRINTF(Ethernet, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
+        }
+        break;
+
+      default:
+        panic("accessing register with invalid size: addr=%#x, size=%d",
+              daddr, req->size);
+    }
+
+    return No_Fault;
+}
+
+Fault
+EtherDev::write(MemReqPtr req, const uint8_t *data)
+{
+    DPRINTF(Ethernet, "write va=%#x size=%d\n", req->vaddr, req->size);
+
+    Addr daddr = req->paddr - addr;
+
+    if (daddr > LAST && daddr <= RESERVED)
+        panic("Accessing reserved register");
+
+    if (daddr > RESERVED)
+        panic("higher memory accesses not implemented!\n");
+
+    if (req->size == sizeof(uint32_t)) {
+        uint32_t reg = *(uint32_t *)data;
+        DPRINTF(Ethernet, "write data=%d data=%#x\n", reg, reg);
+
+        switch (daddr) {
+          case CR:
+            regs.command = reg;
+            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
+                txHalt = true;
+            } else if (reg & CR_TXE) {
+                if (txState == txIdle)
+                    txKick();
+            } else if (reg & CR_TXD) {
+                txHalt = true;
+            }
+
+            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
+                rxHalt = true;
+            } else if (reg & CR_RXE) {
+                if (rxState == rxIdle) {
+                    rxKick();
+                }
+            } else if (reg & CR_RXD) {
+                rxHalt = true;
+            }
+
+            if (reg & CR_TXR)
+                txReset();
+
+            if (reg & CR_RXR)
+                rxReset();
+
+            if (reg & CR_SWI)
+                devIntrPost(ISR_SWI);
+
+            if (reg & CR_RST) {
+                txReset();
+                rxReset();
+                regsReset();
+            }
+            break;
+
+          case CFG:
+            regs.config = reg;
+            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
+                || reg & CFG_RESERVED || reg & CFG_T64ADDR
+                || reg & CFG_PCI64_DET)
+                panic("writing to read-only or reserved CFG bits!\n");
+
+#if 0
+              if (reg & CFG_TBI_EN) ;
+              if (reg & CFG_MODE_1000) ;
+#endif
+
+            if (reg & CFG_AUTO_1000)
+                panic("CFG_AUTO_1000 not implemented!\n");
+
+#if 0
+            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
+            if (reg & CFG_TMRTEST) ;
+            if (reg & CFG_MRM_DIS) ;
+            if (reg & CFG_MWI_DIS) ;
+#endif
+
+            if (reg & CFG_T64ADDR)
+                panic("CFG_T64ADDR is read only register!\n");
+
+            if (reg & CFG_PCI64_DET)
+                panic("CFG_PCI64_DET is read only register!\n");
+
+#if 0
+              if (reg & CFG_DATA64_EN) ;
+              if (reg & CFG_M64ADDR) ;
+              if (reg & CFG_PHY_RST) ;
+              if (reg & CFG_PHY_DIS) ;
+#endif
+
+            if (reg & CFG_EXTSTS_EN)
+                extstsEnable = true;
+            else
+                extstsEnable = false;
+
+#if 0
+              if (reg & CFG_REQALG) ;
+              if (reg & CFG_SB) ;
+              if (reg & CFG_POW) ;
+              if (reg & CFG_EXD) ;
+              if (reg & CFG_PESEL) ;
+              if (reg & CFG_BROM_DIS) ;
+              if (reg & CFG_EXT_125) ;
+              if (reg & CFG_BEM) ;
+#endif
+            break;
+
+          case MEAR:
+            regs.mear = reg;
+            /* since phy is completely faked, MEAR_MD* don't matter
+               and since the driver never uses MEAR_EE*, they don't matter */
+#if 0
+            if (reg & MEAR_EEDI) ;
+            if (reg & MEAR_EEDO) ; //this one is read only
+            if (reg & MEAR_EECLK) ;
+            if (reg & MEAR_EESEL) ;
+            if (reg & MEAR_MDIO) ;
+            if (reg & MEAR_MDDIR) ;
+            if (reg & MEAR_MDC) ;
+#endif
+            break;
+
+          case PTSCR:
+            regs.ptscr = reg;
+            /* these control BISTs for various parts of chip - we don't care or do */
+            break;
+
+          case ISR: /* writing to the ISR has no effect */
+            panic("ISR is a read only register!\n");
+
+          case IMR:
+            regs.imr = reg;
+            devIntrChangeMask();
+            break;
+
+          case IER:
+            regs.ier = reg;
+            break;
+
+          case IHR:
+            regs.ihr = reg;
+            /* not going to implement real interrupt holdoff */
+            break;
+
+          case TXDP:
+            regs.txdp = (reg & 0xFFFFFFFC);
+            assert(txState == txIdle);
+            CTDD = false;
+            break;
+
+          case TXDP_HI:
+            regs.txdp_hi = reg;
+            break;
+
+          case TXCFG:
+            regs.txcfg = reg;
+#if 0
+            if (reg & TXCFG_CSI) ;
+            if (reg & TXCFG_HBI) ;
+            if (reg & TXCFG_MLB) ;
+            if (reg & TXCFG_ATP) ;
+            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
+                                           considering the network is just a fake
+                                           pipe, wouldn't make sense to do this */
+
+            if (reg & TXCFG_BRST_DIS) ;
+#endif
+
+#if 0 /* current 2.6 driver doesn't use these.  if we upgrade, may need these */
+            if (reg & TXCFG_MXDMA1024)
+                maxTxBurst = 1024;
+
+            if (reg & TXCFG_MXDMA8)
+                maxTxBurst = 8;
+
+            if (reg & TXCFG_MXDMA16)
+                maxTxBurst = 16;
+
+            if (reg & TXCFG_MXDMA32)
+                maxTxBurst = 32;
+
+            if (reg & TXCFG_MXDMA64)
+                maxTxBurst = 64;
+
+            if (reg & TXCFG_MXDMA128)
+                maxTxBurst = 128;
+
+            if (reg & TXCFG_MXDMA256)
+                maxTxBurst = 256;
+#endif
+
+            if (reg & TXCFG_MXDMA512)
+                maxTxBurst = 512;
+
+            break;
+
+          case GPIOR:
+            regs.gpior = reg;
+            /* these just control general purpose i/o pins, don't matter */
+            break;
+
+          case RXCFG:
+            regs.rxcfg = reg;
+#if 0
+            if (reg & RXCFG_AEP) ;
+            if (reg & RXCFG_ARP) ;
+            if (reg & RXCFG_STRIPCRC) ;
+            if (reg & RXCFG_RX_RD) ;
+            if (reg & RXCFG_ALP) ;
+            if (reg & RXCFG_AIRL) ;
+#endif
+
+            if (reg & RXCFG_MXDMA512)
+                maxRxBurst = 512;
+
+#if 0
+            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
+#endif
+            break;
+
+          case PQCR:
+            /* there is no priority queueing used in the linux 2.6 driver */
+            regs.pqcr = reg;
+            break;
+
+          case WCSR:
+            /* not going to implement wake on LAN */
+            regs.wcsr = reg;
+            break;
+
+          case PCR:
+            /* not going to implement pause control */
+            regs.pcr = reg;
+            break;
+
+          case RFCR:
+            regs.rfcr = reg;
+            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
+
+            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
+
+            acceptMulticast = (reg & RFCR_AAM) ? true : false;
+
+            acceptUnicast = (reg & RFCR_AAU) ? true : false;
+
+            acceptPerfect = (reg & RFCR_APM) ? true : false;
+
+            acceptArp = (reg & RFCR_AARP) ? true : false;
+
+            if (reg & RFCR_APAT)
+                panic("RFCR_APAT not implemented!\n");
+
+            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
+                panic("hash filtering not implemented!\n");
+
+            if (reg & RFCR_ULM)
+                panic("RFCR_ULM not implemented!\n");
+
+            break;
+
+          case RFDR:
+            panic("the driver never writes to RFDR, something is wrong!\n");
+
+          case BRAR:
+            panic("the driver never uses BRAR, something is wrong!\n");
+
+          case BRDR:
+            panic("the driver never uses BRDR, something is wrong!\n");
+
+          case SRR:
+            panic("SRR is read only register!\n");
+
+          case MIBC:
+            panic("the driver never uses MIBC, something is wrong!\n");
+
+          case VRCR:
+            regs.vrcr = reg;
+            break;
+
+          case VTCR:
+            regs.vtcr = reg;
+            break;
+
+          case VDR:
+            panic("the driver never uses VDR, something is wrong!\n");
+            break;
+
+          case CCSR:
+            /* not going to implement clockrun stuff */
+            regs.ccsr = reg;
+            break;
+
+          case TBICR:
+            regs.tbicr = reg;
+            if (reg & TBICR_MR_LOOPBACK)
+                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
+
+            if (reg & TBICR_MR_AN_ENABLE) {
+                regs.tanlpar = regs.tanar;
+                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
+            }
+
+#if 0
+            if (reg & TBICR_MR_RESTART_AN) ;
+#endif
+
+            break;
+
+          case TBISR:
+            panic("TBISR is read only register!\n");
+
+          case TANAR:
+            regs.tanar = reg;
+            if (reg & TANAR_PS2)
+                panic("this isn't used in driver, something wrong!\n");
+
+            if (reg & TANAR_PS1)
+                panic("this isn't used in driver, something wrong!\n");
+            break;
+
+          case TANLPAR:
+            panic("this should only be written to by the fake phy!\n");
+
+          case TANER:
+            panic("TANER is read only register!\n");
+
+          case TESR:
+            regs.tesr = reg;
+            break;
+
+          default:
+            panic("thought i covered all the register, what is this? addr=%#x",
+                  daddr);
+        }
+    } else
+        panic("Invalid Request Size");
+
+    return No_Fault;
+}
+
+void
+EtherDev::devIntrPost(uint32_t interrupts)
+{
+DPRINTF(Ethernet, "interrupt posted intr=%x isr=%x imr=%x\n",
+    interrupts, regs.isr, regs.imr);
+
+if (interrupts & ISR_RESERVE)
+    panic("Cannot set a reserved interrupt");
+
+if (interrupts & ISR_TXRCMP)
+    regs.isr |= ISR_TXRCMP;
+
+if (interrupts & ISR_RXRCMP)
+    regs.isr |= ISR_RXRCMP;
+
+//ISR_DPERR  not implemented
+//ISR_SSERR not implemented
+//ISR_RMABT not implemented
+//ISR_RXSOVR not implemented
+//ISR_HIBINT not implemented
+//ISR_PHY not implemented
+//ISR_PME not implemented
+
+if (interrupts & ISR_SWI)
+    regs.isr |= ISR_SWI;
+
+//ISR_MIB not implemented
+//ISR_TXURN not implemented
+
+ if (interrupts & ISR_TXIDLE)
+     regs.isr |= ISR_TXIDLE;
+
+ if (interrupts & ISR_TXERR)
+     regs.isr |= ISR_TXERR;
+
+ if (interrupts & ISR_TXDESC)
+     regs.isr |= ISR_TXDESC;
+
+ if (interrupts & ISR_TXOK)
+     regs.isr |= ISR_TXOK;
+
+ if (interrupts & ISR_RXORN)
+     regs.isr |= ISR_RXORN;
+
+ if (interrupts & ISR_RXIDLE)
+     regs.isr |= ISR_RXIDLE;
+
+//ISR_RXEARLY not implemented
+
+ if (interrupts & ISR_RXERR)
+     regs.isr |= ISR_RXERR;
+
+ if (interrupts & ISR_RXOK)
+     regs.isr |= ISR_RXOK;
+
+ if ((regs.isr & regs.imr))
+        cpuIntrPost();
+}
+
+void
+EtherDev::devIntrClear(uint32_t interrupts)
+{
+    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
+            interrupts, regs.isr, regs.imr);
+
+    if (interrupts & ISR_RESERVE)
+        panic("Cannot clear a reserved interrupt");
+
+    if (interrupts & ISR_TXRCMP)
+        regs.isr &= ~ISR_TXRCMP;
+
+    if (interrupts & ISR_RXRCMP)
+        regs.isr &= ~ISR_RXRCMP;
+
+//ISR_DPERR  not implemented
+//ISR_SSERR not implemented
+//ISR_RMABT not implemented
+//ISR_RXSOVR not implemented
+//ISR_HIBINT not implemented
+//ISR_PHY not implemented
+//ISR_PME not implemented
+
+    if (interrupts & ISR_SWI)
+        regs.isr &= ~ISR_SWI;
+
+//ISR_MIB not implemented
+//ISR_TXURN not implemented
+
+    if (interrupts & ISR_TXIDLE)
+        regs.isr &= ~ISR_TXIDLE;
+
+    if (interrupts & ISR_TXERR)
+        regs.isr &= ~ISR_TXERR;
+
+    if (interrupts & ISR_TXDESC)
+        regs.isr &= ~ISR_TXDESC;
+
+    if (interrupts & ISR_TXOK)
+        regs.isr &= ~ISR_TXOK;
+
+    if (interrupts & ISR_RXORN)
+        regs.isr &= ~ISR_RXORN;
+
+    if (interrupts & ISR_RXIDLE)
+        regs.isr &= ~ISR_RXIDLE;
+
+//ISR_RXEARLY not implemented
+
+    if (interrupts & ISR_RXERR)
+        regs.isr &= ~ISR_RXERR;
+
+    if (interrupts & ISR_RXOK)
+        regs.isr &= ~ISR_RXOK;
+
+    if ((regs.isr & regs.imr))
+        cpuIntrPost();
+
+    if (!(regs.isr & regs.imr))
+        cpuIntrClear();
+}
+
+void
+EtherDev::devIntrChangeMask()
+{
+    DPRINTF(Ethernet, "iterrupt mask changed\n");
+
+    if (regs.isr & regs.imr)
+        cpuIntrPost();
+    else
+        cpuIntrClear();
+}
+
+void
+EtherDev::cpuIntrPost()
+{
+    if (!cpuPendingIntr) {
+        if (regs.ier) {
+            cpuPendingIntr = true;
+            intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+        }
+    }
+}
+
+void
+EtherDev::cpuIntrClear()
+{
+    if (cpuPendingIntr) {
+        cpuPendingIntr = false;
+        intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+    }
+}
+
+bool
+EtherDev::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+EtherDev::txReset()
+{
+
+    DPRINTF(Ethernet, "transmit reset\n");
+
+    txPacketFlag = false;
+    CTDD = false;
+    txFifoCnt = 0;
+    txFifoAvail = 0;
+    txHalt = false;
+    txFifo.clear();
+    descAddrFifo.clear();
+    regs.command &= ~CR_TXE;
+    txState = txIdle;
+}
+
+void
+EtherDev::rxReset()
+{
+    DPRINTF(Ethernet, "receive reset\n");
+
+    rxPacketFlag = false;
+    CRDD = false;
+    fragLen = 0;
+    rxFifoCnt = 0;
+    rxHalt = false;
+    rxFifo.clear();
+    regs.command &= ~CR_RXE;
+    rxState = rxIdle;
+}
+
+/**
+ * This sets up a DMA transfer to read one data segment from the rxFifo into
+ * the buffer indicated by rxDescCache.bufptr. Assumes the value of rxFragPtr
+ * is already correctly set.
+ */
+void
+EtherDev::writeOneFrag()
+{
+    /* i think there is no need for an "in use" warning here like in old */
+    fragLen = rxFifo.front()->length; //length of whole packet
+    fragLen = (fragLen < rxDescCnt) ? fragLen : rxDescCnt;
+
+    writePhys.addr = rxFragPtr;
+    writePhys.length = fragLen;
+
+    // Set up DMA request area
+    writeRequest.init(&rxDoneCB, 0, false, &writePhys, 1, fragLen,
+                     rxDescBufPtr, fragLen, curTick);
+
+    dma->doTransfer(&readRequest);
+}
+
+void
+EtherDev::rxKick()
+{
+    DPRINTF(Ethernet, "receive state machine activated!\n");
+
+    if (CRDD) {
+        rxState = rxDescRefr;
+        readOneDesc(rx, LINK_LEN);
+    } else {
+        rxState = rxDescRead;
+        readOneDesc(rx);
+    }
+}
+
+EtherDev::RxDescDone::RxDescDone(EtherDev *e)
+    : ethernet(e)
+{
+}
+
+std::string
+EtherDev::RxDescDone::name() const
+{
+    return ethernet->name() + ".rxDescDoneCB";
+}
+
+void
+EtherDev::RxDescDone::process()
+{
+    DPRINTF(Ethernet, "receive descriptor done callback\n");
+    ethernet->rxDescDone();
+}
+
+void
+EtherDev::rxDescDone()
+{
+    if (rxState == rxDescRefr) {
+        if (rxDescCache.link == 0) {
+            rxState = rxIdle;
+            regs.command &= ~CR_RXE;
+            devIntrPost(ISR_RXIDLE);
+            return;
+        } else {
+            rxState = rxDescRead;
+            regs.rxdp = rxDescCache.link;
+            CRDD = false;
+            readOneDesc(rx);
+        }
+    } else if (rxState == rxDescRead) {
+        if (rxDescCache.cmdsts & CMDSTS_OWN) {
+            rxState = rxIdle;
+            regs.command &= ~CR_RXE;
+            devIntrPost(ISR_RXIDLE);
+        } else {
+            rxState = rxFifoBlock;
+            rxFragPtr = rxDescCache.bufptr;
+            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
+
+            if (!rxFifo.empty()) {
+                rxState = rxFragWrite;
+                if (!rxPacketFlag) { // reading a new packet
+                    rxPacketBufPtr = rxFifo.front()->data;
+                    rxPacketBufPtr -= rxDescCnt;
+                    rxDescBufPtr = rxPacketBufPtr;
+                    rxCopied = 0;
+                } else {
+                    rxDescBufPtr = rxPacketBufPtr - rxDescCnt;
+                }
+                writeOneFrag();
+            }
+        }
+    } else if (rxState == rxDescWrite) {
+        devIntrPost(ISR_RXOK);
+
+        if (rxDescCache.cmdsts & CMDSTS_INTR)
+            devIntrPost(ISR_RXDESC);
+
+        if (rxDescCache.link == 0 || ((rxPktBytes != 0) && rxHalt)) {
+            rxState = rxIdle;
+            regs.command &= ~CR_RXE;
+            devIntrPost(ISR_RXIDLE);
+            rxHalt = false;
+        } else {
+            rxState = rxDescRead;
+            regs.rxdp = rxDescCache.link;
+            CRDD = false;
+            readOneDesc(rx);
+        }
+    }
+}
+
+EtherDev::RxDone::RxDone(EtherDev *e)
+    : ethernet(e)
+{
+}
+
+std::string
+EtherDev::RxDone::name() const
+{
+    return ethernet->name() + ".rxDoneCB";
+}
+
+void
+EtherDev::RxDone::process()
+{
+    DPRINTF(Ethernet, "receive done callback\n");
+    ethernet->rxDone();
+}
+
+void
+EtherDev::rxDone()
+{
+    DPRINTF(Ethernet, "packet received to host memory\n");
+
+    if (!rxDescCache.cmdsts & CMDSTS_OWN)
+        panic("This descriptor is already owned by the driver!\n");
+
+    rxState = rxFifoBlock;
+    rxCopied += fragLen;
+    rxFifoCnt -= fragLen;
+
+    if (rxDescCnt) { /* there is still data left in the descriptor */
+        rxState = rxFragWrite;
+        rxDescBufPtr += fragLen;
+        writeOneFrag();
+    } else {
+        rxState = rxDescWrite;
+        if (rxPktBytes == 0) {  /* packet is done */
+            rxDescCache.cmdsts |= CMDSTS_OWN;
+            rxDescCache.cmdsts &= ~CMDSTS_MORE;
+            rxDescCache.cmdsts |= CMDSTS_OK;
+            rxDescCache.cmdsts += rxCopied;   //i.e. set CMDSTS_SIZE
+
+            rxPacketFlag = false;
+            if (rxFilterEnable) {
+                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
+                if (rxFifo.front()->IsUnicast())
+                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
+                if (rxFifo.front()->IsMulticast())
+                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
+                if (rxFifo.front()->IsBroadcast())
+                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
+            }
+
+            PacketPtr &pkt = rxFifo.front();
+            eth_header *eth = (eth_header *) pkt->data;
+            if (eth->type == 0x800 && extstsEnable) {
+                rxDescCache.extsts |= EXTSTS_IPPKT;
+                if (!ipChecksum(pkt, false))
+                    rxDescCache.extsts |= EXTSTS_IPERR;
+                ip_header *ip = rxFifo.front()->getIpHdr();
+
+                if (ip->protocol == 6) {
+                    rxDescCache.extsts |= EXTSTS_TCPPKT;
+                    if (!tcpChecksum(pkt, false))
+                        rxDescCache.extsts |= EXTSTS_TCPERR;
+                } else if (ip->protocol == 17) {
+                    rxDescCache.extsts |= EXTSTS_UDPPKT;
+                    if (!udpChecksum(pkt, false))
+                        rxDescCache.extsts |= EXTSTS_UDPERR;
+                }
+            }
+
+            rxFifo.front() = NULL;
+            rxFifo.pop_front();
+        } else { /* just the descriptor is done */
+            rxDescCache.cmdsts |= CMDSTS_OWN;
+            rxDescCache.cmdsts |= CMDSTS_MORE;
+        }
+        writeDescPhys.addr = regs.rxdp + LINK_LEN + BUFPTR_LEN;
+        writeDescPhys.length = CMDSTS_LEN;
+
+        writeDescRequest.init(&rxDescDoneCB, 0, true, &writeDescPhys, 1,
+                              CMDSTS_LEN, (uint8_t *) &rxDescCache.cmdsts,
+                              CMDSTS_LEN, curTick);
+    }
+}
+
+/**
+ * This sets up a DMA transfer to read one descriptor into the network device.
+ */
+void
+EtherDev::readOneDesc(dir_t dir, uint32_t len) {
+    readDescPhys.addr = (dir == tx) ? regs.txdp : regs.rxdp;
+    readDescPhys.length = len;
+
+    ns_desc *cache = (dir == tx) ? &txDescCache : &rxDescCache;
+
+    /* THIS ASSUMES THAT DESC_LEN < regs.txcfg's maxdma value,
+       which is 512 bytes in the driver, so i'll just hard code it here */
+    readDescRequest.init(&txDescDoneCB, 0, false, &readDescPhys, 1,
+                         len, (uint8_t *) cache , len, curTick);
+
+    dma->doTransfer(&readDescRequest);
+}
+
+/**
+ * This sets up a DMA transfer to read one data segment of the descriptor in
+ * txDescCache.  Assumes the value of txFragPtr is already correctly set
+ */
+void
+EtherDev::readOneFrag()
+{
+    /* i think there is no need for an "in use" warning here like in old */
+    fragLen = (txDescCnt < txFifoAvail) ? txDescCnt : txFifoAvail;
+    readPhys.addr = txFragPtr;
+    readPhys.length = fragLen;
+
+    // Set up DMA request area
+    readRequest.init(&txDoneCB, 0, false, &readPhys, 1, fragLen,
+                     txPacketBufPtr, fragLen, curTick);
+
+    dma->doTransfer(&readRequest);
+}
+
+void
+EtherDev::transmit()
+{
+    if (txFifo.empty()) {
+        DPRINTF(Ethernet, "nothing to transmit\n");
+        return;
+    }
+
+   if (interface->sendPacket(txFifo.front())) {
+        DPRINTF(Ethernet, "transmit packet\n");
+        txBytes += txFifo.front()->length;
+        txPackets++;
+
+        txFifoCnt -= txFifo.front()->length;
+
+        txFifo.front() = NULL;
+        txFifo.pop_front();
+
+        txDescCache.cmdsts &= ~CMDSTS_OK;
+    } else {
+        txDescCache.cmdsts &= ~CMDSTS_ERR;
+    }
+
+    txDescCache.cmdsts &= ~CMDSTS_OWN;
+
+    writeDescPhys.addr = descAddrFifo.front() + LINK_LEN + BUFPTR_LEN;
+    writeDescPhys.length = CMDSTS_LEN;
+
+    descAddrFifo.front() = 0;
+    descAddrFifo.pop_front();
+
+    writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
+                          writeDescPhys.length,
+                          (uint8_t *) &(txDescCache.cmdsts),
+                          writeDescPhys.length, curTick);
+
+    dma->doTransfer(&writeDescRequest);
+
+    transmit();
+}
+
+void
+EtherDev::txKick()
+{
+    DPRINTF(Ethernet, "transmit state machine activated\n");
+#if 0
+    if (DTRACE(Ethernet))
+        txDump();
+#endif
+
+    if (CTDD) {
+        txState = txDescRefr;
+        readOneDesc(tx, LINK_LEN);
+    } else {
+        txState = txDescRead;
+        readOneDesc(tx);
+    }
+}
+
+EtherDev::TxDescDone::TxDescDone(EtherDev *e)
+    : ethernet(e)
+{
+}
+
+std::string
+EtherDev::TxDescDone::name() const
+{
+    return ethernet->name() + ".txDescDoneCB";
+}
+
+void
+EtherDev::TxDescDone::process()
+{
+    DPRINTF(Ethernet, "transmit descriptor done callback\n");
+    ethernet->txDescDone();
+
+}
+
+void
+EtherDev::txDescDone()
+{
+    if (txState == txFifoBlock) {
+        if (txDescCache.cmdsts & CMDSTS_OK) {
+            devIntrPost(ISR_TXOK);
+        } else if (txDescCache.cmdsts & CMDSTS_ERR) {
+            devIntrPost(ISR_TXERR);
+        }
+    } else if (txState == txDescRefr || txState == txDescWrite) {
+
+        if (txState == txDescWrite) {
+            if (txDescCache.cmdsts & CMDSTS_INTR) {
+                devIntrPost(ISR_TXDESC);
+            }
+        }
+
+        if (txDescCache.link == 0) {
+            txState = txIdle;
+            regs.command &= ~CR_TXE;
+            devIntrPost(ISR_TXIDLE);
+            return;
+        } else {
+            txState = txDescRead;
+            regs.txdp = txDescCache.link;
+            CTDD = false;
+            readOneDesc(tx);
+        }
+    } else if (txState == txDescRead) {
+        if (txDescCache.cmdsts & CMDSTS_OWN) {
+            txState = txFifoBlock;
+            txFragPtr = txDescCache.bufptr;
+            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
+
+            if (txFifoAvail >= ((regs.txcfg & TXCFG_FLTH_MASK) >> 8)) {
+                txState = txFragRead;
+                if (!txPacketFlag) {
+                    txPacketFlag = true;
+                    /* find the total length of this packet */
+                    txPacketLen = txDescCnt;
+                    bool more = txDescCache.cmdsts & CMDSTS_MORE;
+                    uint8_t *addr = (uint8_t *) regs.txdp;
+                    while (more) {
+                        addr = physmem->dma_addr(((ns_desc *) addr)->link, sizeof(ns_desc));
+                        /* !!!!!!mask needed? */
+                        txPacketLen += ((ns_desc *)addr)->cmdsts & CMDSTS_LEN_MASK;
+                        more = ((ns_desc *) addr)->cmdsts & CMDSTS_MORE;
+                    }
+                    PacketPtr &packet = txDoneCB.packet;
+                    packet = new EtherPacket;
+                    packet->length = txPacketLen;
+                    packet->data = new uint8_t[txPacketLen];
+                    txPacketBufPtr = packet->data;
+                }
+                readOneFrag();
+            }
+        } else {
+            txState = txIdle;
+            regs.command &= ~CR_TXE;
+            devIntrPost(ISR_TXIDLE);
+        }
+    }
+}
+
+EtherDev::TxDone::TxDone(EtherDev *e)
+    : ethernet(e)
+{
+}
+
+std::string
+EtherDev::TxDone::name() const
+{
+    return ethernet->name() + ".txDoneCB";
+}
+
+
+void
+EtherDev::TxDone::process()
+{
+    DPRINTF(Ethernet, "transmit done callback\n");
+    ethernet->txDone(packet);
+}
+
+void
+EtherDev::txDone(PacketPtr packet)
+{
+    DPRINTF(Ethernet, "transmit done\n");
+
+    if (!txDescCache.cmdsts & CMDSTS_OWN)
+        panic("This descriptor is already owned by the driver!\n");
+
+    txState = txFifoBlock;
+
+    txPacketBufPtr += fragLen;  /* hope this ptr manipulation is right! */
+    txDescCnt -= fragLen;
+    txFifoCnt += fragLen;
+
+    if (txFifoCnt >= (regs.txcfg & TXCFG_DRTH_MASK)) {
+        if (txFifo.empty()) {
+            txFifoCnt -= (uint32_t) (txPacketBufPtr - packet->data);
+        } else {
+            transmit();
+        }
+    }
+
+    if (txDescCnt) { /* if there is still more data to go in this desc */
+        if (txFifoAvail >= regs.txcfg & TXCFG_FLTH_MASK) {
+            txState = txFragRead;
+            readOneFrag();
+        }
+    } else { /* this descriptor is done */
+        /* but there is more descriptors for this packet */
+        if (txDescCache.cmdsts & CMDSTS_MORE) {
+            txState = txDescWrite;
+            txDescCache.cmdsts &= ~CMDSTS_OWN;
+            writeDescPhys.addr = regs.txdp + LINK_LEN + BUFPTR_LEN;
+            writeDescPhys.length = CMDSTS_LEN;
+
+            writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
+                                  writeDescPhys.length,
+                                  (uint8_t*) &txDescCache.cmdsts,
+                                  writeDescPhys.length, curTick);
+        } else { /* this packet is totally done */
+            /* deal with the the packet that just finished */
+            if (regs.vtcr & VTCR_PPCHK && extstsEnable) {
+                if (txDescCache.extsts & EXTSTS_UDPPKT) {
+                    udpChecksum(packet, true);
+                } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
+                    tcpChecksum(packet, true);
+                } else if (txDescCache.extsts & EXTSTS_IPPKT) {
+                    ipChecksum(packet, true);
+                }
+            }
+
+            txFifo.push_back(packet);
+            transmit();
+            txPacketFlag = false;
+            descAddrFifo.push_back(regs.txdp);
+
+            /* if there is not another descriptor ready for reading, go idle */
+            if (txDescCache.link == 0 || txHalt) {
+                txState = txIdle;
+                devIntrPost(ISR_TXIDLE);
+                txHalt = false;
+            } else { /* else go read next descriptor */
+                txState = txDescRead;
+                regs.txdp = txDescCache.link;
+                CTDD = false;
+                readOneDesc(tx);
+            }
+        }
+    }
+}
+
+void
+EtherDev::transferDone()
+{
+    if (txFifo.empty())
+        return;
+
+    DPRINTF(Ethernet, "schedule transmit\n");
+
+    if (txEvent.scheduled())
+        txEvent.reschedule(curTick + 1);
+    else
+        txEvent.schedule(curTick + 1);
+}
+
+void
+EtherDev::txDump() const
+{
+#if 0
+    int i = tx_ptr;
+    for (int loop = 0; loop < tx_ring_len; loop++) {
+        es_desc *desc = &tx_ring[i];
+
+        if (desc->addr)
+            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
+                    i, desc->addr, desc->length, desc->flags);
+
+        if (++i >= tx_ring_len)
+            i = 0;
+    }
+#endif
+}
+
+void
+EtherDev::rxDump() const
+{
+#if 0
+    int i = rx_ptr;
+    for (int loop = 0; loop < rx_ring_len; loop++) {
+        es_desc *desc = &rx_ring[i];
+
+        if (desc->addr)
+            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
+                    i, desc->addr, desc->length, desc->flags);
+
+        if (++i >= rx_ring_len)
+            i = 0;
+    }
+#endif
+}
+
+bool
+EtherDev::rxFilter(PacketPtr packet)
+{
+    bool drop = true;
+    string type;
+
+    if (packet->IsUnicast()) {
+        type = "unicast";
+
+        // If we're accepting all unicast addresses
+        if (acceptUnicast)
+            drop = false;
+
+        // If we make a perfect match
+        if ((acceptPerfect)
+            && (memcmp(regs.perfectMatch, packet->data, sizeof(regs.perfectMatch)) == 0))
+            drop = false;
+
+        eth_header *eth = (eth_header *) packet->data;
+        if ((acceptArp) && (eth->type == 0x806))
+            drop = false;
+
+    } else if (packet->IsBroadcast()) {
+        type = "broadcast";
+
+        // if we're accepting broadcasts
+        if (acceptBroadcast)
+            drop = false;
+
+    } else if (packet->IsMulticast()) {
+        type = "multicast";
+
+        // if we're accepting all multicasts
+        if (acceptMulticast)
+            drop = false;
+
+    } else {
+        type = "unknown";
+
+        // oh well, punt on this one
+    }
+
+    if (drop) {
+        DPRINTF(Ethernet, "rxFilter drop\n");
+        DDUMP(EthernetData, packet->data, packet->length);
+    }
+
+    return drop;
+}
+
+bool
+EtherDev::recvPacket(PacketPtr packet)
+{
+    rxBytes += packet->length;
+    rxPackets++;
+
+    if (rxState == rxIdle) {
+        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+        interface->recvDone();
+        return true;
+    }
+
+    if (rxFilterEnable && rxFilter(packet)) {
+        DPRINTF(Ethernet, "packet filtered...dropped\n");
+        interface->recvDone();
+        return true;
+    }
+
+    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
+        DPRINTF(Ethernet,
+                "packet will not fit in receive buffer...packet dropped\n");
+        devIntrPost(ISR_RXORN);
+        return false;
+    }
+
+    rxFifo.push_back(packet);
+    rxPktBytes = packet->length;
+    rxFifoCnt += packet->length;
+    interface->recvDone();
+
+    return true;
+}
+
+bool
+EtherDev::udpChecksum(PacketPtr packet, bool gen)
+{
+    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
+
+    ip_header *ip = packet->getIpHdr();
+
+    pseudo_header *pseudo = new pseudo_header;
+
+    pseudo->src_ip_addr = ip->src_ip_addr;
+    pseudo->dest_ip_addr = ip->dest_ip_addr;
+    pseudo->protocol = ip->protocol;
+    pseudo->len = hdr->len;
+
+    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
+                                  (uint32_t) hdr->len);
+
+    delete pseudo;
+    if (gen)
+        hdr->chksum = cksum;
+    else
+        if (cksum != 0)
+            return false;
+
+    return true;
+}
+
+bool
+EtherDev::tcpChecksum(PacketPtr packet, bool gen)
+{
+    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
+
+    ip_header *ip = packet->getIpHdr();
+
+    pseudo_header *pseudo = new pseudo_header;
+
+    pseudo->src_ip_addr = ip->src_ip_addr;
+    pseudo->dest_ip_addr = ip->dest_ip_addr;
+    pseudo->protocol = ip->protocol;
+    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
+
+    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
+                                  (uint32_t) pseudo->len);
+
+    delete pseudo;
+    if (gen)
+        hdr->chksum = cksum;
+    else
+        if (cksum != 0)
+            return false;
+
+    return true;
+}
+
+bool
+EtherDev::ipChecksum(PacketPtr packet, bool gen)
+{
+    ip_header *hdr = packet->getIpHdr();
+
+    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
+
+    if (gen)
+        hdr->hdr_chksum = cksum;
+    else
+        if (cksum != 0)
+            return false;
+
+    return true;
+}
+
+uint16_t
+EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
+{
+    uint32_t sum = 0;
+
+    uint16_t last_pad = 0;
+    if (len & 1) {
+        last_pad = buf[len/2] & 0xff;
+        len--;
+        sum += last_pad;
+    }
+
+    if (pseudo) {
+        sum = pseudo[0] + pseudo[1] + pseudo[2] +
+            pseudo[3] + pseudo[4] + pseudo[5];
+    }
+
+    for (int i=0; i < (len/2); ++i) {
+        sum += buf[i];
+    }
+
+    while (sum >> 16)
+        sum = (sum >> 16) + (sum & 0xffff);
+
+    return ~sum;
+}
+
+//=====================================================================
+//
+//
+void
+dp_regs::serialize(ostream &os)
+{
+    SERIALIZE_SCALAR(command);
+    SERIALIZE_SCALAR(config);
+    SERIALIZE_SCALAR(isr);
+    SERIALIZE_SCALAR(imr);
+}
+
+void
+dp_regs::unserialize(Checkpoint *cp, const std::string &section)
+{
+    UNSERIALIZE_SCALAR(command);
+    UNSERIALIZE_SCALAR(config);
+    UNSERIALIZE_SCALAR(isr);
+    UNSERIALIZE_SCALAR(imr);
+#if 0
+    UNSERIALIZE_SCALAR(tx_ring);
+    UNSERIALIZE_SCALAR(rx_ring);
+    UNSERIALIZE_SCALAR(tx_ring_len);
+    UNSERIALIZE_SCALAR(rx_ring_len);
+    UNSERIALIZE_SCALAR(rom_addr);
+    UNSERIALIZE_SCALAR(rom_data);
+    UNSERIALIZE_SCALAR(rxfilt_ctl);
+    UNSERIALIZE_SCALAR(rxfilt_data);
+
+    UNSERIALIZE_ARRAY(perfect,EADDR_LEN);
+    UNSERIALIZE_ARRAY(hash_table,ES_HASH_SIZE);
+
+    UNSERIALIZE_SCALAR(tx_ring_ptr);
+    UNSERIALIZE_SCALAR(rx_ring_ptr);
+#endif
+}
+
+//---------------------------------------
+
+void
+EtherPacket::serialize(ostream &os)
+{
+    SERIALIZE_SCALAR(length);
+    SERIALIZE_ARRAY(data, length);
+}
+
+void
+EtherPacket::unserialize(Checkpoint *cp, const std::string &section)
+{
+    UNSERIALIZE_SCALAR(length);
+    data = new uint8_t[length];
+    UNSERIALIZE_ARRAY(data, length);
+}
+
+//---------------------------------------
+
+void
+EtherDev::serialize(ostream &os)
+{
+
+#if 0
+    regs.serialize(os);
+
+    // tx_ring & rx_ring are contained in the physmem...
+    SERIALIZE_SCALAR(cpuPendingIntr);
+    SERIALIZE_SCALAR(tx_ptr);
+    SERIALIZE_SCALAR(rx_ptr);
+
+    SERIALIZE_SCALAR(rxDoneCB.ptr);
+    SERIALIZE_SCALAR(rxDoneCB.ignore);
+
+    SERIALIZE_SCALAR(txDoneCB.ptr);
+    SERIALIZE_SCALAR(txDoneCB.ignore);
+
+    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
+        paramOut(os, csprintf("readPhys%d.addr",i),   readPhys[i].addr);
+        paramOut(os, csprintf("readPhys%d.length",i), readPhys[i].length);
+        paramOut(os, csprintf("writePhys%d.addr",i),   writePhys[i].addr);
+        paramOut(os, csprintf("writePhys%d.length",i), writePhys[i].length);
+    }
+
+    SERIALIZE_SCALAR(txEnable);
+    SERIALIZE_SCALAR(rxEnable);
+    SERIALIZE_SCALAR(txDelay);
+    SERIALIZE_SCALAR(rxDelay);
+
+    SERIALIZE_SCALAR(txbuf_len);
+
+    //Calculate the number here, actually dump them at end
+    int numTxPkts=0;
+    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
+        numTxPkts++;
+    }
+    SERIALIZE_SCALAR(numTxPkts);
+
+    SERIALIZE_SCALAR(rxbuf_len);
+    int numRxPkts=0;
+    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
+        numRxPkts++;
+    }
+    SERIALIZE_SCALAR(numRxPkts);
+
+    // output whether the tx and rx packets exist
+    bool txPacketExists = false;
+    if (txDoneCB.packet)
+        txPacketExists = true;
+    SERIALIZE_SCALAR(txPacketExists);
+
+    bool rxPacketExists = false;
+    if (rxPacket)
+        rxPacketExists = true;
+    SERIALIZE_SCALAR(rxPacketExists);
+
+    // output the names (unique by pointer) of the read and write requests
+    paramOut(os, csprintf("readReqName"), readRequest.name());
+    paramOut(os, csprintf("writeReqName"), writeRequest.name());
+
+    // Serialize txPacket, because its data is needed for readRequest
+    if (txPacketExists) {
+        nameOut(os, csprintf("%s.txPacket", name()));
+        txDoneCB.packet->serialize(os);
+    }
+
+    // Serialize rxPacket, because its data is needed for writeRequest
+    if (rxPacketExists) {
+        nameOut(os, csprintf("%s.rxPacket", name()));
+        rxPacket->serialize(os);
+    }
+
+    // create a section for the readRequest
+    nameOut(os, readRequest.name());
+    paramOut(os, csprintf("parent"), name());
+    paramOut(os, csprintf("id"), 0);
+    readRequest.serialize(os);
+
+    // create a section for the writeRequest
+    nameOut(os, writeRequest.name());
+    paramOut(os, csprintf("parent"), name());
+    paramOut(os, csprintf("id"), 1);
+    writeRequest.serialize(os);
+
+    //Redo the buffers, this time outputing them to the file
+    numTxPkts = 0;
+    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
+        nameOut(os, csprintf("%s.txbuf%d", name(),numTxPkts++));
+        (*p)->serialize(os);
+    }
+
+    numRxPkts = 0;
+    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
+        nameOut(os, csprintf("%s.rxbuf%d", name(),numRxPkts++));
+        (*p)->serialize(os);
+    }
+#endif
+}
+
+void
+EtherDev::unserialize(Checkpoint *cp, const std::string &section)
+{
+#if 0
+    regs.unserialize(cp, section);
+
+    UNSERIALIZE_SCALAR(cpuPendingIntr);
+
+    // initialize the tx_ring
+    txReset();
+
+    // initialize the rx_ring
+    rxReset();
+
+    UNSERIALIZE_SCALAR(tx_ptr);
+    UNSERIALIZE_SCALAR(rx_ptr);
+
+    PacketPtr p;
+    UNSERIALIZE_SCALAR(txbuf_len);
+    int numTxPkts;
+    UNSERIALIZE_SCALAR(numTxPkts);
+    for (int i=0; i<numTxPkts; ++i) {
+        p = new EtherPacket;
+        p->unserialize(cp, csprintf("%s.txbuf%d", section, i));
+        txbuf.push_back(p);
+    }
+
+    UNSERIALIZE_SCALAR(rxbuf_len);
+    int numRxPkts;
+    UNSERIALIZE_SCALAR(numRxPkts);
+    for (int i=0; i<numRxPkts; ++i) {
+        p = new EtherPacket;
+        p->unserialize(cp, csprintf("%s.rxbuf%d", section, i));
+        rxbuf.push_back(p);
+    }
+
+    UNSERIALIZE_SCALAR(rxDoneCB.ptr);
+    UNSERIALIZE_SCALAR(rxDoneCB.ignore);
+
+    UNSERIALIZE_SCALAR(txDoneCB.ptr);
+    UNSERIALIZE_SCALAR(txDoneCB.ignore);
+
+    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
+        paramIn(cp, section, csprintf("readPhys%d.addr",i),
+                readPhys[i].addr);
+        paramIn(cp, section, csprintf("readPhys%d.length",i),
+                readPhys[i].length);
+        paramIn(cp, section, csprintf("writePhys%d.addr",i),
+                writePhys[i].addr);
+        paramIn(cp, section, csprintf("writePhys%d.length",i),
+                writePhys[i].length);
+    }
+
+    UNSERIALIZE_SCALAR(txEnable);
+    UNSERIALIZE_SCALAR(rxEnable);
+    UNSERIALIZE_SCALAR(txDelay);
+    UNSERIALIZE_SCALAR(rxDelay);
+
+    // Unserialize the current txPacket
+    bool txPacketExists;
+    UNSERIALIZE_SCALAR(txPacketExists);
+
+    txDoneCB.packet = NULL;
+    if (txPacketExists) {
+        txDoneCB.packet = new EtherPacket;
+        txDoneCB.packet->unserialize(cp, csprintf("%s.txPacket", section));
+    }
+
+    // Unserialize the current rxPacket
+    bool rxPacketExists;
+    UNSERIALIZE_SCALAR(rxPacketExists);
+
+    rxPacket = NULL;
+    if (rxPacketExists) {
+        rxPacket = new EtherPacket;
+        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
+    }
+
+    std::string readReqName, writeReqName;
+    UNSERIALIZE_SCALAR(readReqName);
+    UNSERIALIZE_SCALAR(writeReqName);
+
+    // Unserialize and fixup the readRequest
+    readRequest.unserialize(cp, readReqName);
+    readRequest.phys = readPhys;
+    readRequest.bufferCB = 0;
+    readRequest.dmaDoneCB = &txDoneCB;
+    readRequest.data = NULL;
+
+    if (txDoneCB.packet)
+        readRequest.data = txDoneCB.packet->data;
+
+    // Unserialize and fixup the writeRequest
+    writeRequest.unserialize(cp, writeReqName);
+    writeRequest.phys = writePhys;
+    writeRequest.bufferCB = 0;
+    writeRequest.dmaDoneCB = &rxDoneCB;
+    writeRequest.data = NULL;
+
+    if (rxPacket)
+        writeRequest.data = rxPacket->data;
+#endif
+}
+
+
+//=====================================================================
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
+
+    SimObjectParam<EtherInt *> peer;
+    SimObjectParam<EtherDev *> device;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
+
+    INIT_PARAM_DFLT(peer, "peer interface", NULL),
+    INIT_PARAM(device, "Ethernet device of this interface")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
+
+CREATE_SIM_OBJECT(EtherDevInt)
+{
+    EtherDevInt *dev_int = new EtherDevInt(getInstanceName(), device);
+
+    EtherInt *p = (EtherInt *)peer;
+    if (p) {
+        dev_int->setPeer(p);
+        p->setPeer(dev_int);
+    }
+
+    return dev_int;
+}
+
+REGISTER_SIM_OBJECT("EtherDevInt", EtherDevInt)
+
+
+BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
+
+    Param<Tick> tx_delay;
+    Param<Tick> rx_delay;
+    SimObjectParam<DmaEngine *> engine;
+    Param<bool> use_interface;
+    SimObjectParam<IntrControl *> intr_ctrl;
+    SimObjectParam<MemoryController *> mmu;
+    SimObjectParam<PhysicalMemory *> physmem;
+    Param<Addr> addr;
+    Param<Addr> mask;
+    Param<bool> rx_filter;
+    Param<string> hardware_address;
+    SimObjectParam<PCIConfigAll *> configspace;
+    SimObjectParam<PciConfigData *> configdata;
+    SimObjectParam<Tsunami *> tsunami;
+    Param<uint32_t> pci_bus;
+    Param<uint32_t> pci_dev;
+    Param<uint32_t> pci_func;
+
+END_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
+
+BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev)
+
+    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
+    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
+    INIT_PARAM(engine, "DMA Engine"),
+    INIT_PARAM_DFLT(use_interface, "Use DMA Interface", true),
+    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
+    INIT_PARAM(mmu, "Memory Controller"),
+    INIT_PARAM(physmem, "Physical Memory"),
+    INIT_PARAM(addr, "Device Address"),
+    INIT_PARAM(mask, "Address Mask"),
+    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
+    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
+                    "00:99:00:00:00:01"),
+    INIT_PARAM(configspace, "PCI Configspace"),
+    INIT_PARAM(configdata, "PCI Config data"),
+    INIT_PARAM(tsunami, "Tsunami"),
+    INIT_PARAM(pci_bus, "PCI bus"),
+    INIT_PARAM(pci_dev, "PCI device number"),
+    INIT_PARAM(pci_func, "PCI function code")
+
+END_INIT_SIM_OBJECT_PARAMS(EtherDev)
+
+
+CREATE_SIM_OBJECT(EtherDev)
+{
+    int eaddr[6];
+    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
+           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
+
+    return new EtherDev(getInstanceName(), engine, use_interface,
+                        intr_ctrl, mmu, physmem, configspace, configdata,
+                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
+                        tx_delay, rx_delay, addr, mask);
+}
+
+REGISTER_SIM_OBJECT("EtherDev", EtherDev)
diff --git a/dev/ns_gige.hh b/dev/ns_gige.hh
new file mode 100644 (file)
index 0000000..eaece25
--- /dev/null
@@ -0,0 +1,403 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller
+ */
+
+#ifndef __NS_GIGE_HH__
+#define __NS_GIGE_HH__
+
+#include "dev/dma.hh"
+#include "dev/etherint.hh"
+#include "dev/etherpkt.hh"
+#include "sim/eventq.hh"
+#include "dev/ns_gige_reg.h"
+#include "base/statistics.hh"
+#include "dev/pcidev.hh"
+#include "dev/tsunami.hh"
+#include "dev/pciconfigall.hh"
+
+/** defined by the NS83820 data sheet */
+#define MAX_TX_FIFO_SIZE 8192
+#define MAX_RX_FIFO_SIZE 32768
+
+/** length of ethernet address in bytes */
+#define EADDR_LEN 6
+
+/** Transmit State Machine states */
+enum tx_state { txIdle, txDescRefr, txDescRead, txFifoBlock, txFragRead,
+               txDescWrite };
+
+/** Receive State Machine States */
+enum rx_state { rxIdle, rxDescRefr, rxDescRead, rxFifoBlock, rxFragWrite,
+                rxDescWrite, rxAdvance };
+
+/**
+ * Ethernet device registers
+ */
+struct dp_regs {
+    uint32_t   command;
+    uint32_t   config;
+    uint32_t   mear;
+    uint32_t   ptscr;
+    uint32_t    isr;
+    uint32_t    imr;
+    uint32_t    ier;
+    uint32_t    ihr;
+    uint32_t    txdp;
+    uint32_t    txdp_hi;
+    uint32_t    txcfg;
+    uint32_t    gpior;
+    uint32_t    rxdp;
+    uint32_t    rxdp_hi;
+    uint32_t    rxcfg;
+    uint32_t    pqcr;
+    uint32_t    wcsr;
+    uint32_t    pcr;
+    uint32_t    rfcr;
+    uint32_t    rfdr;
+    uint32_t    srr;
+    uint32_t    mibc;
+    uint32_t    vrcr;
+    uint32_t    vtcr;
+    uint32_t    vdr;
+    uint32_t    ccsr;
+    uint32_t    tbicr;
+    uint32_t    tbisr;
+    uint32_t    tanar;
+    uint32_t    tanlpar;
+    uint32_t    taner;
+    uint32_t    tesr;
+
+    /** for perfect match memory.  the linux driver doesn't use any other ROM */
+    uint8_t perfectMatch[EADDR_LEN];
+
+    virtual void serialize(std::ostream &os);
+    virtual void unserialize(Checkpoint *cp, const std::string &section);
+};
+
+/** an enum indicating direction, transmit or receive, used as a param for
+    some fns */
+enum dir_t { tx, rx };
+
+class DmaEngine;
+class IntrControl;
+class EtherDevInt;
+class PhysicalMemory;
+
+/**
+ * NS DP82830 Ethernet device model
+ */
+class EtherDev : public PciDev, public DmaHolder
+{
+  private:
+    /** pointer to the chipset */
+    Tsunami *tsunami;
+
+  protected:
+    Addr addr;
+    Addr mask;
+
+    /** device register file */
+    dp_regs regs;
+
+     /*** BASIC STRUCTURES FOR TX/RX ***/
+    /* Data FIFOs */
+    typedef std::deque<PacketPtr> pktbuf_t;
+    typedef pktbuf_t::iterator pktiter_t;
+    pktbuf_t txFifo;
+    pktbuf_t rxFifo;
+
+    /** for the tx side, to track addrs to write updated cmdsts to */
+    typedef std::deque<uint32_t> txdpbuf_t; /* ASSUME32 */
+    txdpbuf_t descAddrFifo;
+
+    /** various helper vars */
+    uint32_t txPacketLen;
+    uint8_t *txPacketBufPtr;
+    uint8_t *rxPacketBufPtr;
+    uint8_t *rxDescBufPtr;
+    uint32_t fragLen;
+    uint32_t rxCopied;
+
+    /** DescCaches */
+    ns_desc txDescCache;
+    ns_desc rxDescCache;
+
+    /* tx State Machine */
+    tx_state txState;
+    /** Current Transmit Descriptor Done */
+    bool CTDD;
+    uint32_t txFifoCnt; /* amt of data in the txDataFifo in bytes (logical) */
+    uint32_t txFifoAvail; /* current amt of free space in txDataFifo in byes */
+    bool txHalt;
+    bool txPacketFlag;  /* when set, indicates not working on a new packet */
+    Addr txFragPtr; /* ptr to the next byte in the current fragment */
+    uint32_t txDescCnt; /* count of bytes remaining in the current descriptor */
+
+    /** rx State Machine */
+    rx_state rxState;
+    bool CRDD; /* Current Receive Descriptor Done */
+    uint32_t rxPktBytes; /* num of bytes in the current packet being drained
+                            from rxDataFifo */
+    uint32_t rxFifoCnt; /* number of bytes in the rxFifo */
+    bool rxHalt;
+    bool rxPacketFlag;  /* when set, indicates not working on a new packet */
+    Addr rxFragPtr; /* ptr to the next byte in current fragment */
+    uint32_t rxDescCnt; /* count of bytes remaining in the current descriptor */
+
+    bool extstsEnable;
+    uint32_t maxTxBurst;
+    uint32_t maxRxBurst;
+
+    PhysicalMemory *physmem;
+
+  protected:
+    /**
+     * Receive dma for descriptors done callback
+     */
+    class RxDescDone : public DmaCallback
+    {
+      public:
+        EtherDev *ethernet;
+
+      public:
+        RxDescDone(EtherDev *e);
+        std::string name() const;
+        virtual void process();
+    };
+
+    /**
+     * Receive dma done callback
+     */
+    class RxDone : public DmaCallback
+    {
+      public:
+        EtherDev *ethernet;
+
+      public:
+        RxDone(EtherDev *e);
+        std::string name() const;
+        virtual void process();
+    };
+
+    /**
+     * Transmit dma for descriptors done callback
+     */
+    class TxDescDone : public DmaCallback
+    {
+      public:
+        EtherDev *ethernet;
+
+      public:
+        TxDescDone(EtherDev *e);
+        std::string name() const;
+        virtual void process();
+    };
+
+    /*
+     * Transmit dma done callback
+     */
+    class TxDone : public DmaCallback
+    {
+      public:
+        EtherDev *ethernet;
+        PacketPtr packet;
+
+      public:
+        TxDone(EtherDev *e);
+        std::string name() const;
+        virtual void process();
+    };
+
+    friend class TxDescDone;
+    friend class TxDone;
+    friend class RxDescDone;
+    friend class RxDone;
+
+    RxDescDone rxDescDoneCB;
+    RxDone rxDoneCB;
+    TxDescDone txDescDoneCB;
+    TxDone txDoneCB;
+
+    DmaEngine *dma;
+    DmaRequest readRequest;
+    DmaRequest writeRequest;
+    DmaRequest readDescRequest;
+    DmaRequest writeDescRequest;
+    PacketPtr rxPacket;
+    DmaPhys readPhys;
+    DmaPhys writePhys;
+    DmaPhys readDescPhys;
+    DmaPhys writeDescPhys;
+
+    EtherDevInt *interface;
+
+  protected:
+    IntrControl *intctrl;
+    Tick txDelay;
+    Tick rxDelay;
+
+    void txReset();
+    void rxReset();
+    void regsReset() {
+        memset(&regs, 0, sizeof(regs));
+        regs.mear = 0x12;
+        regs.isr = 0x00608000;
+        regs.txcfg = 0x120;
+        regs.rxcfg = 0x4;
+        regs.srr = 0x0103;
+        regs.mibc = 0x2;
+        regs.vdr = 0x81;
+        regs.tesr = 0xc000;
+    }
+
+    void txKick();
+    void rxKick();
+
+    /*
+     * Retransmit event
+     */
+    class TxEvent : public Event
+    {
+      protected:
+        EtherDev *dev;
+
+      public:
+        TxEvent(EtherDev *_dev)
+            : Event(&mainEventQueue), dev(_dev) {}
+        void process() { dev->transmit(); }
+        virtual const char *description() { return "retransmit"; }
+    };
+    friend class TxEvent;
+    TxEvent txEvent;
+    void transmit();
+
+
+    void txDescDone();
+    void rxDescDone();
+    void txDone(PacketPtr packet);
+    void rxDone();
+
+    void txDump() const;
+    void rxDump() const;
+
+    void devIntrPost(uint32_t interrupts);
+    void devIntrClear(uint32_t interrupts);
+    void devIntrChangeMask();
+
+    bool cpuPendingIntr;
+    void cpuIntrPost();
+    void cpuIntrClear();
+
+    bool rxFilterEnable;
+    bool rxFilter(PacketPtr packet);
+    bool acceptBroadcast;
+    bool acceptMulticast;
+    bool acceptUnicast;
+    bool acceptPerfect;
+    bool acceptArp;
+
+    bool udpChecksum(PacketPtr packet, bool gen);
+    bool tcpChecksum(PacketPtr packet, bool gen);
+    bool ipChecksum(PacketPtr packet, bool gen);
+    uint16_t checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len);
+
+  public:
+    EtherDev(const std::string &name, DmaEngine *de, bool use_interface,
+             IntrControl *i, MemoryController *mmu, PhysicalMemory *pmem,
+             PCIConfigAll *cf, PciConfigData *cd, Tsunami *t, uint32_t bus,
+             uint32_t dev, uint32_t func, bool rx_filter, const int eaddr[6],
+             Tick tx_delay, Tick rx_delay, Addr addr, Addr mask);
+    ~EtherDev();
+
+    virtual void WriteConfig(int offset, int size, uint32_t data);
+    virtual void ReadConfig(int offset, int size, uint8_t *data);
+
+
+
+    Fault read(MemReqPtr req, uint8_t *data);
+    Fault write(MemReqPtr req, const uint8_t *data);
+
+    bool cpuIntrPending() const;
+    void cpuIntrAck() { cpuIntrClear(); }
+
+    bool recvPacket(PacketPtr packet);
+    void transferDone();
+
+    void setInterface(EtherDevInt *i) { assert(!interface); interface = i; }
+
+    virtual void serialize(std::ostream &os);
+    virtual void unserialize(Checkpoint *cp, const std::string &section);
+
+    virtual DmaRequest *find_dmareq(uint32_t &id) {
+        if (id == 0)
+            return(&readRequest);
+        else if (id == 1)
+            return(&writeRequest);
+        else
+            return(NULL);
+    }
+
+  public:
+    void regStats();
+
+  private:
+    Statistics::Scalar<> txBytes;
+    Statistics::Scalar<> rxBytes;
+    Statistics::Scalar<> txPackets;
+    Statistics::Scalar<> rxPackets;
+    Statistics::Formula txBandwidth;
+    Statistics::Formula rxBandwidth;
+    Statistics::Formula txPacketRate;
+    Statistics::Formula rxPacketRate;
+
+    void readOneDesc(dir_t dir, uint32_t len = sizeof(ns_desc));
+    void readOneFrag();
+    void writeOneFrag();
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class EtherDevInt : public EtherInt
+{
+  private:
+    EtherDev *dev;
+
+  public:
+    EtherDevInt(const std::string &name, EtherDev *d)
+        : EtherInt(name), dev(d) { dev->setInterface(this); }
+
+    virtual bool recvPacket(PacketPtr &pkt) { return dev->recvPacket(pkt); }
+    virtual void sendDone() { dev->transferDone(); }
+};
+
+#endif // __NS_GIGE_HH__
diff --git a/dev/ns_gige_reg.h b/dev/ns_gige_reg.h
new file mode 100644 (file)
index 0000000..5b0f961
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2003 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Portions of code taken from: */
+
+/* ns83820.c by Benjamin LaHaise with contributions.
+ *
+ * Questions/comments/discussion to linux-ns83820@kvack.org.
+ *
+ * $Revision: 1.34.2.23 $
+ *
+ * Copyright 2001 Benjamin LaHaise.
+ * Copyright 2001, 2002 Red Hat.
+ *
+ * Mmmm, chocolate vanilla mocha...
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+
+
+
+/* @file
+ * Ethernet device register definitions for the National
+ * Semiconductor DP83820 Ethernet controller
+ */
+
+#ifndef _NS_GIGE_H
+#define _NS_GIGE_H_
+
+/*
+ * Configuration Register Map
+ */
+#define NS_ID                   0x00    /* identification register */
+#define NS_CS                   0x04    /* command and status register */
+#define NS_RID                  0x08    /* revision ID register */
+#define NS_LAT                 0x0C    /* latency timer register */
+#define NS_IOA                 0x10    /* IO base address register */
+#define NS_MA                  0x14    /* memory address register */
+#define NS_MA1                 0x18    /* memory address high dword register */
+#define NS_SID                 0x2C    /* subsystem identification register */
+#define NS_ROM                 0x30    /* boot ROM configuration register */
+#define NS_CAPPTR              0x34    /* number of tx descriptors */
+#define NS_INT                 0x3C    /* interrupt select register */
+#define NS_PMCAP               0x40    /* power mgmt capabilities register */
+#define NS_PMCS                0x44    /* power mgmt control and status
+                                           register */
+/* Operational Register Map */
+#define CR             0x00
+#define CFG            0x04
+#define MEAR           0x08
+#define PTSCR          0x0c
+#define        ISR             0x10
+#define        IMR             0x14
+#define        IER             0x18
+#define        IHR             0x1c
+#define TXDP           0x20
+#define TXDP_HI                0x24
+#define TXCFG          0x28
+#define GPIOR          0x2c
+#define RXDP           0x30
+#define RXDP_HI                0x34
+#define RXCFG          0x38
+#define PQCR           0x3c
+#define WCSR           0x40
+#define PCR            0x44
+#define RFCR           0x48
+#define RFDR           0x4c
+#define BRAR            0x50
+#define BRDR            0x54
+#define SRR            0x58
+#define MIBC            0x5c
+#define VRCR           0xbc
+#define VTCR           0xc0
+#define VDR            0xc4
+#define CCSR           0xcc
+#define TBICR          0xe0
+#define TBISR          0xe4
+#define TANAR          0xe8
+#define TANLPAR                0xec
+#define TANER          0xf0
+#define TESR           0xf4
+#define LAST            0xf4
+#define RESERVED        0xfc
+
+/* chip command register */
+#define CR_TXE         0x00000001
+#define CR_TXD         0x00000002
+#define CR_RXE         0x00000004
+#define CR_RXD         0x00000008
+#define CR_TXR         0x00000010
+#define CR_RXR         0x00000020
+#define CR_SWI         0x00000080
+#define CR_RST         0x00000100
+
+/* configuration register */
+#define CFG_LNKSTS     0x80000000
+#define CFG_SPDSTS     0x60000000
+#define CFG_SPDSTS1    0x40000000
+#define CFG_SPDSTS0    0x20000000
+#define CFG_DUPSTS     0x10000000
+#define CFG_TBI_EN     0x01000000
+#define CFG_RESERVED    0x0e000000
+#define CFG_MODE_1000  0x00400000
+#define CFG_AUTO_1000  0x00200000
+#define CFG_PINT_CTL   0x001c0000
+#define CFG_PINT_DUPSTS        0x00100000
+#define CFG_PINT_LNKSTS        0x00080000
+#define CFG_PINT_SPDSTS        0x00040000
+#define CFG_TMRTEST    0x00020000
+#define CFG_MRM_DIS    0x00010000
+#define CFG_MWI_DIS    0x00008000
+#define CFG_T64ADDR    0x00004000
+#define CFG_PCI64_DET  0x00002000
+#define CFG_DATA64_EN  0x00001000
+#define CFG_M64ADDR    0x00000800
+#define CFG_PHY_RST    0x00000400
+#define CFG_PHY_DIS    0x00000200
+#define CFG_EXTSTS_EN  0x00000100
+#define CFG_REQALG     0x00000080
+#define CFG_SB         0x00000040
+#define CFG_POW                0x00000020
+#define CFG_EXD                0x00000010
+#define CFG_PESEL      0x00000008
+#define CFG_BROM_DIS   0x00000004
+#define CFG_EXT_125    0x00000002
+#define CFG_BEM                0x00000001
+
+/* EEPROM access register */
+#define MEAR_EEDI              0x00000001
+#define MEAR_EEDO              0x00000002
+#define MEAR_EECLK             0x00000004
+#define MEAR_EESEL             0x00000008
+#define MEAR_MDIO              0x00000010
+#define MEAR_MDDIR             0x00000020
+#define MEAR_MDC               0x00000040
+
+/* PCI test control register */
+#define PTSCR_EEBIST_FAIL       0x00000001
+#define PTSCR_EEBIST_EN         0x00000002
+#define PTSCR_EELOAD_EN         0x00000004
+#define PTSCR_RBIST_FAIL        0x000001b8
+#define PTSCR_RBIST_DONE        0x00000200
+#define PTSCR_RBIST_EN          0x00000400
+#define PTSCR_RBIST_RST         0x00002000
+
+/* interrupt status register */
+#define ISR_RESERVE     0x80000000
+#define ISR_TXDESC3    0x40000000
+#define ISR_TXDESC2    0x20000000
+#define ISR_TXDESC1    0x10000000
+#define ISR_TXDESC0    0x08000000
+#define ISR_RXDESC3    0x04000000
+#define ISR_RXDESC2    0x02000000
+#define ISR_RXDESC1    0x01000000
+#define ISR_RXDESC0    0x00800000
+#define ISR_TXRCMP     0x00400000
+#define ISR_RXRCMP     0x00200000
+#define ISR_DPERR      0x00100000
+#define ISR_SSERR      0x00080000
+#define ISR_RMABT      0x00040000
+#define ISR_RTABT      0x00020000
+#define ISR_RXSOVR     0x00010000
+#define ISR_HIBINT     0x00008000
+#define ISR_PHY                0x00004000
+#define ISR_PME                0x00002000
+#define ISR_SWI                0x00001000
+#define ISR_MIB                0x00000800
+#define ISR_TXURN      0x00000400
+#define ISR_TXIDLE     0x00000200
+#define ISR_TXERR      0x00000100
+#define ISR_TXDESC     0x00000080
+#define ISR_TXOK       0x00000040
+#define ISR_RXORN      0x00000020
+#define ISR_RXIDLE     0x00000010
+#define ISR_RXEARLY    0x00000008
+#define ISR_RXERR      0x00000004
+#define ISR_RXDESC     0x00000002
+#define ISR_RXOK       0x00000001
+
+/* transmit configuration register */
+#define TXCFG_CSI      0x80000000
+#define TXCFG_HBI      0x40000000
+#define TXCFG_MLB      0x20000000
+#define TXCFG_ATP      0x10000000
+#define TXCFG_ECRETRY  0x00800000
+#define TXCFG_BRST_DIS 0x00080000
+#define TXCFG_MXDMA1024        0x00000000
+#define TXCFG_MXDMA512 0x00700000
+#define TXCFG_MXDMA256 0x00600000
+#define TXCFG_MXDMA128 0x00500000
+#define TXCFG_MXDMA64  0x00400000
+#define TXCFG_MXDMA32  0x00300000
+#define TXCFG_MXDMA16  0x00200000
+#define TXCFG_MXDMA8   0x00100000
+
+#define TXCFG_FLTH_MASK 0x0000ff00
+#define TXCFG_DRTH_MASK 0x000000ff
+
+/*general purpose I/O control register */
+#define GPIOR_GP5_OE           0x00000200
+#define GPIOR_GP4_OE           0x00000100
+#define GPIOR_GP3_OE           0x00000080
+#define GPIOR_GP2_OE           0x00000040
+#define GPIOR_GP1_OE           0x00000020
+#define GPIOR_GP3_OUT          0x00000004
+#define GPIOR_GP1_OUT          0x00000001
+
+/* receive configuration register */
+#define RXCFG_AEP      0x80000000
+#define RXCFG_ARP      0x40000000
+#define RXCFG_STRIPCRC 0x20000000
+#define RXCFG_RX_FD    0x10000000
+#define RXCFG_ALP      0x08000000
+#define RXCFG_AIRL     0x04000000
+#define RXCFG_MXDMA512 0x00700000
+#define RXCFG_DRTH     0x0000003e
+#define RXCFG_DRTH0    0x00000002
+
+/* pause control status register */
+#define PCR_PSEN       (1 << 31)
+#define PCR_PS_MCAST   (1 << 30)
+#define PCR_PS_DA      (1 << 29)
+#define PCR_STHI_8     (3 << 23)
+#define PCR_STLO_4     (1 << 23)
+#define PCR_FFHI_8K    (3 << 21)
+#define PCR_FFLO_4K    (1 << 21)
+#define PCR_PAUSE_CNT  0xFFFE
+
+/*receive filter/match control register */
+#define RFCR_RFEN      0x80000000
+#define RFCR_AAB       0x40000000
+#define RFCR_AAM       0x20000000
+#define RFCR_AAU       0x10000000
+#define RFCR_APM       0x08000000
+#define RFCR_APAT      0x07800000
+#define RFCR_APAT3     0x04000000
+#define RFCR_APAT2     0x02000000
+#define RFCR_APAT1     0x01000000
+#define RFCR_APAT0     0x00800000
+#define RFCR_AARP      0x00400000
+#define RFCR_MHEN      0x00200000
+#define RFCR_UHEN      0x00100000
+#define RFCR_ULM       0x00080000
+#define RFCR_RFADDR     0x000003ff
+
+/* receive filter/match data register */
+#define RFDR_BMASK      0x00030000
+#define RFDR_RFDATA0    0x000000ff
+#define RFDR_RFDATA1    0x0000ff00
+
+/* management information base control register */
+#define MIBC_MIBS      0x00000008
+#define MIBC_ACLR      0x00000004
+#define MIBC_FRZ       0x00000002
+#define MIBC_WRN       0x00000001
+
+/* VLAN/IP receive control register */
+#define VRCR_RUDPE     0x00000080
+#define VRCR_RTCPE     0x00000040
+#define VRCR_RIPE      0x00000020
+#define VRCR_IPEN      0x00000010
+#define VRCR_DUTF      0x00000008
+#define VRCR_DVTF      0x00000004
+#define VRCR_VTREN     0x00000002
+#define VRCR_VTDEN     0x00000001
+
+/* VLAN/IP transmit control register */
+#define VTCR_PPCHK     0x00000008
+#define VTCR_GCHK      0x00000004
+#define VTCR_VPPTI     0x00000002
+#define VTCR_VGTI      0x00000001
+
+/* Clockrun Control/Status Register */
+#define CCSR_CLKRUN_EN  0x00000001
+
+/* TBI control register */
+#define TBICR_MR_LOOPBACK       0x00004000
+#define TBICR_MR_AN_ENABLE     0x00001000
+#define TBICR_MR_RESTART_AN    0x00000200
+
+/* TBI status register */
+#define TBISR_MR_LINK_STATUS   0x00000020
+#define TBISR_MR_AN_COMPLETE   0x00000004
+
+/* TBI auto-negotiation advertisement register */
+#define TANAR_PS2              0x00000100
+#define TANAR_PS1              0x00000080
+#define TANAR_HALF_DUP                 0x00000040
+#define TANAR_FULL_DUP                 0x00000020
+
+/*
+ * descriptor format currently assuming link and bufptr
+ * are set for 32 bits,( may be wrong ) ASSUME32
+ */
+struct ns_desc {
+  uint32_t link;    /* link field to next descriptor in linked list */
+  uint32_t bufptr;  /* pointer to the first fragment or buffer */
+  uint32_t cmdsts;  /* command/status field */
+  uint32_t extsts;  /* extended status field for VLAN and IP info */
+};
+
+/* ASSUME32 in bytes, how big the desc fields are */
+#define LINK_LEN 4
+#define BUFPTR_LEN 4
+#define CMDSTS_LEN 4
+#define EXTSTS_LEN 4
+
+/* cmdsts flags for descriptors */
+#define CMDSTS_OWN     0x80000000
+#define CMDSTS_MORE    0x40000000
+#define CMDSTS_INTR    0x20000000
+#define CMDSTS_ERR     0x10000000
+#define CMDSTS_OK      0x08000000
+#define CMDSTS_LEN_MASK        0x0000ffff
+
+#define CMDSTS_DEST_MASK       0x01800000
+#define CMDSTS_DEST_SELF       0x00800000
+#define CMDSTS_DEST_MULTI      0x01000000
+
+/* extended flags for descriptors */
+#define EXTSTS_UDPERR   0x00400000
+#define EXTSTS_UDPPKT  0x00200000
+#define EXTSTS_TCPERR   0x00100000
+#define EXTSTS_TCPPKT  0x00080000
+#define EXTSTS_IPERR    0x00040000
+#define EXTSTS_IPPKT   0x00020000
+
+
+/* speed status */
+#define SPDSTS_POLARITY        (CFG_SPDSTS1 | CFG_SPDSTS0 | CFG_DUPSTS | (lnksts ? CFG_LNKSTS : 0))
+
+#endif /* _NS_GIGE_H_ */