#include "sim/host.hh"
 #include "sim/stats.hh"
 
+using namespace std;
 using namespace Net;
 using namespace TheISA;
 
     totPackets = txPackets + rxPackets;
     txPacketRate = txPackets / simSeconds;
     rxPacketRate = rxPackets / simSeconds;
+
+    _maxVnicDistance = 0;
+
+    maxVnicDistance
+        .name(name() + ".maxVnicDistance")
+        .desc("maximum vnic distance")
+        ;
+
+    totalVnicDistance
+        .name(name() + ".totalVnicDistance")
+        .desc("total vnic distance")
+        ;
+    numVnicDistance
+        .name(name() + ".numVnicDistance")
+        .desc("number of vnic distance measurements")
+        ;
+
+    avgVnicDistance
+        .name(name() + ".avgVnicDistance")
+        .desc("average vnic distance")
+        ;
+
+    avgVnicDistance = totalVnicDistance / numVnicDistance;
+}
+
+void
+Device::resetStats()
+{
+    _maxVnicDistance = 0;
 }
 
 EtherInt*
               index, size);
 }
 
+//add stats for head of line blocking
+//add stats for average fifo length
+//add stats for average number of vnics busy
+
 void
 Device::prepareRead(int cpu, int index)
 {
     uint64_t rxdone = vnic.RxDone;
     rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
     rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
-    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
+    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
     rxdone = set_RxDone_NotHigh(rxdone, rxLow);
     regs.RxData = vnic.RxData;
     regs.RxDone = rxdone;
     uint64_t txdone = vnic.TxDone;
     txdone = set_TxDone_Packets(txdone, txFifo.packets());
     txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
-    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
+    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
     regs.TxData = vnic.TxData;
     regs.TxDone = txdone;
     regs.TxWait = txdone;
+
+    int head = 0xffff;
+
+    if (!rxFifo.empty()) {
+        int vnic = rxFifo.begin()->priv;
+        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
+            head = vnic;
+    }
+
+    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
+    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
+    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
+    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
 }
 
 void
         vnic.rxUnique = rxUnique++;
         vnic.RxDone = Regs::RxDone_Busy;
         vnic.RxData = pkt->get<uint64_t>();
+        rxBusyCount++;
 
         if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
             panic("vtophys not implemented in newmem");
-/*            Addr vaddr = Regs::get_RxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+            Addr vaddr = Regs::get_RxData_Addr(reg64);
             Addr paddr = vtophys(req->xc, vaddr);
             DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
                     "vaddr=%#x, paddr=%#x\n",
                     index, vnic.rxUnique, vaddr, paddr);
 
-            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);*/
+            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
+#endif
         } else {
             DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
                     index, vnic.rxUnique);
         }
 
