Get rid of the xc from the alphaAccess/alphaConsole backdoor device.
[gem5.git] / dev / ns_gige.cc
index 7260ecde49698ba32c2f0feb14987034ffc04bcf..9010850ab8a67cc1e09c497d768cbf1540cc0022 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004 The Regents of The University of Michigan
+ * Copyright (c) 2004-2005 The Regents of The University of Michigan
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -26,7 +26,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-/* @file
+/** @file
  * Device module for modelling the National Semiconductor
  * DP83820 ethernet controller.  Does not support priority queueing
  */
 
 #include "base/inet.hh"
 #include "cpu/exec_context.hh"
-#include "cpu/intr_control.hh"
-#include "dev/dma.hh"
 #include "dev/etherlink.hh"
 #include "dev/ns_gige.hh"
 #include "dev/pciconfigall.hh"
-#include "dev/tsunami_cchip.hh"
 #include "mem/bus/bus.hh"
 #include "mem/bus/dma_interface.hh"
 #include "mem/bus/pio_interface.hh"
 #include "mem/bus/pio_interface_impl.hh"
-#include "mem/functional_mem/memory_control.hh"
-#include "mem/functional_mem/physical_memory.hh"
+#include "mem/functional/memory_control.hh"
+#include "mem/functional/physical.hh"
 #include "sim/builder.hh"
 #include "sim/debug.hh"
 #include "sim/host.hh"
-#include "sim/sim_stats.hh"
+#include "sim/stats.hh"
 #include "targetarch/vtophys.hh"
 
 const char *NsRxStateStrings[] =
@@ -86,77 +83,68 @@ const char *NsDmaState[] =
 };
 
 using namespace std;
-
+using namespace Net;
 
 ///////////////////////////////////////////////////////////////////////
 //
 // NSGigE PCI Device
 //
-NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
-               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
-               MemoryController *mmu, HierParams *hier, Bus *header_bus,
-               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
-               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
-               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
-               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
-               uint32_t func, bool rx_filter, const int eaddr[6],
-               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
-    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
-      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
+NSGigE::NSGigE(Params *p)
+    : PciDev(p), ioEnable(false),
+      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
       txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
-      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
-      CTDD(false), txFifoAvail(tx_fifo_size),
+      txXferLen(0), rxXferLen(0), clock(p->clock),
+      txState(txIdle), txEnable(false), CTDD(false),
       txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
-      rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0),
+      rxEnable(false), CRDD(false), rxPktBytes(0),
       rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
-      rxDmaReadEvent(this), rxDmaWriteEvent(this),
+      eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
       txDmaReadEvent(this), txDmaWriteEvent(this),
-      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
-      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
-      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
+      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
+      txDelay(p->tx_delay), rxDelay(p->rx_delay),
+      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
+      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
       acceptMulticast(false), acceptUnicast(false),
-      acceptPerfect(false), acceptArp(false),
-      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
+      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
+      physmem(p->pmem), intrTick(0), cpuPendingIntr(false),
       intrEvent(0), interface(0)
 {
-    tsunami->ethernet = this;
-
-    if (header_bus) {
-        pioInterface = newPioInterface(name, hier, header_bus, this,
+    if (p->pio_bus) {
+        pioInterface = newPioInterface(name() + ".pio", p->hier,
+                                       p->pio_bus, this,
                                        &NSGigE::cacheAccess);
+        pioLatency = p->pio_latency * p->pio_bus->clockRate;
+    }
 
-        pioLatency = pio_latency * header_bus->clockRatio;
-
-        if (payload_bus)
-            dmaInterface = new DMAInterface<Bus>(name + ".dma",
-                                                 header_bus, payload_bus, 1);
+    if (p->header_bus) {
+        if (p->payload_bus)
+            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
+                                                 p->header_bus,
+                                                 p->payload_bus, 1,
+                                                 p->dma_no_allocate);
         else
-            dmaInterface = new DMAInterface<Bus>(name + ".dma",
-                                                 header_bus, header_bus, 1);
-    } else if (payload_bus) {
-        pioInterface = newPioInterface(name, hier, payload_bus, this,
-                                       &NSGigE::cacheAccess);
+            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
+                                                 p->header_bus,
+                                                 p->header_bus, 1,
+                                                 p->dma_no_allocate);
+    } else if (p->payload_bus)
+        panic("Must define a header bus if defining a payload bus");
 
-        pioLatency = pio_latency * payload_bus->clockRatio;
+    pioDelayWrite = p->pio_delay_write && pioInterface;
 
-        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
-                                         payload_bus, 1);
-    }
-
-
-    intrDelay = US2Ticks(intr_delay);
-    dmaReadDelay = dma_read_delay;
-    dmaWriteDelay = dma_write_delay;
-    dmaReadFactor = dma_read_factor;
-    dmaWriteFactor = dma_write_factor;
+    intrDelay = p->intr_delay;
+    dmaReadDelay = p->dma_read_delay;
+    dmaWriteDelay = p->dma_write_delay;
+    dmaReadFactor = p->dma_read_factor;
+    dmaWriteFactor = p->dma_write_factor;
 
     regsReset();
-    rom.perfectMatch[0] = eaddr[0];
-    rom.perfectMatch[1] = eaddr[1];
-    rom.perfectMatch[2] = eaddr[2];
-    rom.perfectMatch[3] = eaddr[3];
-    rom.perfectMatch[4] = eaddr[4];
-    rom.perfectMatch[5] = eaddr[5];
+    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
+
+    memset(&rxDesc32, 0, sizeof(rxDesc32));
+    memset(&txDesc32, 0, sizeof(txDesc32));
+    memset(&rxDesc64, 0, sizeof(rxDesc64));
+    memset(&txDesc64, 0, sizeof(txDesc64));
 }
 
 NSGigE::~NSGigE()
@@ -255,7 +243,6 @@ NSGigE::regStats()
         .precision(0)
         ;
 
-
     txBandwidth
         .name(name() + ".txBandwidth")
         .desc("Transmit Bandwidth (bits/s)")
@@ -270,6 +257,34 @@ NSGigE::regStats()
         .prereq(rxBytes)
         ;
 
+    totBandwidth
+        .name(name() + ".totBandwidth")
+        .desc("Total Bandwidth (bits/s)")
+        .precision(0)
+        .prereq(totBytes)
+        ;
+
+    totPackets
+        .name(name() + ".totPackets")
+        .desc("Total Packets")
+        .precision(0)
+        .prereq(totBytes)
+        ;
+
+    totBytes
+        .name(name() + ".totBytes")
+        .desc("Total Bytes")
+        .precision(0)
+        .prereq(totBytes)
+        ;
+
+    totPacketRate
+        .name(name() + ".totPPS")
+        .desc("Total Tranmission Rate (packets/s)")
+        .precision(0)
+        .prereq(totBytes)
+        ;
+
     txPacketRate
         .name(name() + ".txPPS")
         .desc("Packet Tranmission Rate (packets/s)")
@@ -284,8 +299,187 @@ NSGigE::regStats()
         .prereq(rxBytes)
         ;
 