-        if (vnic.rxPacket == rxFifo.end()) {
+        if (vnic.rxIndex == rxFifo.end()) {
             DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
             rxList.push_back(index);
         } else {
 
         if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
             panic("vtophys won't work here in newmem.\n");
-            /*Addr vaddr = Regs::get_TxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+            Addr vaddr = Regs::get_TxData_Addr(reg64);
             Addr paddr = vtophys(req->xc, vaddr);
-            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
                     "vaddr=%#x, paddr=%#x\n",
                     index, vnic.txUnique, vaddr, paddr);
 
-            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
+#endif
         } else {
-            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
                     index, vnic.txUnique);
         }
 
     regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
     regs.RxMaxCopy = params()->rx_max_copy;
     regs.TxMaxCopy = params()->tx_max_copy;
-    regs.RxMaxIntr = params()->rx_max_intr;
+    regs.ZeroCopySize = params()->zero_copy_size;
+    regs.ZeroCopyMark = params()->zero_copy_threshold;
     regs.VirtualCount = params()->virtual_count;
+    regs.RxMaxIntr = params()->rx_max_intr;
     regs.RxFifoSize = params()->rx_fifo_size;
     regs.TxFifoSize = params()->tx_fifo_size;
-    regs.RxFifoMark = params()->rx_fifo_threshold;
-    regs.TxFifoMark = params()->tx_fifo_threshold;
+    regs.RxFifoLow = params()->rx_fifo_low_mark;
+    regs.TxFifoLow = params()->tx_fifo_threshold;
+    regs.RxFifoHigh = params()->rx_fifo_threshold;
+    regs.TxFifoHigh = params()->tx_fifo_high_mark;
     regs.HwAddr = params()->hardware_address;
 
+    if (regs.RxMaxCopy < regs.ZeroCopyMark)
+        panic("Must be able to copy at least as many bytes as the threshold");
+
+    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
+        panic("The number of bytes to copy must be less than the threshold");
+
     rxList.clear();
     rxBusy.clear();
     rxActive = -1;
     txList.clear();
+    rxBusyCount = 0;
+    rxDirtyCount = 0;
+    rxMappedCount = 0;
 
     rxState = rxIdle;
     txState = txIdle;
     virtualRegs.clear();
     virtualRegs.resize(size);
     for (int i = 0; i < size; ++i)
-        virtualRegs[i].rxPacket = rxFifo.end();
+        virtualRegs[i].rxIndex = rxFifo.end();
 }
 
 void
     }
 
   next:
+    rxFifo.check();
     if (rxState == rxIdle)
         goto exit;
 
             int size = virtualRegs.size();
             for (int i = 0; i < size; ++i) {
                 VirtualReg *vn = &virtualRegs[i];
-                if (vn->rxPacket != end &&
-                    !Regs::get_RxDone_Busy(vn->RxDone)) {
+                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
+                if (vn->rxIndex != end) {
+                    bool dirty = vn->rxPacketOffset > 0;
+                    const char *status;
+
+                    if (busy && dirty)
+                        status = "busy,dirty";
+                    else if (busy)
+                        status = "busy";
+                    else if (dirty)
+                        status = "dirty";
+                    else
+                        status = "mapped";
+
                     DPRINTF(EthernetSM,
-                            "vnic %d (rxunique %d), has outstanding packet %d\n",
-                            i, vn->rxUnique,
-                            rxFifo.countPacketsBefore(vn->rxPacket));
+                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
+                            i, status, vn->rxUnique,
+                            rxFifo.countPacketsBefore(vn->rxIndex),
+                            vn->rxIndex->slack);
+                } else if (busy) {
+                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
+                            i, vn->rxUnique);
                 }
             }
         }
             rxBusy.pop_front();
             vnic = &virtualRegs[rxActive];
 
-            if (vnic->rxPacket == rxFifo.end())
+            if (vnic->rxIndex == rxFifo.end())
                 panic("continuing vnic without packet\n");
 
             DPRINTF(EthernetSM,
 
             rxState = rxBeginCopy;
 
+            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
+            totalVnicDistance += vnic_distance;
+            numVnicDistance += 1;
+            if (vnic_distance > _maxVnicDistance) {
+                maxVnicDistance = vnic_distance;
+                _maxVnicDistance = vnic_distance;
+            }
+
             break;
         }
 
                 rxActive, vnic->rxUnique);
 
         // Grab a new packet from the fifo.
-        vnic->rxPacket = rxFifoPtr++;
+        vnic->rxIndex = rxFifoPtr++;
+        vnic->rxIndex->priv = rxActive;
         vnic->rxPacketOffset = 0;
-        vnic->rxPacketBytes = vnic->rxPacket->packet->length;
+        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
         assert(vnic->rxPacketBytes);
+        rxMappedCount++;
 
         vnic->rxDoneData = 0;
         /* scope for variables */ {
-            IpPtr ip(vnic->rxPacket->packet);
+            IpPtr ip(vnic->rxIndex->packet);
             if (ip) {
                 DPRINTF(Ethernet, "ID is %d\n", ip->id());
                 vnic->rxDoneData |= Regs::RxDone_IpPacket;
 
         rxDmaAddr = params()->platform->pciToDma(
                 Regs::get_RxData_Addr(vnic->RxData));
-        rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
+        rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
                             vnic->rxPacketBytes);
-        rxDmaData = vnic->rxPacket->packet->data + vnic->rxPacketOffset;
+
+        /*
+         * if we're doing zero/delay copy and we're below the fifo
+         * threshold, see if we should try to do the zero/defer copy
+         */
+        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
+             Regs::get_Config_DelayCopy(regs.Config)) &&
+            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
+            if (rxDmaLen > regs.ZeroCopyMark)
+                rxDmaLen = regs.ZeroCopySize;
+        }
+        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
         rxState = rxCopy;
         if (rxDmaAddr == 1LL) {
             rxState = rxCopyDone;
             break;
         }
 
-
         dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
         break;
 
       case rxCopyDone:
         vnic->RxDone = vnic->rxDoneData;
         vnic->RxDone |= Regs::RxDone_Complete;
+        rxBusyCount--;
 
         if (vnic->rxPacketBytes == rxDmaLen) {
+            if (vnic->rxPacketOffset)
+                rxDirtyCount--;
+
             // Packet is complete.  Indicate how many bytes were copied
             vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
 
             DPRINTF(EthernetSM,
                     "rxKick: packet complete on vnic %d (rxunique %d)\n",
                     rxActive, vnic->rxUnique);
-            rxFifo.remove(vnic->rxPacket);
-            vnic->rxPacket = rxFifo.end();
+            rxFifo.remove(vnic->rxIndex);
+            vnic->rxIndex = rxFifo.end();
+            rxMappedCount--;
         } else {
+            if (!vnic->rxPacketOffset)
+                rxDirtyCount++;
+
             vnic->rxPacketBytes -= rxDmaLen;
             vnic->rxPacketOffset += rxDmaLen;
             vnic->RxDone |= Regs::RxDone_More;
             rxEmpty = true;
         }
 
-        if (rxFifo.size() < params()->rx_fifo_low_mark)
+        if (rxFifo.size() < regs.RxFifoLow)
             rxLow = true;
 
-        if (rxFifo.size() > params()->rx_fifo_threshold)
+        if (rxFifo.size() > regs.RxFifoHigh)
             rxLow = false;
 
         devIntrPost(Regs::Intr_RxDMA);
     if (!interface->sendPacket(packet)) {
         DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
                 txFifo.avail());
-        goto reschedule;
+        return;
     }
 
     txFifo.pop();
             txFifo.avail());
 
     interrupts = Regs::Intr_TxPacket;
-    if (txFifo.size() < regs.TxFifoMark)
+    if (txFifo.size() < regs.TxFifoLow)
         interrupts |= Regs::Intr_TxLow;
     devIntrPost(interrupts);
-
-  reschedule:
-   if (!txFifo.empty() && !txEvent.scheduled()) {
-       DPRINTF(Ethernet, "reschedule transmit\n");
-       txEvent.schedule(curTick + retryTime);
-   }
 }
 
 void
         return true;
     }
 
-    if (rxFifo.size() >= regs.RxFifoMark)
+    if (rxFifo.size() >= regs.RxFifoHigh)
         devIntrPost(Regs::Intr_RxHigh);
 
     if (!rxFifo.push(packet)) {
               TxStateStrings[txState]);
 
     /*
-     * Serialize the device registers
+     * Serialize the device registers that could be modified by the OS.
      */
     SERIALIZE_SCALAR(regs.Config);
     SERIALIZE_SCALAR(regs.IntrStatus);
     SERIALIZE_SCALAR(regs.IntrMask);
-    SERIALIZE_SCALAR(regs.RxMaxCopy);
-    SERIALIZE_SCALAR(regs.TxMaxCopy);
-    SERIALIZE_SCALAR(regs.RxMaxIntr);
-    SERIALIZE_SCALAR(regs.VirtualCount);
     SERIALIZE_SCALAR(regs.RxData);
-    SERIALIZE_SCALAR(regs.RxDone);
     SERIALIZE_SCALAR(regs.TxData);
-    SERIALIZE_SCALAR(regs.TxDone);
 
     /*
      * Serialize the virtual nic state
         paramOut(os, reg + ".TxData", vnic->TxData);
         paramOut(os, reg + ".TxDone", vnic->TxDone);
 
-        bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
         paramOut(os, reg + ".rxPacketExists", rxPacketExists);
         if (rxPacketExists) {
             int rxPacket = 0;
             PacketFifo::iterator i = rxFifo.begin();
-            while (i != vnic->rxPacket) {
+            while (i != vnic->rxIndex) {
                 assert(i != rxFifo.end());
                 ++i;
                 ++rxPacket;
         paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
     }
 
-    int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+    int rxFifoPtr = -1;
+    if (this->rxFifoPtr != rxFifo.end())
+        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
     SERIALIZE_SCALAR(rxFifoPtr);
 
     SERIALIZE_SCALAR(rxActive);
+    SERIALIZE_SCALAR(rxBusyCount);
+    SERIALIZE_SCALAR(rxDirtyCount);
+    SERIALIZE_SCALAR(rxMappedCount);
 
     VirtualList::iterator i, end;
     for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
     Base::unserialize(cp, section);
 
     /*
-     * Unserialize the device registers
+     * Unserialize the device registers that may have been written by the OS.
      */
     UNSERIALIZE_SCALAR(regs.Config);
     UNSERIALIZE_SCALAR(regs.IntrStatus);
     UNSERIALIZE_SCALAR(regs.IntrMask);
-    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
-    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
-    UNSERIALIZE_SCALAR(regs.RxMaxIntr);
-    UNSERIALIZE_SCALAR(regs.VirtualCount);
     UNSERIALIZE_SCALAR(regs.RxData);