+    postedSwi
+        .name(name() + ".postedSwi")
+        .desc("number of software interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalSwi
+        .name(name() + ".totalSwi")
+        .desc("total number of Swi written to ISR")
+        .precision(0)
+        ;
+
+    coalescedSwi
+        .name(name() + ".coalescedSwi")
+        .desc("average number of Swi's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedRxIdle
+        .name(name() + ".postedRxIdle")
+        .desc("number of rxIdle interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalRxIdle
+        .name(name() + ".totalRxIdle")
+        .desc("total number of RxIdle written to ISR")
+        .precision(0)
+        ;
+
+    coalescedRxIdle
+        .name(name() + ".coalescedRxIdle")
+        .desc("average number of RxIdle's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedRxOk
+        .name(name() + ".postedRxOk")
+        .desc("number of RxOk interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalRxOk
+        .name(name() + ".totalRxOk")
+        .desc("total number of RxOk written to ISR")
+        .precision(0)
+        ;
+
+    coalescedRxOk
+        .name(name() + ".coalescedRxOk")
+        .desc("average number of RxOk's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedRxDesc
+        .name(name() + ".postedRxDesc")
+        .desc("number of RxDesc interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalRxDesc
+        .name(name() + ".totalRxDesc")
+        .desc("total number of RxDesc written to ISR")
+        .precision(0)
+        ;
+
+    coalescedRxDesc
+        .name(name() + ".coalescedRxDesc")
+        .desc("average number of RxDesc's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedTxOk
+        .name(name() + ".postedTxOk")
+        .desc("number of TxOk interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalTxOk
+        .name(name() + ".totalTxOk")
+        .desc("total number of TxOk written to ISR")
+        .precision(0)
+        ;
+
+    coalescedTxOk
+        .name(name() + ".coalescedTxOk")
+        .desc("average number of TxOk's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedTxIdle
+        .name(name() + ".postedTxIdle")
+        .desc("number of TxIdle interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalTxIdle
+        .name(name() + ".totalTxIdle")
+        .desc("total number of TxIdle written to ISR")
+        .precision(0)
+        ;
+
+    coalescedTxIdle
+        .name(name() + ".coalescedTxIdle")
+        .desc("average number of TxIdle's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedTxDesc
+        .name(name() + ".postedTxDesc")
+        .desc("number of TxDesc interrupts posted to CPU")
+        .precision(0)
+        ;
+
+    totalTxDesc
+        .name(name() + ".totalTxDesc")
+        .desc("total number of TxDesc written to ISR")
+        .precision(0)
+        ;
+
+    coalescedTxDesc
+        .name(name() + ".coalescedTxDesc")
+        .desc("average number of TxDesc's coalesced into each post")
+        .precision(0)
+        ;
+
+    postedRxOrn
+        .name(name() + ".postedRxOrn")
+        .desc("number of RxOrn posted to CPU")
+        .precision(0)
+        ;
+
+    totalRxOrn
+        .name(name() + ".totalRxOrn")
+        .desc("total number of RxOrn written to ISR")
+        .precision(0)
+        ;
+
+    coalescedRxOrn
+        .name(name() + ".coalescedRxOrn")
+        .desc("average number of RxOrn's coalesced into each post")
+        .precision(0)
+        ;
+
+    coalescedTotal
+        .name(name() + ".coalescedTotal")
+        .desc("average number of interrupts coalesced into each post")
+        .precision(0)
+        ;
+
+    postedInterrupts
+        .name(name() + ".postedInterrupts")
+        .desc("number of posts to CPU")
+        .precision(0)
+        ;
+
+    droppedPackets
+        .name(name() + ".droppedPackets")
+        .desc("number of packets dropped")
+        .precision(0)
+        ;
+
+    coalescedSwi = totalSwi / postedInterrupts;
+    coalescedRxIdle = totalRxIdle / postedInterrupts;
+    coalescedRxOk = totalRxOk / postedInterrupts;
+    coalescedRxDesc = totalRxDesc / postedInterrupts;
+    coalescedTxOk = totalTxOk / postedInterrupts;
+    coalescedTxIdle = totalTxIdle / postedInterrupts;
+    coalescedTxDesc = totalTxDesc / postedInterrupts;
+    coalescedRxOrn = totalRxOrn / postedInterrupts;
+
+    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
+                      totalTxOk + totalTxIdle + totalTxDesc +
+                      totalRxOrn) / postedInterrupts;
+
     txBandwidth = txBytes * Stats::constant(8) / simSeconds;
     rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
+    totBandwidth = txBandwidth + rxBandwidth;
+    totBytes = txBytes + rxBytes;
+    totPackets = txPackets + rxPackets;
+
     txPacketRate = txPackets / simSeconds;
     rxPacketRate = rxPackets / simSeconds;
 }
@@ -294,10 +488,10 @@ NSGigE::regStats()
  * This is to read the PCI general configuration registers
  */
 void
-NSGigE::ReadConfig(int offset, int size, uint8_t *data)
+NSGigE::readConfig(int offset, int size, uint8_t *data)
 {
     if (offset < PCI_DEVICE_SPECIFIC)
-        PciDev::ReadConfig(offset, size, data);
+        PciDev::readConfig(offset, size, data);
     else
         panic("Device specific PCI config space not implemented!\n");
 }
@@ -306,10 +500,10 @@ NSGigE::ReadConfig(int offset, int size, uint8_t *data)
  * This is to write to the PCI general configuration registers
  */
 void
-NSGigE::WriteConfig(int offset, int size, uint32_t data)
+NSGigE::writeConfig(int offset, int size, const uint8_t* data)
 {
     if (offset < PCI_DEVICE_SPECIFIC)
-        PciDev::WriteConfig(offset, size, data);
+        PciDev::writeConfig(offset, size, data);
     else
         panic("Device specific PCI config space not implemented!\n");
 
@@ -344,19 +538,17 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data)
       case PCI0_BASE_ADDR0:
         if (BARAddrs[0] != 0) {
             if (pioInterface)
-                pioInterface->addAddrRange(BARAddrs[0],
-                                           BARAddrs[0] + BARSize[0] - 1);
+                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
 
-            BARAddrs[0] &= PA_UNCACHED_MASK;
+            BARAddrs[0] &= EV5::PAddrUncachedMask;
         }
         break;
       case PCI0_BASE_ADDR1:
         if (BARAddrs[1] != 0) {
             if (pioInterface)
-                pioInterface->addAddrRange(BARAddrs[1],
-                                           BARAddrs[1] + BARSize[1] - 1);
+                pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
 
-            BARAddrs[1] &= PA_UNCACHED_MASK;
+            BARAddrs[1] &= EV5::PAddrUncachedMask;
         }
         break;
     }
@@ -382,7 +574,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
     if (daddr > LAST && daddr <=  RESERVED) {
         panic("Accessing reserved register");
     } else if (daddr > RESERVED && daddr <= 0x3FC) {
-        ReadConfig(daddr & 0xff, req->size, data);
+        readConfig(daddr & 0xff, req->size, data);
         return No_Fault;
     } else if (daddr >= MIB_START && daddr <= MIB_END) {
         // don't implement all the MIB's.  hopefully the kernel
@@ -398,6 +590,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
       case sizeof(uint32_t):
         {
             uint32_t &reg = *(uint32_t *)data;
+            uint16_t rfaddr;
 
             switch (daddr) {
               case CR:
@@ -406,7 +599,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                 reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
                 break;
 
-              case CFG:
+              case CFGR:
                 reg = regs.config;
                 break;
 
@@ -443,7 +636,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                 reg = regs.txdp_hi;
                 break;
 
-              case TXCFG:
+              case TX_CFG:
                 reg = regs.txcfg;
                 break;
 
@@ -459,7 +652,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                 reg = regs.rxdp_hi;
                 break;
 
-              case RXCFG:
+              case RX_CFG:
                 reg = regs.rxcfg;
                 break;
 
@@ -485,7 +678,9 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                 break;
 
               case RFDR:
-                switch (regs.rfcr & RFCR_RFADDR) {
+                rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+                switch (rfaddr) {
+                  // Read from perfect match ROM octets
                   case 0x000:
                     reg = rom.perfectMatch[1];
                     reg = reg << 8;
@@ -500,9 +695,21 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                     reg += rom.perfectMatch[4];
                     break;
                   default:
-                    panic("reading RFDR for something other than PMATCH!\n");
-                    // didn't implement other RFDR functionality b/c
-                    // driver didn't use it
+                    // Read filter hash table
+                    if (rfaddr >= FHASH_ADDR &&
+                        rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+                        // Only word-aligned reads supported
+                        if (rfaddr % 2)
+                            panic("unaligned read from filter hash table!");
+
+                        reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
+                        reg += rom.filterHash[rfaddr - FHASH_ADDR];
+                        break;
+                    }
+
+                    panic("reading RFDR for something other than pattern"
+                          " matching or hashing! %#x\n", rfaddr);
                 }
                 break;
 
@@ -555,6 +762,14 @@ NSGigE::read(MemReqPtr &req, uint8_t *data)
                 reg = regs.tesr;
                 break;
 
+              case M5REG:
+                reg = 0;
+                if (params()->rx_thread)
+                    reg |= M5REG_RX_THREAD;
+                if (params()->tx_thread)
+                    reg |= M5REG_TX_THREAD;
+                break;
+
               default:
                 panic("reading unimplemented register: addr=%#x", daddr);
             }
@@ -584,13 +799,22 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
     if (daddr > LAST && daddr <=  RESERVED) {
         panic("Accessing reserved register");
     } else if (daddr > RESERVED && daddr <= 0x3FC) {
-        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
+        writeConfig(daddr & 0xff, req->size, data);
         return No_Fault;
     } else if (daddr > 0x3FC)
         panic("Something is messed up!\n");
 
+    if (pioDelayWrite) {
+        int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
+        if (cpu >= writeQueue.size())
+            writeQueue.resize(cpu + 1);
+        writeQueue[cpu].push_back(RegWriteData(daddr, *(uint32_t *)data));
+    }
+
     if (req->size == sizeof(uint32_t)) {
         uint32_t reg = *(uint32_t *)data;
+        uint16_t rfaddr;
+
         DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
 
         switch (daddr) {
@@ -599,20 +823,24 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             if (reg & CR_TXD) {
                 txEnable = false;
             } else if (reg & CR_TXE) {
-                txEnable = true;
+                if (!pioDelayWrite) {
+                    txEnable = true;
 
-                // the kernel is enabling the transmit machine
-                if (txState == txIdle)
-                    txKick();
+                    // the kernel is enabling the transmit machine
+                    if (txState == txIdle)
+                        txKick();
+                }
             }
 
             if (reg & CR_RXD) {
                 rxEnable = false;
             } else if (reg & CR_RXE) {
-                rxEnable = true;
+                if (!pioDelayWrite) {
+                    rxEnable = true;
 
-                if (rxState == rxIdle)
-                    rxKick();
+                    if (rxState == rxIdle)
+                        rxKick();
+                }
             }
 
             if (reg & CR_TXR)
@@ -632,82 +860,91 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             }
             break;
 
-          case CFG:
-            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");
-
-            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
-                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
+          case CFGR:
+            if (reg & CFGR_LNKSTS ||
+                reg & CFGR_SPDSTS ||
+                reg & CFGR_DUPSTS ||
+                reg & CFGR_RESERVED ||
+                reg & CFGR_T64ADDR ||
+                reg & CFGR_PCI64_DET)
+
+            // First clear all writable bits
+            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+                                   CFGR_RESERVED | CFGR_T64ADDR |
+                                   CFGR_PCI64_DET;
+            // Now set the appropriate writable bits
+            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
+                                   CFGR_RESERVED | CFGR_T64ADDR |
+                                   CFGR_PCI64_DET);
 
 // all these #if 0's are because i don't THINK the kernel needs to
 // have these implemented. if there is a problem relating to one of
 // these, you may need to add functionality in.
-#if 0
-            if (reg & CFG_TBI_EN) ;
-            if (reg & CFG_MODE_1000) ;
-#endif
+            if (reg & CFGR_TBI_EN) ;
+            if (reg & CFGR_MODE_1000) ;
 
-            if (reg & CFG_AUTO_1000)
-                panic("CFG_AUTO_1000 not implemented!\n");
+            if (reg & CFGR_AUTO_1000)
+                panic("CFGR_AUTO_1000 not implemented!\n");
 
-#if 0
-            if (reg & CFG_PINT_DUPSTS ||
-                reg & CFG_PINT_LNKSTS ||
-                reg & CFG_PINT_SPDSTS)
+            if (reg & CFGR_PINT_DUPSTS ||
+                reg & CFGR_PINT_LNKSTS ||
+                reg & CFGR_PINT_SPDSTS)
                 ;
 
-            if (reg & CFG_TMRTEST) ;
-            if (reg & CFG_MRM_DIS) ;
-            if (reg & CFG_MWI_DIS) ;
+            if (reg & CFGR_TMRTEST) ;
+            if (reg & CFGR_MRM_DIS) ;
+            if (reg & CFGR_MWI_DIS) ;
 
-            if (reg & CFG_T64ADDR)
-                panic("CFG_T64ADDR is read only register!\n");
+            if (reg & CFGR_T64ADDR) ;
+            // panic("CFGR_T64ADDR is read only register!\n");
 
-            if (reg & CFG_PCI64_DET)
-                panic("CFG_PCI64_DET is read only register!\n");
+            if (reg & CFGR_PCI64_DET)
+                panic("CFGR_PCI64_DET is read only register!\n");
 
-            if (reg & CFG_DATA64_EN) ;
-            if (reg & CFG_M64ADDR) ;
-            if (reg & CFG_PHY_RST) ;
-            if (reg & CFG_PHY_DIS) ;
-#endif
+            if (reg & CFGR_DATA64_EN) ;
+            if (reg & CFGR_M64ADDR) ;
+            if (reg & CFGR_PHY_RST) ;
+            if (reg & CFGR_PHY_DIS) ;
 
-            if (reg & CFG_EXTSTS_EN)
+            if (reg & CFGR_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
+            if (reg & CFGR_REQALG) ;
+            if (reg & CFGR_SB) ;
+            if (reg & CFGR_POW) ;
+            if (reg & CFGR_EXD) ;
+            if (reg & CFGR_PESEL) ;
+            if (reg & CFGR_BROM_DIS) ;
+            if (reg & CFGR_EXT_125) ;
+            if (reg & CFGR_BEM) ;
             break;
 
           case MEAR:
-            regs.mear = reg;
+            // Clear writable bits
+            regs.mear &= MEAR_EEDO;
+            // Set appropriate writable bits
+            regs.mear |= reg & ~MEAR_EEDO;
+
+            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
+            // even though it could get it through RFDR
+            if (reg & MEAR_EESEL) {
+                // Rising edge of clock
+                if (reg & MEAR_EECLK && !eepromClk)
+                    eepromKick();
+            }
+            else {
+                eepromState = eepromStart;
+                regs.mear &= ~MEAR_EEDI;
+            }
+
+            eepromClk = reg & MEAR_EECLK;
+
             // 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:
@@ -749,14 +986,14 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             regs.txdp_hi = reg;
             break;
 
-          case TXCFG:
+          case TX_CFG:
             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) {
+            if (reg & TX_CFG_CSI) ;
+            if (reg & TX_CFG_HBI) ;
+            if (reg & TX_CFG_MLB) ;
+            if (reg & TX_CFG_ATP) ;
+            if (reg & TX_CFG_ECRETRY) {
                 /*
                  * this could easily be implemented, but considering
                  * the network is just a fake pipe, wouldn't make
@@ -764,12 +1001,12 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
                  */
             }
 
-            if (reg & TXCFG_BRST_DIS) ;
+            if (reg & TX_CFG_BRST_DIS) ;
 #endif
 
 #if 0
             /* we handle our own DMA, ignore the kernel's exhortations */
-            if (reg & TXCFG_MXDMA) ;
+            if (reg & TX_CFG_MXDMA) ;
 #endif
 
             // also, we currently don't care about fill/drain
@@ -780,7 +1017,11 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             break;
 
           case GPIOR:
-            regs.gpior = reg;
+            // Only write writable bits
+            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
+            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
+                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
             /* these just control general purpose i/o pins, don't matter */
             break;
 
@@ -793,23 +1034,23 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             regs.rxdp_hi = reg;
             break;
 
-          case RXCFG:
+          case RX_CFG:
             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) ;
+            if (reg & RX_CFG_AEP) ;
+            if (reg & RX_CFG_ARP) ;
+            if (reg & RX_CFG_STRIPCRC) ;
+            if (reg & RX_CFG_RX_RD) ;
+            if (reg & RX_CFG_ALP) ;
+            if (reg & RX_CFG_AIRL) ;
 
             /* we handle our own DMA, ignore what kernel says about it */
-            if (reg & RXCFG_MXDMA) ;
+            if (reg & RX_CFG_MXDMA) ;
 
             //also, we currently don't care about fill/drain thresholds
             //though this may change in the future with more realistic
             //networks or a driver which changes it according to feedback
-            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
+            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
 #endif
             break;
 
@@ -837,14 +1078,14 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             acceptUnicast = (reg & RFCR_AAU) ? true : false;
             acceptPerfect = (reg & RFCR_APM) ? true : false;
             acceptArp = (reg & RFCR_AARP) ? true : false;
+            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
 
 #if 0
             if (reg & RFCR_APAT)
                 panic("RFCR_APAT not implemented!\n");
 #endif
-
-            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
-                panic("hash filtering not implemented!\n");
+            if (reg & RFCR_UHEN)
+                panic("Unicast hash filtering not used by drivers!\n");
 
             if (reg & RFCR_ULM)
                 panic("RFCR_ULM not implemented!\n");
@@ -852,10 +1093,41 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             break;
 
           case RFDR:
-            panic("the driver never writes to RFDR, something is wrong!\n");
+            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+            switch (rfaddr) {
+              case 0x000:
+                rom.perfectMatch[0] = (uint8_t)reg;
+                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
+                break;
+              case 0x002:
+                rom.perfectMatch[2] = (uint8_t)reg;
+                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
+                break;
+              case 0x004:
+                rom.perfectMatch[4] = (uint8_t)reg;
+                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
+                break;
+              default:
+
+                if (rfaddr >= FHASH_ADDR &&
+                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
+
+                    // Only word-aligned writes supported
+                    if (rfaddr % 2)
+                        panic("unaligned write to filter hash table!");
+
+                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
+                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
+                        = (uint8_t)(reg >> 8);
+                    break;
+                }
+                panic("writing RFDR for something other than pattern matching\
+                    or hashing! %#x\n", rfaddr);
+            }
 
           case BRAR:
-            panic("the driver never uses BRAR, something is wrong!\n");
+            regs.brar = reg;
+            break;
 
           case BRDR:
             panic("the driver never uses BRDR, something is wrong!\n");
@@ -876,7 +1148,6 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
 
           case VDR:
             panic("the driver never uses VDR, something is wrong!\n");
-            break;
 
           case CCSR:
             /* not going to implement clockrun stuff */
@@ -903,12 +1174,16 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data)
             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");
+            // Only write the writable bits
+            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
+            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
+
+            // Pause capability unimplemented
+#if 0
+            if (reg & TANAR_PS2) ;
+            if (reg & TANAR_PS1) ;
+#endif
 
-            if (reg & TANAR_PS1)
-                panic("this isn't used in driver, something wrong!\n");
             break;
 
           case TANLPAR:
@@ -940,27 +1215,87 @@ NSGigE::devIntrPost(uint32_t interrupts)
     if (interrupts & ISR_NOIMPL)
         warn("interrupt not implemented %#x\n", interrupts);
 
-    interrupts &= ~ISR_NOIMPL;
+    interrupts &= ISR_IMPL;
     regs.isr |= interrupts;
 
+    if (interrupts & regs.imr) {
+        if (interrupts & ISR_SWI) {
+            totalSwi++;
+        }
+        if (interrupts & ISR_RXIDLE) {
+            totalRxIdle++;
+        }
+        if (interrupts & ISR_RXOK) {
+            totalRxOk++;
+        }
+        if (interrupts & ISR_RXDESC) {
+            totalRxDesc++;
+        }
+        if (interrupts & ISR_TXOK) {
+            totalTxOk++;
+        }
+        if (interrupts & ISR_TXIDLE) {
+            totalTxIdle++;
+        }
+        if (interrupts & ISR_TXDESC) {
+            totalTxDesc++;
+        }
+        if (interrupts & ISR_RXORN) {
+            totalRxOrn++;
+        }
+    }
+
     DPRINTF(EthernetIntr,
             "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
             interrupts, regs.isr, regs.imr);
 
     if ((regs.isr & regs.imr)) {
         Tick when = curTick;
-        if (!(regs.isr & regs.imr & ISR_NODELAY))
+        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
             when += intrDelay;
         cpuIntrPost(when);
     }
 }
 
+/* writing this interrupt counting stats inside this means that this function
+   is now limited to being used to clear all interrupts upon the kernel
+   reading isr and servicing.  just telling you in case you were thinking
+   of expanding use.
+*/
 void
 NSGigE::devIntrClear(uint32_t interrupts)
 {
     if (interrupts & ISR_RESERVE)
         panic("Cannot clear a reserved interrupt");
 
+    if (regs.isr & regs.imr & ISR_SWI) {
+        postedSwi++;
+    }
+    if (regs.isr & regs.imr & ISR_RXIDLE) {
+        postedRxIdle++;
+    }
+    if (regs.isr & regs.imr & ISR_RXOK) {
+        postedRxOk++;
+    }
+    if (regs.isr & regs.imr & ISR_RXDESC) {
+            postedRxDesc++;
+    }
+    if (regs.isr & regs.imr & ISR_TXOK) {
+        postedTxOk++;
+    }
+    if (regs.isr & regs.imr & ISR_TXIDLE) {
+        postedTxIdle++;
+    }
+    if (regs.isr & regs.imr & ISR_TXDESC) {
+        postedTxDesc++;
+    }
+    if (regs.isr & regs.imr & ISR_RXORN) {
+        postedRxOrn++;
+    }
+
+    if (regs.isr & regs.imr & ISR_IMPL)
+        postedInterrupts++;
+
     interrupts &= ~ISR_NOIMPL;
     regs.isr &= ~interrupts;
 
@@ -1037,8 +1372,8 @@ NSGigE::cpuInterrupt()
         // Send interrupt
         cpuPendingIntr = true;
 
-        DPRINTF(EthernetIntr, "posting cchip interrupt\n");
-        tsunami->postPciInt(configData->config.hdr.pci0.interruptLine);
+        DPRINTF(EthernetIntr, "posting interrupt\n");
+        intrPost();
     }
 }
 
@@ -1057,8 +1392,8 @@ NSGigE::cpuIntrClear()
 
     cpuPendingIntr = false;
 
-    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
-    tsunami->clearPciInt(configData->config.hdr.pci0.interruptLine);
+    DPRINTF(EthernetIntr, "clearing interrupt\n");
+    intrClear();
 }
 
 bool
@@ -1072,7 +1407,6 @@ NSGigE::txReset()
     DPRINTF(Ethernet, "transmit reset\n");
 
     CTDD = false;
-    txFifoAvail = maxTxFifoSize;
     txEnable = false;;
     txFragPtr = 0;
     assert(txDescCnt == 0);
@@ -1088,7 +1422,6 @@ NSGigE::rxReset()
 
     CRDD = false;
     assert(rxPktBytes == 0);
-    rxFifoCnt = 0;
     rxEnable = false;
     rxFragPtr = 0;
     assert(rxDescCnt == 0);
@@ -1101,8 +1434,8 @@ void
 NSGigE::regsReset()
 {
     memset(&regs, 0, sizeof(regs));
-    regs.config = CFG_LNKSTS;
-    regs.mear = MEAR_MDDIR | MEAR_EEDO;
+    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
+    regs.mear = 0x12;
     regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
                         // fill threshold to 32 bytes
     regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
@@ -1110,6 +1443,7 @@ NSGigE::regsReset()
     regs.mibc = MIBC_FRZ;
     regs.vdr = 0x81;    // set the vlan tag type to 802.1q
     regs.tesr = 0xc000; // TBI capable of both full and half duplex
+    regs.brar = 0xffffffff;
 
     extstsEnable = false;
     acceptBroadcast = false;
@@ -1226,16 +1560,29 @@ NSGigE::rxDmaWriteDone()
 void
 NSGigE::rxKick()
 {
-    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
-            NsRxStateStrings[rxState], rxFifo.size());
+    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
 
-    if (rxKickTick > curTick) {
-        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
-                rxKickTick);
-        return;
-    }
+    DPRINTF(EthernetSM,
+            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
+            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
+
+    Addr link, bufptr;
+    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
+    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
 
   next:
+    if (clock) {
+        if (rxKickTick > curTick) {
+            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
+                    rxKickTick);
+
+            goto exit;
+        }
+
+        // Go to the next state machine clock tick.
+        rxKickTick = curTick + cycles(1);
+    }
+
     switch(rxDmaState) {
       case dmaReadWaiting:
         if (doRxDmaRead())
@@ -1249,6 +1596,9 @@ NSGigE::rxKick()
         break;
     }
 
+    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
+    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
+
     // see state machine from spec for details
     // the way this works is, if you finish work on one state and can
     // go directly to another, you do that through jumping to the
@@ -1267,8 +1617,9 @@ NSGigE::rxKick()
             rxState = rxDescRefr;
 
             rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
-            rxDmaLen = sizeof(rxDescCache.link);
+            rxDmaData =
+                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
+            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
             rxDmaFree = dmaDescFree;
 
             descDmaReads++;
@@ -1280,8 +1631,8 @@ NSGigE::rxKick()
             rxState = rxDescRead;
 
             rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData = &rxDescCache;
-            rxDmaLen = sizeof(ns_desc);
+            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
             rxDmaFree = dmaDescFree;
 
             descDmaReads++;
@@ -1303,22 +1654,20 @@ NSGigE::rxKick()
         if (rxDmaState != dmaIdle)
             goto exit;
 
-        DPRINTF(EthernetDesc,
-                "rxDescCache: addr=%08x read descriptor\n",
+        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
                 regs.rxdp & 0x3fffffff);
         DPRINTF(EthernetDesc,
-                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
-                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
-                rxDescCache.extsts);
+                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+                link, bufptr, cmdsts, extsts);
 
-        if (rxDescCache.cmdsts & CMDSTS_OWN) {
+        if (cmdsts & CMDSTS_OWN) {
             devIntrPost(ISR_RXIDLE);
             rxState = rxIdle;
             goto exit;
         } else {
             rxState = rxFifoBlock;
-            rxFragPtr = rxDescCache.bufptr;
-            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
+            rxFragPtr = bufptr;
+            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
         }
         break;
 
@@ -1341,13 +1690,15 @@ NSGigE::rxKick()
 
 #if TRACING_ON
             if (DTRACE(Ethernet)) {
-                const IpHdr *ip = rxPacket->ip();
+                IpPtr ip(rxPacket);
                 if (ip) {
                     DPRINTF(Ethernet, "ID is %d\n", ip->id());
-                    const TcpHdr *tcp = rxPacket->tcp();
+                    TcpPtr tcp(ip);
                     if (tcp) {
-                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
-                                tcp->sport(), tcp->dport());
+                        DPRINTF(Ethernet,
+                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                                tcp->sport(), tcp->dport(), tcp->seq(),
+                                tcp->ack());
                     }
                 }
             }
@@ -1355,12 +1706,7 @@ NSGigE::rxKick()
 
             // sanity check - i think the driver behaves like this
             assert(rxDescCnt >= rxPktBytes);
-
-            // Must clear the value before popping to decrement the
-            // reference count
-            rxFifo.front() = NULL;
-            rxFifo.pop_front();
-            rxFifoCnt -= rxPacket->length;
+            rxFifo.pop();
         }
 
 
@@ -1387,11 +1733,11 @@ NSGigE::rxKick()
             assert(rxPktBytes == 0);
             DPRINTF(EthernetSM, "done with receiving packet\n");
 
-            rxDescCache.cmdsts |= CMDSTS_OWN;
-            rxDescCache.cmdsts &= ~CMDSTS_MORE;
-            rxDescCache.cmdsts |= CMDSTS_OK;
-            rxDescCache.cmdsts &= 0xffff0000;
-            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
+            cmdsts |= CMDSTS_OWN;
+            cmdsts &= ~CMDSTS_MORE;
+            cmdsts |= CMDSTS_OK;
+            cmdsts &= 0xffff0000;
+            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
 
 #if 0
             /*
@@ -1402,39 +1748,41 @@ NSGigE::rxKick()
              * functional purposes, just undef
              */
             if (rxFilterEnable) {
-                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
-                EthHdr *eth = rxFifoFront()->eth();
-                if (eth->unicast())
-                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
-                if (eth->multicast())
-                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
-                if (eth->broadcast())
-                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
+                cmdsts &= ~CMDSTS_DEST_MASK;
+                const EthAddr &dst = rxFifoFront()->dst();
+                if (dst->unicast())
+                    cmdsts |= CMDSTS_DEST_SELF;
+                if (dst->multicast())
+                    cmdsts |= CMDSTS_DEST_MULTI;
+                if (dst->broadcast())
+                    cmdsts |= CMDSTS_DEST_MASK;
             }
 #endif
 
-            if (extstsEnable && rxPacket->ip()) {
-                rxDescCache.extsts |= EXTSTS_IPPKT;
+            IpPtr ip(rxPacket);
+            if (extstsEnable && ip) {
+                extsts |= EXTSTS_IPPKT;
                 rxIpChecksums++;
-                IpHdr *ip = rxPacket->ip();
-                if (ip->ip_cksum() != 0) {
+                if (cksum(ip) != 0) {
                     DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
-                    rxDescCache.extsts |= EXTSTS_IPERR;
+                    extsts |= EXTSTS_IPERR;
                 }
-                if (rxPacket->tcp()) {
-                    rxDescCache.extsts |= EXTSTS_TCPPKT;
+                TcpPtr tcp(ip);
+                UdpPtr udp(ip);
+                if (tcp) {
+                    extsts |= EXTSTS_TCPPKT;
                     rxTcpChecksums++;
-                    if (ip->tu_cksum() != 0) {
+                    if (cksum(tcp) != 0) {
                         DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
-                        rxDescCache.extsts |= EXTSTS_TCPERR;
+                        extsts |= EXTSTS_TCPERR;
 
                     }
-                } else if (rxPacket->udp()) {
-                    rxDescCache.extsts |= EXTSTS_UDPPKT;
+                } else if (udp) {
+                    extsts |= EXTSTS_UDPPKT;
                     rxUdpChecksums++;
-                    if (ip->tu_cksum() != 0) {
+                    if (cksum(udp) != 0) {
                         DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
-                        rxDescCache.extsts |= EXTSTS_UDPERR;
+                        extsts |= EXTSTS_UDPERR;
                     }
                 }
             }
@@ -1448,16 +1796,21 @@ NSGigE::rxKick()
              */
 
             DPRINTF(EthernetDesc,
-                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
+                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
                     regs.rxdp & 0x3fffffff);
             DPRINTF(EthernetDesc,
-                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
-                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
-                    rxDescCache.extsts);
+                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+                    link, bufptr, cmdsts, extsts);
 
-            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
-            rxDmaData = &(rxDescCache.cmdsts);
-            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
+            rxDmaAddr = regs.rxdp & 0x3fffffff;
+            rxDmaData = &cmdsts;
+            if (is64bit) {
+                rxDmaAddr += offsetof(ns_desc64, cmdsts);
+                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
+            } else {
+                rxDmaAddr += offsetof(ns_desc32, cmdsts);
+                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
+            }
             rxDmaFree = dmaDescFree;
 
             descDmaWrites++;
@@ -1483,12 +1836,12 @@ NSGigE::rxKick()
         if (rxDmaState != dmaIdle)
             goto exit;
 
-        assert(rxDescCache.cmdsts & CMDSTS_OWN);
+        assert(cmdsts & CMDSTS_OWN);
 
         assert(rxPacket == 0);
         devIntrPost(ISR_RXOK);
 
-        if (rxDescCache.cmdsts & CMDSTS_INTR)
+        if (cmdsts & CMDSTS_INTR)
             devIntrPost(ISR_RXDESC);
 
         if (!rxEnable) {
@@ -1500,19 +1853,21 @@ NSGigE::rxKick()
         break;
 
       case rxAdvance:
-        if (rxDescCache.link == 0) {
+        if (link == 0) {
             devIntrPost(ISR_RXIDLE);
             rxState = rxIdle;
             CRDD = true;
             goto exit;
         } else {
+            if (rxDmaState != dmaIdle)
+                goto exit;
             rxState = rxDescRead;
-            regs.rxdp = rxDescCache.link;
+            regs.rxdp = link;
             CRDD = false;
 
             rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData = &rxDescCache;
-            rxDmaLen = sizeof(ns_desc);
+            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
             rxDmaFree = dmaDescFree;
 
             if (doRxDmaRead())
@@ -1526,7 +1881,6 @@ NSGigE::rxKick()
 
     DPRINTF(EthernetSM, "entering next rxState=%s\n",
             NsRxStateStrings[rxState]);
-
     goto next;
 
   exit:
@@ -1535,6 +1889,9 @@ NSGigE::rxKick()
      */
     DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
             NsRxStateStrings[rxState]);
+
+    if (clock && !rxKickEvent.scheduled())
+        rxKickEvent.schedule(rxKickTick);
 }
 
 void
@@ -1546,32 +1903,31 @@ NSGigE::transmit()
     }
 
     DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
-            maxTxFifoSize - txFifoAvail);
+            txFifo.size());
     if (interface->sendPacket(txFifo.front())) {
 #if TRACING_ON
         if (DTRACE(Ethernet)) {
-            const IpHdr *ip = txFifo.front()->ip();
+            IpPtr ip(txFifo.front());
             if (ip) {
                 DPRINTF(Ethernet, "ID is %d\n", ip->id());
-                const TcpHdr *tcp = txFifo.front()->tcp();
+                TcpPtr tcp(ip);
                 if (tcp) {
-                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
-                            tcp->sport(), tcp->dport());
+                    DPRINTF(Ethernet,
+                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                            tcp->sport(), tcp->dport(), tcp->seq(),
+                            tcp->ack());
                 }
             }
         }
 #endif
 
-        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
+        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
         txBytes += txFifo.front()->length;
         txPackets++;
 
-        txFifoAvail += txFifo.front()->length;
-
         DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
-                txFifoAvail);
-        txFifo.front() = NULL;
-        txFifo.pop_front();
+                txFifo.avail());
+        txFifo.pop();
 
         /*
          * normally do a writeback of the descriptor here, and ONLY
@@ -1581,14 +1937,11 @@ NSGigE::transmit()
          * besides, it's functionally the same.
          */
         devIntrPost(ISR_TXOK);
-    } else {
-        DPRINTF(Ethernet,
-                "May need to rethink always sending the descriptors back?\n");
     }
 
    if (!txFifo.empty() && !txEvent.scheduled()) {
        DPRINTF(Ethernet, "reschedule transmit\n");
-       txEvent.schedule(curTick + 1000);
+       txEvent.schedule(curTick + retryTime);
    }
 }
 
@@ -1699,17 +2052,27 @@ NSGigE::txDmaWriteDone()
 void
 NSGigE::txKick()
 {
-    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
-            NsTxStateStrings[txState]);
+    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
 
-    if (txKickTick > curTick) {
-        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
-                txKickTick);
+    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
+            NsTxStateStrings[txState], is64bit ? 64 : 32);
 
-        return;
-    }
+    Addr link, bufptr;
+    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
+    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
 
   next:
+    if (clock) {
+        if (txKickTick > curTick) {
+            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
+                    txKickTick);
+            goto exit;
+        }
+
+        // Go to the next state machine clock tick.
+        txKickTick = curTick + cycles(1);
+    }
+
     switch(txDmaState) {
       case dmaReadWaiting:
         if (doTxDmaRead())
@@ -1723,6 +2086,8 @@ NSGigE::txKick()
         break;
     }
 
+    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
+    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
     switch (txState) {
       case txIdle:
         if (!txEnable) {
@@ -1734,8 +2099,9 @@ NSGigE::txKick()
             txState = txDescRefr;
 
             txDmaAddr = regs.txdp & 0x3fffffff;
-            txDmaData = &txDescCache + offsetof(ns_desc, link);
-            txDmaLen = sizeof(txDescCache.link);
+            txDmaData =
+                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
+            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
             txDmaFree = dmaDescFree;
 
             descDmaReads++;
@@ -1748,8 +2114,8 @@ NSGigE::txKick()
             txState = txDescRead;
 
             txDmaAddr = regs.txdp & 0x3fffffff;
-            txDmaData = &txDescCache;
-            txDmaLen = sizeof(ns_desc);
+            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
             txDmaFree = dmaDescFree;
 
             descDmaReads++;
@@ -1771,15 +2137,16 @@ NSGigE::txKick()
         if (txDmaState != dmaIdle)
             goto exit;
 
+        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
+                regs.txdp & 0x3fffffff);
         DPRINTF(EthernetDesc,
-                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
-                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
-                txDescCache.extsts);
+                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
+                link, bufptr, cmdsts, extsts);
 
-        if (txDescCache.cmdsts & CMDSTS_OWN) {
+        if (cmdsts & CMDSTS_OWN) {
             txState = txFifoBlock;
-            txFragPtr = txDescCache.bufptr;
-            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
+            txFragPtr = bufptr;
+            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
         } else {
             devIntrPost(ISR_TXIDLE);
             txState = txIdle;
@@ -1790,23 +2157,27 @@ NSGigE::txKick()
       case txFifoBlock:
         if (!txPacket) {
             DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
-            txPacket = new PacketData;
-            txPacket->data = new uint8_t[16384];
+            txPacket = new PacketData(16384);
             txPacketBufPtr = txPacket->data;
         }
 
         if (txDescCnt == 0) {
             DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
-            if (txDescCache.cmdsts & CMDSTS_MORE) {
+            if (cmdsts & CMDSTS_MORE) {
                 DPRINTF(EthernetSM, "there are more descriptors to come\n");
                 txState = txDescWrite;
 
-                txDescCache.cmdsts &= ~CMDSTS_OWN;
+                cmdsts &= ~CMDSTS_OWN;
 
-                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
-                txDmaAddr &= 0x3fffffff;
-                txDmaData = &(txDescCache.cmdsts);
-                txDmaLen = sizeof(txDescCache.cmdsts);
+                txDmaAddr = regs.txdp & 0x3fffffff;
+                txDmaData = &cmdsts;
+                if (is64bit) {
+                    txDmaAddr += offsetof(ns_desc64, cmdsts);
+                    txDmaLen = sizeof(txDesc64.cmdsts);
+                } else {
+                    txDmaAddr += offsetof(ns_desc32, cmdsts);
+                    txDmaLen = sizeof(txDesc32.cmdsts);
+                }
                 txDmaFree = dmaDescFree;
 
                 if (doTxDmaWrite())
@@ -1816,21 +2187,21 @@ NSGigE::txKick()
                 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
                 /* deal with the the packet that just finished */
                 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
-                    IpHdr *ip = txPacket->ip();
-                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
-                        UdpHdr *udp = txPacket->udp();
+                    IpPtr ip(txPacket);
+                    if (extsts & EXTSTS_UDPPKT) {
+                        UdpPtr udp(ip);
                         udp->sum(0);
-                        udp->sum(ip->tu_cksum());
+                        udp->sum(cksum(udp));
                         txUdpChecksums++;
-                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
-                        TcpHdr *tcp = txPacket->tcp();
+                    } else if (extsts & EXTSTS_TCPPKT) {
+                        TcpPtr tcp(ip);
                         tcp->sum(0);
-                        tcp->sum(ip->tu_cksum());
+                        tcp->sum(cksum(tcp));
                         txTcpChecksums++;
                     }
-                    if (txDescCache.extsts & EXTSTS_IPPKT) {
+                    if (extsts & EXTSTS_IPPKT) {
                         ip->sum(0);
-                        ip->sum(ip->ip_cksum());
+                        ip->sum(cksum(ip));
                         txIpChecksums++;
                     }
                 }
@@ -1838,8 +2209,15 @@ NSGigE::txKick()
                 txPacket->length = txPacketBufPtr - txPacket->data;
                 // this is just because the receive can't handle a
                 // packet bigger want to make sure
-                assert(txPacket->length <= 1514);
-                txFifo.push_back(txPacket);
+                if (txPacket->length > 1514)
+                    panic("transmit packet too large, %s > 1514\n",
+                          txPacket->length);
+
+#ifndef NDEBUG
+                bool success =
+#endif
+                    txFifo.push(txPacket);
+                assert(success);
 
                 /*
                  * this following section is not tqo spec, but
@@ -1853,19 +2231,25 @@ NSGigE::txKick()
                  * spec would complicate the code, we just do it here
                  */
 
-                txDescCache.cmdsts &= ~CMDSTS_OWN;
-                txDescCache.cmdsts |= CMDSTS_OK;
+                cmdsts &= ~CMDSTS_OWN;
+                cmdsts |= CMDSTS_OK;
 
                 DPRINTF(EthernetDesc,
                         "txDesc writeback: cmdsts=%08x extsts=%08x\n",
-                        txDescCache.cmdsts, txDescCache.extsts);
+                        cmdsts, extsts);
 
-                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
-                txDmaAddr &= 0x3fffffff;
-                txDmaData = &(txDescCache.cmdsts);
-                txDmaLen = sizeof(txDescCache.cmdsts) +
-                    sizeof(txDescCache.extsts);
                 txDmaFree = dmaDescFree;
+                txDmaAddr = regs.txdp & 0x3fffffff;
+                txDmaData = &cmdsts;
+                if (is64bit) {
+                    txDmaAddr += offsetof(ns_desc64, cmdsts);
+                    txDmaLen =
+                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
+                } else {
+                    txDmaAddr += offsetof(ns_desc32, cmdsts);
+                    txDmaLen =
+                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
+                }
 
                 descDmaWrites++;
                 descDmaWrBytes += txDmaLen;
@@ -1885,7 +2269,7 @@ NSGigE::txKick()
             }
         } else {
             DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
-            if (txFifoAvail) {
+            if (!txFifo.full()) {
                 txState = txFragRead;
 
                 /*
@@ -1894,7 +2278,7 @@ NSGigE::txKick()
                  * is not enough room in the fifo, just whatever room
                  * is left in the fifo
                  */
-                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
+                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
 
                 txDmaAddr = txFragPtr & 0x3fffffff;
                 txDmaData = txPacketBufPtr;
@@ -1920,7 +2304,7 @@ NSGigE::txKick()
         txPacketBufPtr += txXferLen;
         txFragPtr += txXferLen;
         txDescCnt -= txXferLen;
-        txFifoAvail -= txXferLen;
+        txFifo.reserve(txXferLen);
 
         txState = txFifoBlock;
         break;
@@ -1929,25 +2313,32 @@ NSGigE::txKick()
         if (txDmaState != dmaIdle)
             goto exit;
 
-        if (txDescCache.cmdsts & CMDSTS_INTR)
+        if (cmdsts & CMDSTS_INTR)
             devIntrPost(ISR_TXDESC);
 
-        txState = txAdvance;
+        if (!txEnable) {
+            DPRINTF(EthernetSM, "halting TX state machine\n");
+            txState = txIdle;
+            goto exit;
+        } else
+            txState = txAdvance;
         break;
 
       case txAdvance:
-        if (txDescCache.link == 0) {
+        if (link == 0) {
             devIntrPost(ISR_TXIDLE);
             txState = txIdle;
             goto exit;
         } else {
+            if (txDmaState != dmaIdle)
+                goto exit;
             txState = txDescRead;
-            regs.txdp = txDescCache.link;
+            regs.txdp = link;
             CTDD = false;
 
-            txDmaAddr = txDescCache.link & 0x3fffffff;
-            txDmaData = &txDescCache;
-            txDmaLen = sizeof(ns_desc);
+            txDmaAddr = link & 0x3fffffff;
+            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
             txDmaFree = dmaDescFree;
 
             if (doTxDmaRead())
@@ -1961,7 +2352,6 @@ NSGigE::txKick()
 
     DPRINTF(EthernetSM, "entering next txState=%s\n",
             NsTxStateStrings[txState]);
-
     goto next;
 
   exit:
@@ -1970,6 +2360,110 @@ NSGigE::txKick()
      */
     DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
             NsTxStateStrings[txState]);
+
+    if (clock && !txKickEvent.scheduled())
+        txKickEvent.schedule(txKickTick);
+}
+
+/**
+ * Advance the EEPROM state machine
+ * Called on rising edge of EEPROM clock bit in MEAR
+ */
+void
+NSGigE::eepromKick()
+{
+    switch (eepromState) {
+
+      case eepromStart:
+
+        // Wait for start bit
+        if (regs.mear & MEAR_EEDI) {
+            // Set up to get 2 opcode bits
+            eepromState = eepromGetOpcode;
+            eepromBitsToRx = 2;
+            eepromOpcode = 0;
+        }
+        break;
+
+      case eepromGetOpcode:
+        eepromOpcode <<= 1;
+        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
+        --eepromBitsToRx;
+
+        // Done getting opcode
+        if (eepromBitsToRx == 0) {
+            if (eepromOpcode != EEPROM_READ)
+                panic("only EEPROM reads are implemented!");
+
+            // Set up to get address
+            eepromState = eepromGetAddress;
+            eepromBitsToRx = 6;
+            eepromAddress = 0;
+        }
+        break;
+
+      case eepromGetAddress:
+        eepromAddress <<= 1;
+        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
+        --eepromBitsToRx;
+
+        // Done getting address
+        if (eepromBitsToRx == 0) {
+
+            if (eepromAddress >= EEPROM_SIZE)
+                panic("EEPROM read access out of range!");
+
+            switch (eepromAddress) {
+
+              case EEPROM_PMATCH2_ADDR:
+                eepromData = rom.perfectMatch[5];
+                eepromData <<= 8;
+                eepromData += rom.perfectMatch[4];
+                break;
+
+              case EEPROM_PMATCH1_ADDR:
+                eepromData = rom.perfectMatch[3];
+                eepromData <<= 8;
+                eepromData += rom.perfectMatch[2];
+                break;
+
+              case EEPROM_PMATCH0_ADDR:
+                eepromData = rom.perfectMatch[1];
+                eepromData <<= 8;
+                eepromData += rom.perfectMatch[0];
+                break;
+
+              default:
+                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
+            }
+            // Set up to read data
+            eepromState = eepromRead;
+            eepromBitsToRx = 16;
+
+            // Clear data in bit
+            regs.mear &= ~MEAR_EEDI;
+        }
+        break;
+
+      case eepromRead:
+        // Clear Data Out bit
+        regs.mear &= ~MEAR_EEDO;
+        // Set bit to value of current EEPROM bit
+        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
+
+        eepromData <<= 1;
+        --eepromBitsToRx;
+
+        // All done
+        if (eepromBitsToRx == 0) {
+            eepromState = eepromStart;
+        }
+        break;
+
+      default:
+        panic("invalid EEPROM state");
+    }
+
 }
 
 void
@@ -1983,41 +2477,44 @@ NSGigE::transferDone()
     DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
 
     if (txEvent.scheduled())
-        txEvent.reschedule(curTick + 1);
+        txEvent.reschedule(curTick + cycles(1));
     else
-        txEvent.schedule(curTick + 1);
+        txEvent.schedule(curTick + cycles(1));
 }
 
 bool
-NSGigE::rxFilter(PacketPtr packet)
+NSGigE::rxFilter(const PacketPtr &packet)
 {
+    EthPtr eth = packet;
     bool drop = true;
     string type;
 
-    EthHdr *eth = packet->eth();
-    if (eth->unicast()) {
+    const EthAddr &dst = eth->dst();
+    if (dst.unicast()) {
         // If we're accepting all unicast addresses
         if (acceptUnicast)
             drop = false;
 
         // If we make a perfect match
-        if (acceptPerfect &&
-            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
+        if (acceptPerfect && dst == rom.perfectMatch)
             drop = false;
 
         if (acceptArp && eth->type() == ETH_TYPE_ARP)
             drop = false;
 
-    } else if (eth->broadcast()) {
+    } else if (dst.broadcast()) {
         // if we're accepting broadcasts
         if (acceptBroadcast)
             drop = false;
 
-    } else if (eth->multicast()) {
+    } else if (dst.multicast()) {
         // if we're accepting all multicasts
         if (acceptMulticast)
             drop = false;
 
+        // Multicast hashing faked - all packets accepted
+        if (multicastHashEnable)
+            drop = false;
     }
 
     if (drop) {
@@ -2035,31 +2532,43 @@ NSGigE::recvPacket(PacketPtr packet)
     rxPackets++;
 
     DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
-            maxRxFifoSize - rxFifoCnt);
+            rxFifo.avail());
 
     if (!rxEnable) {
         DPRINTF(Ethernet, "receive disabled...packet dropped\n");
-        debug_break();
-        interface->recvDone();
         return true;
     }
 
-    if (rxFilterEnable && rxFilter(packet)) {
+    if (!rxFilterEnable) {
+        DPRINTF(Ethernet,
+            "receive packet filtering disabled . . . packet dropped\n");
+        return true;
+    }
+
+    if (rxFilter(packet)) {
         DPRINTF(Ethernet, "packet filtered...dropped\n");
-        interface->recvDone();
         return true;
     }
 
-    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
-        DPRINTF(Ethernet,
-                "packet will not fit in receive buffer...packet dropped\n");
+    if (rxFifo.avail() < packet->length) {
+#if TRACING_ON
+        IpPtr ip(packet);
+        TcpPtr tcp(ip);
+        if (ip) {
+            DPRINTF(Ethernet,
+                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
+                    ip->id());
+            if (tcp) {
+                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
+            }
+        }
+#endif
+        droppedPackets++;
         devIntrPost(ISR_RXORN);
         return false;
     }
 
-    rxFifo.push_back(packet);
-    rxFifoCnt += packet->length;
-    interface->recvDone();
+    rxFifo.push(packet);
 
     rxKick();
     return true;
@@ -2109,6 +2618,8 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(regs.pcr);
     SERIALIZE_SCALAR(regs.rfcr);
     SERIALIZE_SCALAR(regs.rfdr);
+    SERIALIZE_SCALAR(regs.brar);
+    SERIALIZE_SCALAR(regs.brdr);
     SERIALIZE_SCALAR(regs.srr);
     SERIALIZE_SCALAR(regs.mibc);
     SERIALIZE_SCALAR(regs.vrcr);
@@ -2122,30 +2633,16 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(regs.taner);
     SERIALIZE_SCALAR(regs.tesr);
 
-    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
 
     SERIALIZE_SCALAR(ioEnable);
 
     /*
      * Serialize the data Fifos
      */
-    int txNumPkts = txFifo.size();
-    SERIALIZE_SCALAR(txNumPkts);
-    int i = 0;
-    pktiter_t end = txFifo.end();
-    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
-        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
-        (*p)->serialize(os);
-    }
-
-    int rxNumPkts = rxFifo.size();
-    SERIALIZE_SCALAR(rxNumPkts);
-    i = 0;
-    end = rxFifo.end();
-    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
-        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
-        (*p)->serialize(os);
-    }
+    rxFifo.serialize("rxFifo", os);
+    txFifo.serialize("txFifo", os);
 
     /*
      * Serialize the various helper variables
@@ -2153,8 +2650,8 @@ NSGigE::serialize(ostream &os)
     bool txPacketExists = txPacket;
     SERIALIZE_SCALAR(txPacketExists);
     if (txPacketExists) {
-        nameOut(os, csprintf("%s.txPacket", name()));
-        txPacket->serialize(os);
+        txPacket->length = txPacketBufPtr - txPacket->data;
+        txPacket->serialize("txPacket", os);
         uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
         SERIALIZE_SCALAR(txPktBufPtr);
     }
@@ -2162,8 +2659,7 @@ NSGigE::serialize(ostream &os)
     bool rxPacketExists = rxPacket;
     SERIALIZE_SCALAR(rxPacketExists);
     if (rxPacketExists) {
-        nameOut(os, csprintf("%s.rxPacket", name()));
-        rxPacket->serialize(os);
+        rxPacket->serialize("rxPacket", os);
         uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
         SERIALIZE_SCALAR(rxPktBufPtr);
     }
@@ -2172,16 +2668,25 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(rxXferLen);
 
     /*
-     * Serialize DescCaches
+     * Serialize Cached Descriptors
      */
-    SERIALIZE_SCALAR(txDescCache.link);
-    SERIALIZE_SCALAR(txDescCache.bufptr);
-    SERIALIZE_SCALAR(txDescCache.cmdsts);
-    SERIALIZE_SCALAR(txDescCache.extsts);
-    SERIALIZE_SCALAR(rxDescCache.link);
-    SERIALIZE_SCALAR(rxDescCache.bufptr);
-    SERIALIZE_SCALAR(rxDescCache.cmdsts);
-    SERIALIZE_SCALAR(rxDescCache.extsts);
+    SERIALIZE_SCALAR(rxDesc64.link);
+    SERIALIZE_SCALAR(rxDesc64.bufptr);
+    SERIALIZE_SCALAR(rxDesc64.cmdsts);
+    SERIALIZE_SCALAR(rxDesc64.extsts);
+    SERIALIZE_SCALAR(txDesc64.link);
+    SERIALIZE_SCALAR(txDesc64.bufptr);
+    SERIALIZE_SCALAR(txDesc64.cmdsts);
+    SERIALIZE_SCALAR(txDesc64.extsts);
+    SERIALIZE_SCALAR(rxDesc32.link);
+    SERIALIZE_SCALAR(rxDesc32.bufptr);
+    SERIALIZE_SCALAR(rxDesc32.cmdsts);
+    SERIALIZE_SCALAR(rxDesc32.extsts);
+    SERIALIZE_SCALAR(txDesc32.link);
+    SERIALIZE_SCALAR(txDesc32.bufptr);
+    SERIALIZE_SCALAR(txDesc32.cmdsts);
+    SERIALIZE_SCALAR(txDesc32.extsts);
+    SERIALIZE_SCALAR(extstsEnable);
 
     /*
      * Serialize tx state machine
@@ -2190,11 +2695,11 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(txState);
     SERIALIZE_SCALAR(txEnable);
     SERIALIZE_SCALAR(CTDD);
-    SERIALIZE_SCALAR(txFifoAvail);
     SERIALIZE_SCALAR(txFragPtr);
     SERIALIZE_SCALAR(txDescCnt);
     int txDmaState = this->txDmaState;
     SERIALIZE_SCALAR(txDmaState);
+    SERIALIZE_SCALAR(txKickTick);
 
     /*
      * Serialize rx state machine
@@ -2204,12 +2709,22 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(rxEnable);
     SERIALIZE_SCALAR(CRDD);
     SERIALIZE_SCALAR(rxPktBytes);
-    SERIALIZE_SCALAR(rxFifoCnt);
+    SERIALIZE_SCALAR(rxFragPtr);
     SERIALIZE_SCALAR(rxDescCnt);
     int rxDmaState = this->rxDmaState;
     SERIALIZE_SCALAR(rxDmaState);
+    SERIALIZE_SCALAR(rxKickTick);
 
-    SERIALIZE_SCALAR(extstsEnable);
+    /*
+     * Serialize EEPROM state machine
+     */
+    int eepromState = this->eepromState;
+    SERIALIZE_SCALAR(eepromState);
+    SERIALIZE_SCALAR(eepromClk);
+    SERIALIZE_SCALAR(eepromBitsToRx);
+    SERIALIZE_SCALAR(eepromOpcode);
+    SERIALIZE_SCALAR(eepromAddress);
+    SERIALIZE_SCALAR(eepromData);
 
     /*
      * If there's a pending transmit, store the time so we can
@@ -2227,6 +2742,7 @@ NSGigE::serialize(ostream &os)
     SERIALIZE_SCALAR(acceptUnicast);
     SERIALIZE_SCALAR(acceptPerfect);
     SERIALIZE_SCALAR(acceptArp);
+    SERIALIZE_SCALAR(multicastHashEnable);
 
     /*
      * Keep track of pending interrupt status.
@@ -2266,6 +2782,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(regs.pcr);
     UNSERIALIZE_SCALAR(regs.rfcr);
     UNSERIALIZE_SCALAR(regs.rfdr);
+    UNSERIALIZE_SCALAR(regs.brar);
+    UNSERIALIZE_SCALAR(regs.brdr);
     UNSERIALIZE_SCALAR(regs.srr);
     UNSERIALIZE_SCALAR(regs.mibc);
     UNSERIALIZE_SCALAR(regs.vrcr);
@@ -2279,29 +2797,16 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(regs.taner);
     UNSERIALIZE_SCALAR(regs.tesr);
 
-    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
 
     UNSERIALIZE_SCALAR(ioEnable);
 
     /*
      * unserialize the data fifos
      */
-    int txNumPkts;
-    UNSERIALIZE_SCALAR(txNumPkts);
-    int i;
-    for (i = 0; i < txNumPkts; ++i) {
-        PacketPtr p = new PacketData;
-        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
-        txFifo.push_back(p);
-    }
-
-    int rxNumPkts;
-    UNSERIALIZE_SCALAR(rxNumPkts);
-    for (i = 0; i < rxNumPkts; ++i) {
-        PacketPtr p = new PacketData;
-        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
-        rxFifo.push_back(p);
-    }
+    rxFifo.unserialize("rxFifo", cp, section);
+    txFifo.unserialize("txFifo", cp, section);
 
     /*
      * unserialize the various helper variables
@@ -2309,8 +2814,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     bool txPacketExists;
     UNSERIALIZE_SCALAR(txPacketExists);
     if (txPacketExists) {
-        txPacket = new PacketData;
-        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
+        txPacket = new PacketData(16384);
+        txPacket->unserialize("txPacket", cp, section);
         uint32_t txPktBufPtr;
         UNSERIALIZE_SCALAR(txPktBufPtr);
         txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
@@ -2321,8 +2826,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(rxPacketExists);
     rxPacket = 0;
     if (rxPacketExists) {
-        rxPacket = new PacketData;
-        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
+        rxPacket = new PacketData(16384);
+        rxPacket->unserialize("rxPacket", cp, section);
         uint32_t rxPktBufPtr;
         UNSERIALIZE_SCALAR(rxPktBufPtr);
         rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
@@ -2333,16 +2838,25 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(rxXferLen);
 
     /*
-     * Unserialize DescCaches
+     * Unserialize Cached Descriptors
      */
-    UNSERIALIZE_SCALAR(txDescCache.link);
-    UNSERIALIZE_SCALAR(txDescCache.bufptr);
-    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
-    UNSERIALIZE_SCALAR(txDescCache.extsts);
-    UNSERIALIZE_SCALAR(rxDescCache.link);
-    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
-    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
-    UNSERIALIZE_SCALAR(rxDescCache.extsts);
+    UNSERIALIZE_SCALAR(rxDesc64.link);
+    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
+    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
+    UNSERIALIZE_SCALAR(rxDesc64.extsts);
+    UNSERIALIZE_SCALAR(txDesc64.link);
+    UNSERIALIZE_SCALAR(txDesc64.bufptr);
+    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
+    UNSERIALIZE_SCALAR(txDesc64.extsts);
+    UNSERIALIZE_SCALAR(rxDesc32.link);
+    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
+    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
+    UNSERIALIZE_SCALAR(rxDesc32.extsts);
+    UNSERIALIZE_SCALAR(txDesc32.link);
+    UNSERIALIZE_SCALAR(txDesc32.bufptr);
+    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
+    UNSERIALIZE_SCALAR(txDesc32.extsts);
+    UNSERIALIZE_SCALAR(extstsEnable);
 
     /*
      * unserialize tx state machine
@@ -2352,12 +2866,14 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     this->txState = (TxState) txState;
     UNSERIALIZE_SCALAR(txEnable);
     UNSERIALIZE_SCALAR(CTDD);
-    UNSERIALIZE_SCALAR(txFifoAvail);
     UNSERIALIZE_SCALAR(txFragPtr);
     UNSERIALIZE_SCALAR(txDescCnt);
     int txDmaState;
     UNSERIALIZE_SCALAR(txDmaState);
     this->txDmaState = (DmaState) txDmaState;
+    UNSERIALIZE_SCALAR(txKickTick);
+    if (txKickTick)
+        txKickEvent.schedule(txKickTick);
 
     /*
      * unserialize rx state machine
@@ -2368,15 +2884,28 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(rxEnable);
     UNSERIALIZE_SCALAR(CRDD);
     UNSERIALIZE_SCALAR(rxPktBytes);
-    UNSERIALIZE_SCALAR(rxFifoCnt);
+    UNSERIALIZE_SCALAR(rxFragPtr);
     UNSERIALIZE_SCALAR(rxDescCnt);
     int rxDmaState;
     UNSERIALIZE_SCALAR(rxDmaState);
     this->rxDmaState = (DmaState) rxDmaState;
+    UNSERIALIZE_SCALAR(rxKickTick);
+    if (rxKickTick)
+        rxKickEvent.schedule(rxKickTick);
 
-    UNSERIALIZE_SCALAR(extstsEnable);
+    /*
+     * Unserialize EEPROM state machine
+     */
+    int eepromState;
+    UNSERIALIZE_SCALAR(eepromState);
+    this->eepromState = (EEPROMState) eepromState;
+    UNSERIALIZE_SCALAR(eepromClk);
+    UNSERIALIZE_SCALAR(eepromBitsToRx);
+    UNSERIALIZE_SCALAR(eepromOpcode);
+    UNSERIALIZE_SCALAR(eepromAddress);
+    UNSERIALIZE_SCALAR(eepromData);
 
-     /*
+    /*
      * If there's a pending transmit, reschedule it now
      */
     Tick transmitTick;
@@ -2393,6 +2922,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(acceptUnicast);
     UNSERIALIZE_SCALAR(acceptPerfect);
     UNSERIALIZE_SCALAR(acceptArp);
+    UNSERIALIZE_SCALAR(multicastHashEnable);
 
     /*
      * Keep track of pending interrupt status.
@@ -2410,16 +2940,46 @@ NSGigE::unserialize(Checkpoint *cp, const std::string &section)
      * re-add addrRanges to bus bridges
      */
     if (pioInterface) {
-        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
-        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
+        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
+        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
     }
 }
 
 Tick
 NSGigE::cacheAccess(MemReqPtr &req)
 {
+    Addr daddr = req->paddr & 0xfff;
     DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
-            req->paddr, req->paddr - addr);
+            req->paddr, daddr);
+
+    if (!pioDelayWrite || !req->cmd.isWrite())
+        return curTick + pioLatency;
+
+    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
+    std::list<RegWriteData> &wq = writeQueue[cpu];
+    if (wq.empty())
+        panic("WriteQueue for cpu %d empty timing daddr=%#x", cpu, daddr);
+
+    const RegWriteData &data = wq.front();
+    if (data.daddr != daddr)
+        panic("read mismatch on cpu %d, daddr functional=%#x timing=%#x",
+              cpu, data.daddr, daddr);
+
+    if (daddr == CR) {
+        if ((data.value & (CR_TXD | CR_TXE)) == CR_TXE) {
+            txEnable = true;
+            if (txState == txIdle)
+                txKick();
+        }
+
+        if ((data.value & (CR_RXD | CR_RXE)) == CR_RXE) {
+            rxEnable = true;
+            if (rxState == rxIdle)
+                rxKick();
+        }
+    }
+
+    wq.pop_front();
     return curTick + pioLatency;
 }
 
@@ -2455,81 +3015,130 @@ REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
 
-    Param<Tick> tx_delay;
-    Param<Tick> rx_delay;
-    SimObjectParam<IntrControl *> intr_ctrl;
-    Param<Tick> intr_delay;
+    Param<Tick> clock;
+
+    Param<Addr> addr;
     SimObjectParam<MemoryController *> mmu;
     SimObjectParam<PhysicalMemory *> physmem;
-    Param<bool> rx_filter;
-    Param<string> hardware_address;
-    SimObjectParam<Bus*> header_bus;
-    SimObjectParam<Bus*> payload_bus;
+    SimObjectParam<PciConfigAll *> configspace;
+    SimObjectParam<PciConfigData *> configdata;
+    SimObjectParam<Platform *> platform;
+    Param<uint32_t> pci_bus;
+    Param<uint32_t> pci_dev;
+    Param<uint32_t> pci_func;
+
     SimObjectParam<HierParams *> hier;
-    Param<Tick> pio_latency;
+    SimObjectParam<Bus*> pio_bus;
+    SimObjectParam<Bus*> dma_bus;
+    SimObjectParam<Bus*> payload_bus;
     Param<bool> dma_desc_free;
     Param<bool> dma_data_free;
     Param<Tick> dma_read_delay;
     Param<Tick> dma_write_delay;
     Param<Tick> dma_read_factor;
     Param<Tick> dma_write_factor;
-    SimObjectParam<PciConfigAll *> configspace;
-    SimObjectParam<PciConfigData *> configdata;
-    SimObjectParam<Tsunami *> tsunami;
-    Param<uint32_t> pci_bus;
-    Param<uint32_t> pci_dev;
-    Param<uint32_t> pci_func;
-    Param<uint32_t> tx_fifo_size;
+    Param<bool> dma_no_allocate;
+    Param<Tick> pio_latency;
+    Param<bool> pio_delay_write;
+    Param<Tick> intr_delay;
+
+    Param<Tick> rx_delay;
+    Param<Tick> tx_delay;
     Param<uint32_t> rx_fifo_size;
+    Param<uint32_t> tx_fifo_size;
+
+    Param<bool> rx_filter;
+    Param<string> hardware_address;
+    Param<bool> rx_thread;
+    Param<bool> tx_thread;
 
 END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
 
 BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
 
-    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
-    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
-    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
-    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
+    INIT_PARAM(clock, "State machine processor frequency"),
+
+    INIT_PARAM(addr, "Device Address"),
     INIT_PARAM(mmu, "Memory Controller"),
     INIT_PARAM(physmem, "Physical Memory"),
-    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_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
-    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
-    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
-    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
-    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
-    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
-    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
-    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
-    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
-    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
     INIT_PARAM(configspace, "PCI Configspace"),
     INIT_PARAM(configdata, "PCI Config data"),
-    INIT_PARAM(tsunami, "Tsunami"),
+    INIT_PARAM(platform, "Platform"),
     INIT_PARAM(pci_bus, "PCI bus"),
     INIT_PARAM(pci_dev, "PCI device number"),
     INIT_PARAM(pci_func, "PCI function code"),
-    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
-    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
+
+    INIT_PARAM(hier, "Hierarchy global variables"),
+    INIT_PARAM(pio_bus, ""),
+    INIT_PARAM(dma_bus, ""),
+    INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"),
+    INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"),
+    INIT_PARAM(dma_data_free, "DMA of Data is free"),
+    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
+    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
+    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
+    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
+    INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"),
+    INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"),
+    INIT_PARAM(pio_delay_write, ""),
+    INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
+
+    INIT_PARAM(rx_delay, "Receive Delay"),
+    INIT_PARAM(tx_delay, "Transmit Delay"),
+    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
+    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
+
+    INIT_PARAM(rx_filter, "Enable Receive Filter"),
+    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+    INIT_PARAM(rx_thread, ""),
+    INIT_PARAM(tx_thread, "")
 
 END_INIT_SIM_OBJECT_PARAMS(NSGigE)
 
 
 CREATE_SIM_OBJECT(NSGigE)
 {
-    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 NSGigE(getInstanceName(), intr_ctrl, intr_delay,
-                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
-                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
-                      dma_read_delay, dma_write_delay, dma_read_factor,
-                      dma_write_factor, configspace, configdata,
-                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
-                      tx_fifo_size, rx_fifo_size);
+    NSGigE::Params *params = new NSGigE::Params;
+
+    params->name = getInstanceName();
+
+    params->clock = clock;
+
+    params->mmu = mmu;
+    params->pmem = physmem;
+    params->configSpace = configspace;
+    params->configData = configdata;
+    params->plat = platform;
+    params->busNum = pci_bus;
+    params->deviceNum = pci_dev;
+    params->functionNum = pci_func;
+
+    params->hier = hier;
+    params->pio_bus = pio_bus;
+    params->header_bus = dma_bus;
+    params->payload_bus = payload_bus;
+    params->dma_desc_free = dma_desc_free;
+    params->dma_data_free = dma_data_free;
+    params->dma_read_delay = dma_read_delay;
+    params->dma_write_delay = dma_write_delay;
+    params->dma_read_factor = dma_read_factor;
+    params->dma_write_factor = dma_write_factor;
+    params->dma_no_allocate = dma_no_allocate;
+    params->pio_latency = pio_latency;
+    params->pio_delay_write = pio_delay_write;
+    params->intr_delay = intr_delay;
+
+    params->rx_delay = rx_delay;
+    params->tx_delay = tx_delay;
+    params->rx_fifo_size = rx_fifo_size;
+    params->tx_fifo_size = tx_fifo_size;
+
+    params->rx_filter = rx_filter;
+    params->eaddr = hardware_address;
+    params->rx_thread = rx_thread;
+    params->tx_thread = tx_thread;
+
+    return new NSGigE(params);
 }
 
 REGISTER_SIM_OBJECT("NSGigE", NSGigE)