-    UNSERIALIZE_SCALAR(regs.RxDone);
     UNSERIALIZE_SCALAR(regs.TxData);
-    UNSERIALIZE_SCALAR(regs.TxDone);
 
     UNSERIALIZE_SCALAR(rxActive);
+    UNSERIALIZE_SCALAR(rxBusyCount);
+    UNSERIALIZE_SCALAR(rxDirtyCount);
+    UNSERIALIZE_SCALAR(rxMappedCount);
 
     int rxListSize;
     UNSERIALIZE_SCALAR(rxListSize);
 
     int rxFifoPtr;
     UNSERIALIZE_SCALAR(rxFifoPtr);
-    this->rxFifoPtr = rxFifo.begin();
-    for (int i = 0; i < rxFifoPtr; ++i)
-        ++this->rxFifoPtr;
+    if (rxFifoPtr >= 0) {
+        this->rxFifoPtr = rxFifo.begin();
+        for (int i = 0; i < rxFifoPtr; ++i)
+            ++this->rxFifoPtr;
+    } else {
+        this->rxFifoPtr = rxFifo.end();
+    }
 
     /*
      * Unserialize tx state machine
         if (rxPacketExists) {
             int rxPacket;
             paramIn(cp, section, reg + ".rxPacket", rxPacket);
-            vnic->rxPacket = rxFifo.begin();
+            vnic->rxIndex = rxFifo.begin();
             while (rxPacket--)
-                ++vnic->rxPacket;
+                ++vnic->rxIndex;
 
             paramIn(cp, section, reg + ".rxPacketOffset",
                     vnic->rxPacketOffset);
             paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
         } else {
-            vnic->rxPacket = rxFifo.end();
+            vnic->rxIndex = rxFifo.end();
         }
         paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
     }
 
 __SINIC_REG32(IntrMask,      0x0c); // 32: interrupt mask
 __SINIC_REG32(RxMaxCopy,     0x10); // 32: max bytes per rx copy
 __SINIC_REG32(TxMaxCopy,     0x14); // 32: max bytes per tx copy
-__SINIC_REG32(RxMaxIntr,     0x18); // 32: max receives per interrupt
-__SINIC_REG32(VirtualCount,  0x1c); // 32: number of virutal NICs
-__SINIC_REG32(RxFifoSize,    0x20); // 32: rx fifo capacity in bytes
-__SINIC_REG32(TxFifoSize,    0x24); // 32: tx fifo capacity in bytes
-__SINIC_REG32(RxFifoMark,    0x28); // 32: rx fifo high watermark
-__SINIC_REG32(TxFifoMark,    0x2c); // 32: tx fifo low watermark
-__SINIC_REG32(RxData,        0x30); // 64: receive data
-__SINIC_REG32(RxDone,        0x38); // 64: receive done
-__SINIC_REG32(RxWait,        0x40); // 64: receive done (busy wait)
-__SINIC_REG32(TxData,        0x48); // 64: transmit data
-__SINIC_REG32(TxDone,        0x50); // 64: transmit done
-__SINIC_REG32(TxWait,        0x58); // 64: transmit done (busy wait)
-__SINIC_REG32(HwAddr,        0x60); // 64: mac address
-__SINIC_REG32(Size,          0x68); // register addres space size
+__SINIC_REG32(ZeroCopySize,  0x18); // 32: bytes to copy if below threshold
+__SINIC_REG32(ZeroCopyMark,  0x1c); // 32: only zero-copy above this threshold
+__SINIC_REG32(VirtualCount,  0x20); // 32: number of virutal NICs
+__SINIC_REG32(RxMaxIntr,     0x24); // 32: max receives per interrupt
+__SINIC_REG32(RxFifoSize,    0x28); // 32: rx fifo capacity in bytes
+__SINIC_REG32(TxFifoSize,    0x2c); // 32: tx fifo capacity in bytes
+__SINIC_REG32(RxFifoLow,     0x30); // 32: rx fifo low watermark
+__SINIC_REG32(TxFifoLow,     0x34); // 32: tx fifo low watermark
+__SINIC_REG32(RxFifoHigh,    0x38); // 32: rx fifo high watermark
+__SINIC_REG32(TxFifoHigh,    0x3c); // 32: tx fifo high watermark
+__SINIC_REG32(RxData,        0x40); // 64: receive data
+__SINIC_REG32(RxDone,        0x48); // 64: receive done
+__SINIC_REG32(RxWait,        0x50); // 64: receive done (busy wait)
+__SINIC_REG32(TxData,        0x58); // 64: transmit data
+__SINIC_REG32(TxDone,        0x60); // 64: transmit done
+__SINIC_REG32(TxWait,        0x68); // 64: transmit done (busy wait)
+__SINIC_REG32(HwAddr,        0x70); // 64: mac address
+__SINIC_REG32(RxStatus,      0x78);
+__SINIC_REG32(Size,          0x80); // register addres space size
 
 // Config register bits
 __SINIC_VAL32(Config_ZeroCopy, 12, 1); // enable zero copy
 __SINIC_REG32(Intr_Res,      ~0x01ff); // reserved interrupt bits
 
 // RX Data Description
-__SINIC_VAL64(RxData_Vaddr, 60,  1); // Addr is virtual
-__SINIC_VAL64(RxData_Len,   40, 20); // 0 - 256k
-__SINIC_VAL64(RxData_Addr,   0, 40); // Address 1TB
+__SINIC_VAL64(RxData_NoDelay,  61,  1); // Don't Delay this copy
+__SINIC_VAL64(RxData_Vaddr,    60,  1); // Addr is virtual
+__SINIC_VAL64(RxData_Len,      40, 20); // 0 - 256k
+__SINIC_VAL64(RxData_Addr,      0, 40); // Address 1TB
 
 // TX Data Description
 __SINIC_VAL64(TxData_More,     63,  1); // Packet not complete (will dma more)
 __SINIC_VAL64(TxDone_Res7,      20,  1); // reserved
 __SINIC_VAL64(TxDone_CopyLen,    0, 20); // up to 256k
 
+__SINIC_VAL64(RxStatus_Dirty,   48, 16);
+__SINIC_VAL64(RxStatus_Mapped,  32, 16);
+__SINIC_VAL64(RxStatus_Busy,    16, 16);
+__SINIC_VAL64(RxStatus_Head,     0, 16);
+
 struct Info
 {
     uint8_t size;
 {
     static Regs::Info invalid = { 0, false, false, "invalid" };
     static Regs::Info info [] = {
-        { 4, true,  true,  "Config"     },
-        { 4, false, true,  "Command"    },
-        { 4, true,  true,  "IntrStatus" },
-        { 4, true,  true,  "IntrMask"   },
-        { 4, true,  false, "RxMaxCopy"  },
-        { 4, true,  false, "TxMaxCopy"  },
-        { 4, true,  false, "RxMaxIntr"  },
-        { 4, true,  false, "VirtualCount"  },
-        { 4, true,  false, "RxFifoSize" },
-        { 4, true,  false, "TxFifoSize" },
-        { 4, true,  false, "RxFifoMark" },
-        { 4, true,  false, "TxFifoMark" },
-        { 8, true,  true,  "RxData"     },
+        { 4, true,  true,  "Config"       },
+        { 4, false, true,  "Command"      },
+        { 4, true,  true,  "IntrStatus"   },
+        { 4, true,  true,  "IntrMask"     },
+        { 4, true,  false, "RxMaxCopy"    },
+        { 4, true,  false, "TxMaxCopy"    },
+        { 4, true,  false, "ZeroCopySize" },
+        { 4, true,  false, "ZeroCopyMark" },
+        { 4, true,  false, "VirtualCount" },
+        { 4, true,  false, "RxMaxIntr"    },
+        { 4, true,  false, "RxFifoSize"   },
+        { 4, true,  false, "TxFifoSize"   },
+        { 4, true,  false, "RxFifoLow"    },
+        { 4, true,  false, "TxFifoLow"    },
+        { 4, true,  false, "RxFifoHigh"   },
+        { 4, true,  false, "TxFifoHigh"   },
+        { 8, true,  true,  "RxData"       },
+        invalid,
+        { 8, true,  false, "RxDone"       },
         invalid,
-        { 8, true,  false, "RxDone"     },
+        { 8, true,  false, "RxWait"       },
         invalid,
-        { 8, true,  false, "RxWait"     },
+        { 8, true,  true,  "TxData"       },
         invalid,
-        { 8, true,  true,  "TxData"     },
+        { 8, true,  false, "TxDone"       },
         invalid,
-        { 8, true,  false, "TxDone"     },
+        { 8, true,  false, "TxWait"       },
         invalid,
-        { 8, true,  false, "TxWait"     },
+        { 8, true,  false, "HwAddr"       },
         invalid,
-        { 8, true,  false, "HwAddr"     },
+        { 8, true,  false, "RxStatus"     },
         invalid,
     };