dev: Move network devices to src/dev/net/
authorAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 10 Dec 2015 10:35:18 +0000 (10:35 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Thu, 10 Dec 2015 10:35:18 +0000 (10:35 +0000)
--HG--
rename : src/dev/Ethernet.py => src/dev/net/Ethernet.py
rename : src/dev/etherbus.cc => src/dev/net/etherbus.cc
rename : src/dev/etherbus.hh => src/dev/net/etherbus.hh
rename : src/dev/etherdevice.cc => src/dev/net/etherdevice.cc
rename : src/dev/etherdevice.hh => src/dev/net/etherdevice.hh
rename : src/dev/etherdump.cc => src/dev/net/etherdump.cc
rename : src/dev/etherdump.hh => src/dev/net/etherdump.hh
rename : src/dev/etherint.cc => src/dev/net/etherint.cc
rename : src/dev/etherint.hh => src/dev/net/etherint.hh
rename : src/dev/etherlink.cc => src/dev/net/etherlink.cc
rename : src/dev/etherlink.hh => src/dev/net/etherlink.hh
rename : src/dev/etherobject.hh => src/dev/net/etherobject.hh
rename : src/dev/etherpkt.cc => src/dev/net/etherpkt.cc
rename : src/dev/etherpkt.hh => src/dev/net/etherpkt.hh
rename : src/dev/ethertap.cc => src/dev/net/ethertap.cc
rename : src/dev/ethertap.hh => src/dev/net/ethertap.hh
rename : src/dev/i8254xGBe.cc => src/dev/net/i8254xGBe.cc
rename : src/dev/i8254xGBe.hh => src/dev/net/i8254xGBe.hh
rename : src/dev/i8254xGBe_defs.hh => src/dev/net/i8254xGBe_defs.hh
rename : src/dev/multi_etherlink.cc => src/dev/net/multi_etherlink.cc
rename : src/dev/multi_etherlink.hh => src/dev/net/multi_etherlink.hh
rename : src/dev/multi_iface.cc => src/dev/net/multi_iface.cc
rename : src/dev/multi_iface.hh => src/dev/net/multi_iface.hh
rename : src/dev/multi_packet.cc => src/dev/net/multi_packet.cc
rename : src/dev/multi_packet.hh => src/dev/net/multi_packet.hh
rename : src/dev/ns_gige.cc => src/dev/net/ns_gige.cc
rename : src/dev/ns_gige.hh => src/dev/net/ns_gige.hh
rename : src/dev/ns_gige_reg.h => src/dev/net/ns_gige_reg.h
rename : src/dev/pktfifo.cc => src/dev/net/pktfifo.cc
rename : src/dev/pktfifo.hh => src/dev/net/pktfifo.hh
rename : src/dev/sinic.cc => src/dev/net/sinic.cc
rename : src/dev/sinic.hh => src/dev/net/sinic.hh
rename : src/dev/sinicreg.hh => src/dev/net/sinicreg.hh
rename : src/dev/tcp_iface.cc => src/dev/net/tcp_iface.cc
rename : src/dev/tcp_iface.hh => src/dev/net/tcp_iface.hh

75 files changed:
src/base/inet.hh
src/dev/Ethernet.py [deleted file]
src/dev/SConscript
src/dev/etherbus.cc [deleted file]
src/dev/etherbus.hh [deleted file]
src/dev/etherdevice.cc [deleted file]
src/dev/etherdevice.hh [deleted file]
src/dev/etherdump.cc [deleted file]
src/dev/etherdump.hh [deleted file]
src/dev/etherint.cc [deleted file]
src/dev/etherint.hh [deleted file]
src/dev/etherlink.cc [deleted file]
src/dev/etherlink.hh [deleted file]
src/dev/etherobject.hh [deleted file]
src/dev/etherpkt.cc [deleted file]
src/dev/etherpkt.hh [deleted file]
src/dev/ethertap.cc [deleted file]
src/dev/ethertap.hh [deleted file]
src/dev/i8254xGBe.cc [deleted file]
src/dev/i8254xGBe.hh [deleted file]
src/dev/i8254xGBe_defs.hh [deleted file]
src/dev/multi_etherlink.cc [deleted file]
src/dev/multi_etherlink.hh [deleted file]
src/dev/multi_iface.cc [deleted file]
src/dev/multi_iface.hh [deleted file]
src/dev/multi_packet.cc [deleted file]
src/dev/multi_packet.hh [deleted file]
src/dev/net/Ethernet.py [new file with mode: 0644]
src/dev/net/SConscript [new file with mode: 0644]
src/dev/net/etherbus.cc [new file with mode: 0644]
src/dev/net/etherbus.hh [new file with mode: 0644]
src/dev/net/etherdevice.cc [new file with mode: 0644]
src/dev/net/etherdevice.hh [new file with mode: 0644]
src/dev/net/etherdump.cc [new file with mode: 0644]
src/dev/net/etherdump.hh [new file with mode: 0644]
src/dev/net/etherint.cc [new file with mode: 0644]
src/dev/net/etherint.hh [new file with mode: 0644]
src/dev/net/etherlink.cc [new file with mode: 0644]
src/dev/net/etherlink.hh [new file with mode: 0644]
src/dev/net/etherobject.hh [new file with mode: 0644]
src/dev/net/etherpkt.cc [new file with mode: 0644]
src/dev/net/etherpkt.hh [new file with mode: 0644]
src/dev/net/ethertap.cc [new file with mode: 0644]
src/dev/net/ethertap.hh [new file with mode: 0644]
src/dev/net/i8254xGBe.cc [new file with mode: 0644]
src/dev/net/i8254xGBe.hh [new file with mode: 0644]
src/dev/net/i8254xGBe_defs.hh [new file with mode: 0644]
src/dev/net/multi_etherlink.cc [new file with mode: 0644]
src/dev/net/multi_etherlink.hh [new file with mode: 0644]
src/dev/net/multi_iface.cc [new file with mode: 0644]
src/dev/net/multi_iface.hh [new file with mode: 0644]
src/dev/net/multi_packet.cc [new file with mode: 0644]
src/dev/net/multi_packet.hh [new file with mode: 0644]
src/dev/net/ns_gige.cc [new file with mode: 0644]
src/dev/net/ns_gige.hh [new file with mode: 0644]
src/dev/net/ns_gige_reg.h [new file with mode: 0644]
src/dev/net/pktfifo.cc [new file with mode: 0644]
src/dev/net/pktfifo.hh [new file with mode: 0644]
src/dev/net/sinic.cc [new file with mode: 0644]
src/dev/net/sinic.hh [new file with mode: 0644]
src/dev/net/sinicreg.hh [new file with mode: 0644]
src/dev/net/tcp_iface.cc [new file with mode: 0644]
src/dev/net/tcp_iface.hh [new file with mode: 0644]
src/dev/ns_gige.cc [deleted file]
src/dev/ns_gige.hh [deleted file]
src/dev/ns_gige_reg.h [deleted file]
src/dev/pktfifo.cc [deleted file]
src/dev/pktfifo.hh [deleted file]
src/dev/sinic.cc [deleted file]
src/dev/sinic.hh [deleted file]
src/dev/sinicreg.hh [deleted file]
src/dev/tcp_iface.cc [deleted file]
src/dev/tcp_iface.hh [deleted file]
src/python/swig/pyobject.cc
src/python/swig/pyobject.hh

index 07bbdc3b4b868ea7c3eecf877fc5636d879bda63..d7e0039701263f09c1de16523bacfabe9ce1ea87 100644 (file)
@@ -53,7 +53,7 @@
 #include <vector>
 
 #include "base/types.hh"
-#include "dev/etherpkt.hh"
+#include "dev/net/etherpkt.hh"
 #include "dnet/os.h"
 #include "dnet/eth.h"
 #include "dnet/ip.h"
diff --git a/src/dev/Ethernet.py b/src/dev/Ethernet.py
deleted file mode 100644 (file)
index 89d1bad..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-# Copyright (c) 2015 ARM Limited
-# All rights reserved.
-#
-# The license below extends only to copyright in the software and shall
-# not be construed as granting a license to any other intellectual
-# property including but not limited to intellectual property relating
-# to a hardware implementation of the functionality of the software
-# licensed hereunder.  You may use the software subject to the license
-# terms below provided that you ensure that this notice is replicated
-# unmodified and in its entirety in all distributions of the software,
-# modified or unmodified, in source code or in binary form.
-#
-# Copyright (c) 2005-2007 The Regents of The University of Michigan
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are
-# met: redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer;
-# redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution;
-# neither the name of the copyright holders nor the names of its
-# contributors may be used to endorse or promote products derived from
-# this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-# Authors: Nathan Binkert
-
-from m5.SimObject import SimObject
-from m5.params import *
-from m5.proxy import *
-from PciDevice import PciDevice
-
-class EtherObject(SimObject):
-    type = 'EtherObject'
-    abstract = True
-    cxx_header = "dev/etherobject.hh"
-
-class EtherLink(EtherObject):
-    type = 'EtherLink'
-    cxx_header = "dev/etherlink.hh"
-    int0 = SlavePort("interface 0")
-    int1 = SlavePort("interface 1")
-    delay = Param.Latency('0us', "packet transmit delay")
-    delay_var = Param.Latency('0ns', "packet transmit delay variability")
-    speed = Param.NetworkBandwidth('1Gbps', "link speed")
-    dump = Param.EtherDump(NULL, "dump object")
-
-class MultiEtherLink(EtherObject):
-    type = 'MultiEtherLink'
-    cxx_header = "dev/multi_etherlink.hh"
-    int0 = SlavePort("interface 0")
-    delay = Param.Latency('0us', "packet transmit delay")
-    delay_var = Param.Latency('0ns', "packet transmit delay variability")
-    speed = Param.NetworkBandwidth('1Gbps', "link speed")
-    dump = Param.EtherDump(NULL, "dump object")
-    multi_rank  =  Param.UInt32('0', "Rank of the this gem5 process (multi run)")
-    sync_start  = Param.Latency('5200000000000t', "first multi sync barrier")
-    sync_repeat = Param.Latency('10us', "multi sync barrier repeat")
-    server_name = Param.String('localhost', "Message server name")
-    server_port = Param.UInt32('2200', "Message server port")
-
-class EtherBus(EtherObject):
-    type = 'EtherBus'
-    cxx_header = "dev/etherbus.hh"
-    loopback = Param.Bool(True, "send packet back to the sending interface")
-    dump = Param.EtherDump(NULL, "dump object")
-    speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second")
-
-class EtherTap(EtherObject):
-    type = 'EtherTap'
-    cxx_header = "dev/ethertap.hh"
-    bufsz = Param.Int(10000, "tap buffer size")
-    dump = Param.EtherDump(NULL, "dump object")
-    port = Param.UInt16(3500, "tap port")
-
-class EtherDump(SimObject):
-    type = 'EtherDump'
-    cxx_header = "dev/etherdump.hh"
-    file = Param.String("dump file")
-    maxlen = Param.Int(96, "max portion of packet data to dump")
-
-class EtherDevice(PciDevice):
-    type = 'EtherDevice'
-    abstract = True
-    cxx_header = "dev/etherdevice.hh"
-    interface = MasterPort("Ethernet Interface")
-
-class IGbE(EtherDevice):
-    # Base class for two IGbE adapters listed above
-    type = 'IGbE'
-    cxx_header = "dev/i8254xGBe.hh"
-    hardware_address = Param.EthernetAddr(NextEthernetAddr,
-        "Ethernet Hardware Address")
-    rx_fifo_size = Param.MemorySize('384kB', "Size of the rx FIFO")
-    tx_fifo_size = Param.MemorySize('384kB', "Size of the tx FIFO")
-    rx_desc_cache_size = Param.Int(64,
-        "Number of enteries in the rx descriptor cache")
-    tx_desc_cache_size = Param.Int(64,
-        "Number of enteries in the rx descriptor cache")
-    VendorID = 0x8086
-    SubsystemID = 0x1008
-    SubsystemVendorID = 0x8086
-    Status = 0x0000
-    SubClassCode = 0x00
-    ClassCode = 0x02
-    ProgIF = 0x00
-    BAR0 = 0x00000000
-    BAR1 = 0x00000000
-    BAR2 = 0x00000000
-    BAR3 = 0x00000000
-    BAR4 = 0x00000000
-    BAR5 = 0x00000000
-    MaximumLatency = 0x00
-    MinimumGrant = 0xff
-    InterruptLine = 0x1e
-    InterruptPin = 0x01
-    BAR0Size = '128kB'
-    wb_delay = Param.Latency('10ns', "delay before desc writeback occurs")
-    fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs")
-    fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs")
-    wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs")
-    tx_read_delay = Param.Latency('0ns', "delay after tx dma read")
-    rx_write_delay = Param.Latency('0ns', "delay after rx dma read")
-    phy_pid = Param.UInt16("Phy PID that corresponds to device ID")
-    phy_epid = Param.UInt16("Phy EPID that corresponds to device ID")
-
-class IGbE_e1000(IGbE):
-    # Older Intel 8254x based gigabit ethernet adapter
-    # Uses Intel e1000 driver
-    DeviceID = 0x1075
-    phy_pid = 0x02A8
-    phy_epid = 0x0380
-
-class IGbE_igb(IGbE):
-    # Newer Intel 8257x based gigabit ethernet adapter
-    # Uses Intel igb driver and in theory supports packet splitting and LRO
-    DeviceID = 0x10C9
-    phy_pid = 0x0141
-    phy_epid = 0x0CC0
-
-class EtherDevBase(EtherDevice):
-    type = 'EtherDevBase'
-    abstract = True
-    cxx_header = "dev/etherdevice.hh"
-
-    hardware_address = Param.EthernetAddr(NextEthernetAddr,
-        "Ethernet Hardware Address")
-
-    dma_read_delay = Param.Latency('0us', "fixed delay for dma reads")
-    dma_read_factor = Param.Latency('0us', "multiplier for dma reads")
-    dma_write_delay = Param.Latency('0us', "fixed delay for dma writes")
-    dma_write_factor = Param.Latency('0us', "multiplier for dma writes")
-
-    rx_delay = Param.Latency('1us', "Receive Delay")
-    tx_delay = Param.Latency('1us', "Transmit Delay")
-    rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo")
-    tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo")
-
-    rx_filter = Param.Bool(True, "Enable Receive Filter")
-    intr_delay = Param.Latency('10us', "Interrupt propagation delay")
-    rx_thread = Param.Bool(False, "dedicated kernel thread for transmit")
-    tx_thread = Param.Bool(False, "dedicated kernel threads for receive")
-    rss = Param.Bool(False, "Receive Side Scaling")
-
-class NSGigE(EtherDevBase):
-    type = 'NSGigE'
-    cxx_header = "dev/ns_gige.hh"
-
-    dma_data_free = Param.Bool(False, "DMA of Data is free")
-    dma_desc_free = Param.Bool(False, "DMA of Descriptors is free")
-    dma_no_allocate = Param.Bool(True, "Should we allocate cache on read")
-
-    VendorID = 0x100B
-    DeviceID = 0x0022
-    Status = 0x0290
-    SubClassCode = 0x00
-    ClassCode = 0x02
-    ProgIF = 0x00
-    BAR0 = 0x00000001
-    BAR1 = 0x00000000
-    BAR2 = 0x00000000
-    BAR3 = 0x00000000
-    BAR4 = 0x00000000
-    BAR5 = 0x00000000
-    MaximumLatency = 0x34
-    MinimumGrant = 0xb0
-    InterruptLine = 0x1e
-    InterruptPin = 0x01
-    BAR0Size = '256B'
-    BAR1Size = '4kB'
-
-
-
-class Sinic(EtherDevBase):
-    type = 'Sinic'
-    cxx_class = 'Sinic::Device'
-    cxx_header = "dev/sinic.hh"
-
-    rx_max_copy = Param.MemorySize('1514B', "rx max copy")
-    tx_max_copy = Param.MemorySize('16kB', "tx max copy")
-    rx_max_intr = Param.UInt32(10, "max rx packets per interrupt")
-    rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold")
-    rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold")
-    tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold")
-    tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold")
-    virtual_count = Param.UInt32(1, "Virtualized SINIC")
-    zero_copy_size = Param.UInt32(64, "Bytes to copy if below threshold")
-    zero_copy_threshold = Param.UInt32(256,
-        "Only zero copy above this threshold")
-    zero_copy = Param.Bool(False, "Zero copy receive")
-    delay_copy = Param.Bool(False, "Delayed copy transmit")
-    virtual_addr = Param.Bool(False, "Virtual addressing")
-
-    VendorID = 0x1291
-    DeviceID = 0x1293
-    Status = 0x0290
-    SubClassCode = 0x00
-    ClassCode = 0x02
-    ProgIF = 0x00
-    BAR0 = 0x00000000
-    BAR1 = 0x00000000
-    BAR2 = 0x00000000
-    BAR3 = 0x00000000
-    BAR4 = 0x00000000
-    BAR5 = 0x00000000
-    MaximumLatency = 0x34
-    MinimumGrant = 0xb0
-    InterruptLine = 0x1e
-    InterruptPin = 0x01
-    BAR0Size = '64kB'
-
-
index 4bacb3e3f9fe9d6c2bac68430ea56f9499d94126..85bf839ec48dbfdef800b59bf895b9708f26eeda 100644 (file)
@@ -41,7 +41,6 @@ if env['TARGET_ISA'] == 'null':
 
 SimObject('BadDevice.py')
 SimObject('DiskImage.py')
-SimObject('Ethernet.py')
 SimObject('Ide.py')
 SimObject('Platform.py')
 SimObject('SimpleDisk.py')
@@ -51,29 +50,14 @@ SimObject('Uart.py')
 Source('baddev.cc')
 Source('disk_image.cc')
 Source('dma_device.cc')
-Source('etherbus.cc')
-Source('etherdevice.cc')
-Source('etherdump.cc')
-Source('etherint.cc')
-Source('etherlink.cc')
-Source('multi_packet.cc')
-Source('multi_iface.cc')
-Source('multi_etherlink.cc')
-Source('tcp_iface.cc')
-Source('etherpkt.cc')
-Source('ethertap.cc')
-Source('i8254xGBe.cc')
 Source('ide_ctrl.cc')
 Source('ide_disk.cc')
 Source('intel_8254_timer.cc')
 Source('mc146818.cc')
-Source('ns_gige.cc')
 Source('pixelpump.cc')
-Source('pktfifo.cc')
 Source('platform.cc')
 Source('ps2.cc')
 Source('simple_disk.cc')
-Source('sinic.cc')
 Source('terminal.cc')
 Source('uart.cc')
 Source('uart8250.cc')
@@ -81,17 +65,6 @@ Source('uart8250.cc')
 DebugFlag('DiskImageRead')
 DebugFlag('DiskImageWrite')
 DebugFlag('DMA')
-DebugFlag('Ethernet')
-DebugFlag('MultiEthernet')
-DebugFlag('MultiEthernetPkt')
-DebugFlag('EthernetCksum')
-DebugFlag('EthernetDMA')
-DebugFlag('EthernetData')
-DebugFlag('EthernetDesc')
-DebugFlag('EthernetEEPROM')
-DebugFlag('EthernetIntr')
-DebugFlag('EthernetPIO')
-DebugFlag('EthernetSM')
 DebugFlag('IdeCtrl')
 DebugFlag('IdeDisk')
 DebugFlag('Intel8254Timer')
@@ -103,9 +76,4 @@ DebugFlag('TerminalVerbose')
 DebugFlag('Uart')
 
 CompoundFlag('DiskImageAll', [ 'DiskImageRead', 'DiskImageWrite' ])
-CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
-    'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
-    'EthernetCksum', 'EthernetEEPROM' ])
-CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
-    'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
 CompoundFlag('IdeAll', [ 'IdeCtrl', 'IdeDisk' ])
diff --git a/src/dev/etherbus.cc b/src/dev/etherbus.cc
deleted file mode 100644 (file)
index c9e9c93..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Device module for modelling an ethernet hub
- */
-
-#include <cmath>
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/trace.hh"
-#include "debug/Ethernet.hh"
-#include "debug/EthernetData.hh"
-#include "dev/etherbus.hh"
-#include "dev/etherdump.hh"
-#include "dev/etherint.hh"
-#include "dev/etherpkt.hh"
-#include "params/EtherBus.hh"
-#include "sim/core.hh"
-
-using namespace std;
-
-EtherBus::EtherBus(const Params *p)
-    : EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback),
-      event(this), sender(0), dump(p->dump)
-{
-}
-
-void
-EtherBus::txDone()
-{
-    devlist_t::iterator i = devlist.begin();
-    devlist_t::iterator end = devlist.end();
-
-    DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length);
-    DDUMP(EthernetData, packet->data, packet->length);
-
-    while (i != end) {
-        if (loopback || *i != sender)
-            (*i)->sendPacket(packet);
-        ++i;
-    }
-
-    sender->sendDone();
-
-    if (dump)
-        dump->dump(packet);
-
-    sender = 0;
-    packet = 0;
-}
-
-EtherInt*
-EtherBus::getEthPort(const std::string &if_name, int idx)
-{
-    panic("Etherbus doesn't work\n");
-}
-
-bool
-EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
-{
-    if (busy()) {
-        DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick());
-        return false;
-    }
-
-    DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length);
-    DDUMP(EthernetData, pkt->data, pkt->length);
-
-    packet = pkt;
-    sender = sndr;
-    int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0);
-    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
-            delay, ticksPerByte);
-    schedule(event, curTick() + delay);
-
-    return true;
-}
-
-EtherBus *
-EtherBusParams::create()
-{
-    return new EtherBus(this);
-}
diff --git a/src/dev/etherbus.hh b/src/dev/etherbus.hh
deleted file mode 100644 (file)
index 43978b9..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Device module for modelling an ethernet hub
- */
-
-#ifndef __ETHERBUS_H__
-#define __ETHERBUS_H__
-
-#include "dev/etherobject.hh"
-#include "dev/etherpkt.hh"
-#include "params/EtherBus.hh"
-#include "sim/eventq.hh"
-#include "sim/sim_object.hh"
-
-class EtherDump;
-class EtherInt;
-class EtherBus : public EtherObject
-{
-  protected:
-    typedef std::list<EtherInt *> devlist_t;
-    devlist_t devlist;
-    double ticksPerByte;
-    bool loopback;
-
-  protected:
-    class DoneEvent : public Event
-    {
-      protected:
-        EtherBus *bus;
-
-      public:
-        DoneEvent(EtherBus *b) : bus(b) {}
-        virtual void process() { bus->txDone(); }
-        virtual const char *description() const
-            { return "ethernet bus completion"; }
-    };
-
-    DoneEvent event;
-    EthPacketPtr packet;
-    EtherInt *sender;
-    EtherDump *dump;
-
-  public:
-    typedef EtherBusParams Params;
-    EtherBus(const Params *p);
-    virtual ~EtherBus() {}
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    void txDone();
-    void reg(EtherInt *dev);
-    bool busy() const { return (bool)packet; }
-    bool send(EtherInt *sender, EthPacketPtr &packet);
-    virtual EtherInt *getEthPort(const std::string &if_name, int idx);
-};
-
-#endif // __ETHERBUS_H__
diff --git a/src/dev/etherdevice.cc b/src/dev/etherdevice.cc
deleted file mode 100644 (file)
index 59febcd..0000000
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- *          Lisa Hsu
- */
-
-#include "dev/etherdevice.hh"
-#include "sim/stats.hh"
-
-void
-EtherDevice::regStats()
-{
-    txBytes
-        .name(name() + ".txBytes")
-        .desc("Bytes Transmitted")
-        .prereq(txBytes)
-        ;
-
-    rxBytes
-        .name(name() + ".rxBytes")
-        .desc("Bytes Received")
-        .prereq(rxBytes)
-        ;
-
-    txPackets
-        .name(name() + ".txPackets")
-        .desc("Number of Packets Transmitted")
-        .prereq(txBytes)
-        ;
-
-    rxPackets
-        .name(name() + ".rxPackets")
-        .desc("Number of Packets Received")
-        .prereq(rxBytes)
-        ;
-
-    txIpChecksums
-        .name(name() + ".txIpChecksums")
-        .desc("Number of tx IP Checksums done by device")
-        .precision(0)
-        .prereq(txBytes)
-        ;
-
-    rxIpChecksums
-        .name(name() + ".rxIpChecksums")
-        .desc("Number of rx IP Checksums done by device")
-        .precision(0)
-        .prereq(rxBytes)
-        ;
-
-    txTcpChecksums
-        .name(name() + ".txTcpChecksums")
-        .desc("Number of tx TCP Checksums done by device")
-        .precision(0)
-        .prereq(txBytes)
-        ;
-
-    rxTcpChecksums
-        .name(name() + ".rxTcpChecksums")
-        .desc("Number of rx TCP Checksums done by device")
-        .precision(0)
-        .prereq(rxBytes)
-        ;
-
-    txUdpChecksums
-        .name(name() + ".txUdpChecksums")
-        .desc("Number of tx UDP Checksums done by device")
-        .precision(0)
-        .prereq(txBytes)
-        ;
-
-    rxUdpChecksums
-        .name(name() + ".rxUdpChecksums")
-        .desc("Number of rx UDP Checksums done by device")
-        .precision(0)
-        .prereq(rxBytes)
-        ;
-
-    descDmaReads
-        .name(name() + ".descDMAReads")
-        .desc("Number of descriptors the device read w/ DMA")
-        .precision(0)
-        ;
-
-    descDmaWrites
-        .name(name() + ".descDMAWrites")
-        .desc("Number of descriptors the device wrote w/ DMA")
-        .precision(0)
-        ;
-
-    descDmaRdBytes
-        .name(name() + ".descDmaReadBytes")
-        .desc("number of descriptor bytes read w/ DMA")
-        .precision(0)
-        ;
-
-    descDmaWrBytes
-        .name(name() + ".descDmaWriteBytes")
-        .desc("number of descriptor bytes write w/ DMA")
-        .precision(0)
-        ;
-
-    txBandwidth
-        .name(name() + ".txBandwidth")
-        .desc("Transmit Bandwidth (bits/s)")
-        .precision(0)
-        .prereq(txBytes)
-        ;
-
-    rxBandwidth
-        .name(name() + ".rxBandwidth")
-        .desc("Receive Bandwidth (bits/s)")
-        .precision(0)
-        .prereq(rxBytes)
-        ;
-
-    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)")
-        .precision(0)
-        .prereq(txBytes)
-        ;
-
-    rxPacketRate
-        .name(name() + ".rxPPS")
-        .desc("Packet Reception Rate (packets/s)")
-        .precision(0)
-        .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;
-    totPacketRate = totPackets / simSeconds;
-}
diff --git a/src/dev/etherdevice.hh b/src/dev/etherdevice.hh
deleted file mode 100644 (file)
index 45df2a2..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2007 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/**
- * @file
- * Base Ethernet Device declaration.
- */
-
-#ifndef __DEV_ETHERDEVICE_HH__
-#define __DEV_ETHERDEVICE_HH__
-
-#include "base/statistics.hh"
-#include "dev/pci/device.hh"
-#include "params/EtherDevice.hh"
-#include "params/EtherDevBase.hh"
-#include "sim/sim_object.hh"
-
-class EtherInt;
-
-/**
- * The base EtherObject class, allows for an accesor function to a
- * simobj that returns the Port.
- */
-class EtherDevice : public PciDevice
-{
-  public:
-    typedef EtherDeviceParams Params;
-    EtherDevice(const Params *params)
-        : PciDevice(params)
-    {}
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-  public:
-    /** Additional function to return the Port of a memory object. */
-    virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
-
-  public:
-    void regStats();
-
-  protected:
-    Stats::Scalar txBytes;
-    Stats::Scalar rxBytes;
-    Stats::Scalar txPackets;
-    Stats::Scalar rxPackets;
-    Stats::Scalar txIpChecksums;
-    Stats::Scalar rxIpChecksums;
-    Stats::Scalar txTcpChecksums;
-    Stats::Scalar rxTcpChecksums;
-    Stats::Scalar txUdpChecksums;
-    Stats::Scalar rxUdpChecksums;
-    Stats::Scalar descDmaReads;
-    Stats::Scalar descDmaWrites;
-    Stats::Scalar descDmaRdBytes;
-    Stats::Scalar descDmaWrBytes;
-    Stats::Formula totBandwidth;
-    Stats::Formula totPackets;
-    Stats::Formula totBytes;
-    Stats::Formula totPacketRate;
-    Stats::Formula txBandwidth;
-    Stats::Formula rxBandwidth;
-    Stats::Formula txPacketRate;
-    Stats::Formula rxPacketRate;
-    Stats::Scalar postedSwi;
-    Stats::Formula coalescedSwi;
-    Stats::Scalar totalSwi;
-    Stats::Scalar postedRxIdle;
-    Stats::Formula coalescedRxIdle;
-    Stats::Scalar totalRxIdle;
-    Stats::Scalar postedRxOk;
-    Stats::Formula coalescedRxOk;
-    Stats::Scalar totalRxOk;
-    Stats::Scalar postedRxDesc;
-    Stats::Formula coalescedRxDesc;
-    Stats::Scalar totalRxDesc;
-    Stats::Scalar postedTxOk;
-    Stats::Formula coalescedTxOk;
-    Stats::Scalar totalTxOk;
-    Stats::Scalar postedTxIdle;
-    Stats::Formula coalescedTxIdle;
-    Stats::Scalar totalTxIdle;
-    Stats::Scalar postedTxDesc;
-    Stats::Formula coalescedTxDesc;
-    Stats::Scalar totalTxDesc;
-    Stats::Scalar postedRxOrn;
-    Stats::Formula coalescedRxOrn;
-    Stats::Scalar totalRxOrn;
-    Stats::Formula coalescedTotal;
-    Stats::Scalar postedInterrupts;
-    Stats::Scalar droppedPackets;
-};
-
-/**
- * Dummy class to keep the Python class hierarchy in sync with the C++
- * object hierarchy.
- *
- * The Python object hierarchy includes the EtherDevBase class which
- * is used by some ethernet devices as a way to share common
- * configuration information in the generated param structs. Since the
- * Python hierarchy is used to generate a SWIG interface for all C++
- * SimObjects, we need to reflect this in the C++ object hierarchy. If
- * we don't, SWIG might end up doing 'bad things' when it down casts
- * ethernet objects to their base class(es).
- */
-class EtherDevBase : public EtherDevice
-{
-  public:
-    EtherDevBase(const EtherDevBaseParams *params)
-        : EtherDevice(params)
-    {}
-
-    const EtherDevBaseParams *
-    params() const
-    {
-        return dynamic_cast<const EtherDevBaseParams *>(_params);
-    }
-
-};
-
-#endif //__DEV_ETHERDEVICE_HH__
diff --git a/src/dev/etherdump.cc b/src/dev/etherdump.cc
deleted file mode 100644 (file)
index 21532bd..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Simple object for creating a simple pcap style packet trace
- */
-
-#include <sys/time.h>
-
-#include <algorithm>
-#include <string>
-
-#include "base/misc.hh"
-#include "base/output.hh"
-#include "dev/etherdump.hh"
-#include "sim/core.hh"
-
-using std::string;
-
-EtherDump::EtherDump(const Params *p)
-    : SimObject(p), stream(simout.create(p->file, true)),
-      maxlen(p->maxlen)
-{
-}
-
-#define DLT_EN10MB              1               // Ethernet (10Mb)
-#define TCPDUMP_MAGIC           0xa1b2c3d4
-#define PCAP_VERSION_MAJOR      2
-#define PCAP_VERSION_MINOR      4
-
-struct pcap_file_header {
-    uint32_t magic;
-    uint16_t version_major;
-    uint16_t version_minor;
-    int32_t thiszone;           // gmt to local correction
-    uint32_t sigfigs;           // accuracy of timestamps
-    uint32_t snaplen;           // max length saved portion of each pkt
-    uint32_t linktype;          // data link type (DLT_*)
-};
-
-struct pcap_pkthdr {
-    uint32_t seconds;
-    uint32_t microseconds;
-    uint32_t caplen;            // length of portion present
-    uint32_t len;               // length this packet (off wire)
-};
-
-void
-EtherDump::init()
-{
-    struct pcap_file_header hdr;
-    hdr.magic = TCPDUMP_MAGIC;
-    hdr.version_major = PCAP_VERSION_MAJOR;
-    hdr.version_minor = PCAP_VERSION_MINOR;
-
-    hdr.thiszone = 0;
-    hdr.snaplen = 1500;
-    hdr.sigfigs = 0;
-    hdr.linktype = DLT_EN10MB;
-
-    stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
-
-    stream->flush();
-}
-
-void
-EtherDump::dumpPacket(EthPacketPtr &packet)
-{
-    pcap_pkthdr pkthdr;
-    pkthdr.seconds = curTick() / SimClock::Int::s;
-    pkthdr.microseconds = (curTick() / SimClock::Int::us) % ULL(1000000);
-    pkthdr.caplen = std::min(packet->length, maxlen);
-    pkthdr.len = packet->length;
-    stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
-    stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
-    stream->flush();
-}
-
-EtherDump *
-EtherDumpParams::create()
-{
-    return new EtherDump(this);
-}
diff --git a/src/dev/etherdump.hh b/src/dev/etherdump.hh
deleted file mode 100644 (file)
index cc8fa91..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Simple object for creating a simple pcap style packet trace
- */
-
-#ifndef __ETHERDUMP_H__
-#define __ETHERDUMP_H__
-
-#include <fstream>
-
-#include "dev/etherpkt.hh"
-#include "params/EtherDump.hh"
-#include "sim/sim_object.hh"
-
-/*
- * Simple object for creating a simple pcap style packet trace
- */
-class EtherDump : public SimObject
-{
-  private:
-    std::ostream *stream;
-    const unsigned maxlen;
-    void dumpPacket(EthPacketPtr &packet);
-    void init();
-
-  public:
-    typedef EtherDumpParams Params;
-    EtherDump(const Params *p);
-
-    inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); }
-};
-
-#endif // __ETHERDUMP_H__
diff --git a/src/dev/etherint.cc b/src/dev/etherint.cc
deleted file mode 100644 (file)
index fce7b28..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#include "base/misc.hh"
-#include "dev/etherint.hh"
-#include "sim/sim_object.hh"
-
-void
-EtherInt::setPeer(EtherInt *p)
-{
-    if (peer && peer != p)
-        panic("You cannot change the peer once it is set.\n"
-              "Current peer=%s Desired peer=%s", peer->name(), p->name());
-
-    peer = p;
-}
diff --git a/src/dev/etherint.hh b/src/dev/etherint.hh
deleted file mode 100644 (file)
index 98b820d..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Class representing the actual interface between two ethernet
- * components.
- */
-
-#ifndef __DEV_ETHERINT_HH__
-#define __DEV_ETHERINT_HH__
-
-#include <string>
-
-#include "dev/etherpkt.hh"
-
-/*
- * Class representing the actual interface between two ethernet
- * components.  These components are intended to attach to another
- * ethernet interface on one side and whatever device on the other.
- */
-class EtherInt
-{
-  protected:
-    mutable std::string portName;
-    EtherInt *peer;
-
-  public:
-    EtherInt(const std::string &name)
-        : portName(name), peer(NULL) {}
-    virtual ~EtherInt() {}
-
-    /** Return port name (for DPRINTF). */
-    const std::string &name() const { return portName; }
-
-    void setPeer(EtherInt *p);
-    EtherInt* getPeer() { return peer; }
-
-    void recvDone() { peer->sendDone(); }
-    virtual void sendDone() = 0;
-
-    bool sendPacket(EthPacketPtr packet)
-    { return peer ? peer->recvPacket(packet) : true; }
-    virtual bool recvPacket(EthPacketPtr packet) = 0;
-
-    bool askBusy() {return peer->isBusy(); }
-    virtual bool isBusy() { return false; }
-};
-
-#endif // __DEV_ETHERINT_HH__
diff --git a/src/dev/etherlink.cc b/src/dev/etherlink.cc
deleted file mode 100644 (file)
index 1c88a31..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- *          Ron Dreslinski
- */
-
-/* @file
- * Device module for modelling a fixed bandwidth full duplex ethernet link
- */
-
-#include <cmath>
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/random.hh"
-#include "base/trace.hh"
-#include "debug/Ethernet.hh"
-#include "debug/EthernetData.hh"
-#include "dev/etherdump.hh"
-#include "dev/etherint.hh"
-#include "dev/etherlink.hh"
-#include "dev/etherpkt.hh"
-#include "params/EtherLink.hh"
-#include "sim/core.hh"
-#include "sim/serialize.hh"
-#include "sim/system.hh"
-
-using namespace std;
-
-EtherLink::EtherLink(const Params *p)
-    : EtherObject(p)
-{
-    link[0] = new Link(name() + ".link0", this, 0, p->speed,
-                       p->delay, p->delay_var, p->dump);
-    link[1] = new Link(name() + ".link1", this, 1, p->speed,
-                       p->delay, p->delay_var, p->dump);
-
-    interface[0] = new Interface(name() + ".int0", link[0], link[1]);
-    interface[1] = new Interface(name() + ".int1", link[1], link[0]);
-}
-
-
-EtherLink::~EtherLink()
-{
-    delete link[0];
-    delete link[1];
-
-    delete interface[0];
-    delete interface[1];
-}
-
-EtherInt*
-EtherLink::getEthPort(const std::string &if_name, int idx)
-{
-    Interface *i;
-    if (if_name == "int0")
-        i = interface[0];
-    else if (if_name == "int1")
-        i = interface[1];
-    else
-        return NULL;
-    if (i->getPeer())
-        panic("interface already connected to\n");
-
-    return i;
-}
-
-
-EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
-    : EtherInt(name), txlink(tx)
-{
-    tx->setTxInt(this);
-    rx->setRxInt(this);
-}
-
-EtherLink::Link::Link(const string &name, EtherLink *p, int num,
-                      double rate, Tick delay, Tick delay_var, EtherDump *d)
-    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
-      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
-      doneEvent(this), txQueueEvent(this)
-{ }
-
-void
-EtherLink::serialize(CheckpointOut &cp) const
-{
-    link[0]->serialize("link0", cp);
-    link[1]->serialize("link1", cp);
-}
-
-void
-EtherLink::unserialize(CheckpointIn &cp)
-{
-    link[0]->unserialize("link0", cp);
-    link[1]->unserialize("link1", cp);
-}
-
-void
-EtherLink::Link::txComplete(EthPacketPtr packet)
-{
-    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
-    DDUMP(EthernetData, packet->data, packet->length);
-    rxint->sendPacket(packet);
-}
-
-void
-EtherLink::Link::txDone()
-{
-    if (dump)
-        dump->dump(packet);
-
-    if (linkDelay > 0) {
-        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
-        txQueue.emplace_back(std::make_pair(curTick() + linkDelay, packet));
-        if (!txQueueEvent.scheduled())
-            parent->schedule(txQueueEvent, txQueue.front().first);
-    } else {
-        assert(txQueue.empty());
-        txComplete(packet);
-    }
-
-    packet = 0;
-    assert(!busy());
-
-    txint->sendDone();
-}
-
-void
-EtherLink::Link::processTxQueue()
-{
-    auto cur(txQueue.front());
-    txQueue.pop_front();
-
-    // Schedule a new event to process the next packet in the queue.
-    if (!txQueue.empty()) {
-        auto next(txQueue.front());
-        assert(next.first > curTick());
-        parent->schedule(txQueueEvent, next.first);
-    }
-
-    assert(cur.first == curTick());
-    txComplete(cur.second);
-}
-
-bool
-EtherLink::Link::transmit(EthPacketPtr pkt)
-{
-    if (busy()) {
-        DPRINTF(Ethernet, "packet not sent, link busy\n");
-        return false;
-    }
-
-    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
-    DDUMP(EthernetData, pkt->data, pkt->length);
-
-    packet = pkt;
-    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
-    if (delayVar != 0)
-        delay += random_mt.random<Tick>(0, delayVar);
-
-    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
-            delay, ticksPerByte);
-    parent->schedule(doneEvent, curTick() + delay);
-
-    return true;
-}
-
-void
-EtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
-{
-    bool packet_exists = packet != nullptr;
-    paramOut(cp, base + ".packet_exists", packet_exists);
-    if (packet_exists)
-        packet->serialize(base + ".packet", cp);
-
-    bool event_scheduled = doneEvent.scheduled();
-    paramOut(cp, base + ".event_scheduled", event_scheduled);
-    if (event_scheduled) {
-        Tick event_time = doneEvent.when();
-        paramOut(cp, base + ".event_time", event_time);
-    }
-
-    const size_t tx_queue_size(txQueue.size());
-    paramOut(cp, base + ".tx_queue_size", tx_queue_size);
-    unsigned idx(0);
-    for (const auto &pe : txQueue) {
-        paramOut(cp, csprintf("%s.txQueue[%i].tick", base, idx), pe.first);
-        pe.second->serialize(csprintf("%s.txQueue[%i].packet", base, idx), cp);
-
-        ++idx;
-    }
-}
-
-void
-EtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
-{
-    bool packet_exists;
-    paramIn(cp, base + ".packet_exists", packet_exists);
-    if (packet_exists) {
-        packet = make_shared<EthPacketData>(16384);
-        packet->unserialize(base + ".packet", cp);
-    }
-
-    bool event_scheduled;
-    paramIn(cp, base + ".event_scheduled", event_scheduled);
-    if (event_scheduled) {
-        Tick event_time;
-        paramIn(cp, base + ".event_time", event_time);
-        parent->schedule(doneEvent, event_time);
-    }
-
-    size_t tx_queue_size;
-    if (optParamIn(cp, base + ".tx_queue_size", tx_queue_size)) {
-        for (size_t idx = 0; idx < tx_queue_size; ++idx) {
-            Tick tick;
-            EthPacketPtr delayed_packet = make_shared<EthPacketData>(16384);
-
-            paramIn(cp, csprintf("%s.txQueue[%i].tick", base, idx), tick);
-            delayed_packet->unserialize(
-                csprintf("%s.txQueue[%i].packet", base, idx), cp);
-
-            fatal_if(!txQueue.empty() && txQueue.back().first > tick,
-                     "Invalid txQueue packet order in EtherLink!\n");
-            txQueue.emplace_back(std::make_pair(tick, delayed_packet));
-        }
-
-        if (!txQueue.empty())
-            parent->schedule(txQueueEvent, txQueue.front().first);
-    } else {
-        // We can't reliably convert in-flight packets from old
-        // checkpoints. In fact, gem5 hasn't been able to load these
-        // packets for at least two years before the format change.
-        warn("Old-style EtherLink serialization format detected, "
-             "in-flight packets may have been dropped.\n");
-    }
-}
-
-EtherLink *
-EtherLinkParams::create()
-{
-    return new EtherLink(this);
-}
diff --git a/src/dev/etherlink.hh b/src/dev/etherlink.hh
deleted file mode 100644 (file)
index 9d2a5fd..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Device module for modelling a fixed bandwidth full duplex ethernet link
- */
-
-#ifndef __DEV_ETHERLINK_HH__
-#define __DEV_ETHERLINK_HH__
-
-#include <queue>
-
-#include "base/types.hh"
-#include "dev/etherint.hh"
-#include "dev/etherobject.hh"
-#include "dev/etherpkt.hh"
-#include "params/EtherLink.hh"
-#include "sim/eventq.hh"
-#include "sim/sim_object.hh"
-
-class EtherDump;
-class Checkpoint;
-/*
- * Model for a fixed bandwidth full duplex ethernet link
- */
-class EtherLink : public EtherObject
-{
-  protected:
-    class Interface;
-
-    /*
-     * Model for a single uni-directional link
-     */
-    class Link
-    {
-      protected:
-        const std::string objName;
-
-        EtherLink *const parent;
-        const int number;
-
-        Interface *txint;
-        Interface *rxint;
-
-        const double ticksPerByte;
-        const Tick linkDelay;
-        const Tick delayVar;
-        EtherDump *const dump;
-
-      protected:
-        /*
-         * Transfer is complete
-         */
-        EthPacketPtr packet;
-        void txDone();
-        typedef EventWrapper<Link, &Link::txDone> DoneEvent;
-        friend void DoneEvent::process();
-        DoneEvent doneEvent;
-
-        /**
-         * Maintain a queue of in-flight packets. Assume that the
-         * delay is non-zero and constant (i.e., at most one packet
-         * per tick).
-         */
-        std::deque<std::pair<Tick, EthPacketPtr>> txQueue;
-
-        void processTxQueue();
-        typedef EventWrapper<Link, &Link::processTxQueue> TxQueueEvent;
-        friend void TxQueueEvent::process();
-        TxQueueEvent txQueueEvent;
-
-        void txComplete(EthPacketPtr packet);
-
-      public:
-        Link(const std::string &name, EtherLink *p, int num,
-             double rate, Tick delay, Tick delay_var, EtherDump *dump);
-        ~Link() {}
-
-        const std::string name() const { return objName; }
-
-        bool busy() const { return (bool)packet; }
-        bool transmit(EthPacketPtr packet);
-
-        void setTxInt(Interface *i) { assert(!txint); txint = i; }
-        void setRxInt(Interface *i) { assert(!rxint); rxint = i; }
-
-        void serialize(const std::string &base, CheckpointOut &cp) const;
-        void unserialize(const std::string &base, CheckpointIn &cp);
-    };
-
-    /*
-     * Interface at each end of the link
-     */
-    class Interface : public EtherInt
-    {
-      private:
-        Link *txlink;
-
-      public:
-        Interface(const std::string &name, Link *txlink, Link *rxlink);
-        bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); }
-        void sendDone() { peer->sendDone(); }
-        bool isBusy() { return txlink->busy(); }
-    };
-
-    Link *link[2];
-    Interface *interface[2];
-
-  public:
-    typedef EtherLinkParams Params;
-    EtherLink(const Params *p);
-    virtual ~EtherLink();
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    EtherInt *getEthPort(const std::string &if_name, int idx) override;
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-
-};
-
-#endif // __ETHERLINK_HH__
diff --git a/src/dev/etherobject.hh b/src/dev/etherobject.hh
deleted file mode 100644 (file)
index 02a30ab..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2007 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/**
- * @file
- * Base Ethernet Object declaration.
- */
-
-#ifndef __DEV_ETHEROBJECT_HH__
-#define __DEV_ETHEROBJECT_HH__
-
-#include "params/EtherObject.hh"
-#include "sim/sim_object.hh"
-
-class EtherInt;
-
-/**
- * The base EtherObject class, allows for an accesor function to a
- * simobj that returns the Port.
- */
-class EtherObject : public SimObject
-{
-  public:
-    typedef EtherObjectParams Params;
-    EtherObject(const Params *params)
-        : SimObject(params) {}
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-  public:
-    /** Additional function to return the Port of a memory object. */
-    virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
-
-};
-
-#endif //__MEM_MEM_OBJECT_HH__
diff --git a/src/dev/etherpkt.cc b/src/dev/etherpkt.cc
deleted file mode 100644 (file)
index 58b53b5..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#include <iostream>
-
-#include "base/misc.hh"
-#include "base/inet.hh"
-#include "dev/etherpkt.hh"
-#include "sim/serialize.hh"
-
-using namespace std;
-
-void
-EthPacketData::serialize(const string &base, CheckpointOut &cp) const
-{
-    paramOut(cp, base + ".length", length);
-    arrayParamOut(cp, base + ".data", data, length);
-}
-
-void
-EthPacketData::unserialize(const string &base, CheckpointIn &cp)
-{
-    paramIn(cp, base + ".length", length);
-    if (length)
-        arrayParamIn(cp, base + ".data", data, length);
-}
-
-void
-EthPacketData::packAddress(uint8_t *src_addr,
-                           uint8_t *dst_addr,
-                           unsigned &nbytes)
-{
-    Net::EthHdr *hdr = (Net::EthHdr *)data;
-    assert(hdr->src().size() == hdr->dst().size());
-    if (nbytes < hdr->src().size())
-        panic("EthPacketData::packAddress() Buffer overflow");
-
-    memcpy(dst_addr, hdr->dst().bytes(), hdr->dst().size());
-    memcpy(src_addr, hdr->src().bytes(), hdr->src().size());
-
-    nbytes = hdr->src().size();
-}
-
diff --git a/src/dev/etherpkt.hh b/src/dev/etherpkt.hh
deleted file mode 100644 (file)
index 0d8998b..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2002-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- *          Lisa Hsu
- */
-
-/* @file
- * Reference counted class containing ethernet packet data
- */
-
-#ifndef __ETHERPKT_HH__
-#define __ETHERPKT_HH__
-
-#include <cassert>
-#include <iosfwd>
-#include <memory>
-
-#include "base/types.hh"
-#include "sim/serialize.hh"
-
-/*
- * Reference counted class containing ethernet packet data
- */
-class EthPacketData
-{
-  public:
-    /*
-     * Pointer to packet data will be deleted
-     */
-    uint8_t *data;
-
-    /*
-     * Length of the current packet
-     */
-    unsigned length;
-
-  public:
-    EthPacketData()
-        : data(NULL), length(0)
-    { }
-
-    explicit EthPacketData(unsigned size)
-        : data(new uint8_t[size]), length(0)
-    { }
-
-    ~EthPacketData() { if (data) delete [] data; }
-
-  public:
-    /**
-     * This function pulls out the MAC source and destination addresses from
-     * the packet data and stores them in the caller specified buffers.
-     *
-     * @param src_addr The buffer to store the source MAC address.
-     * @param dst_addr The buffer to store the destination MAC address.
-     * @param length This is an inout parameter. The caller stores in this
-     * the size of the address buffers. On return, this will contain the
-     * actual address size stored in the buffers. (We assume that source
-     * address size is equal to that of the destination address.)
-     */
-    void packAddress(uint8_t *src_addr, uint8_t *dst_addr, unsigned &length);
-
-    void serialize(const std::string &base, CheckpointOut &cp) const;
-    void unserialize(const std::string &base, CheckpointIn &cp);
-
-    unsigned size() const { return length; }
-};
-
-typedef std::shared_ptr<EthPacketData> EthPacketPtr;
-
-#endif // __ETHERPKT_HH__
diff --git a/src/dev/ethertap.cc b/src/dev/ethertap.cc
deleted file mode 100644 (file)
index d062b5d..0000000
+++ /dev/null
@@ -1,346 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Interface to connect a simulated ethernet device to the real world
- */
-
-#if defined(__OpenBSD__) || defined(__APPLE__)
-#include <sys/param.h>
-#endif
-#include <netinet/in.h>
-#include <unistd.h>
-
-#include <deque>
-#include <string>
-
-#include "base/misc.hh"
-#include "base/pollevent.hh"
-#include "base/socket.hh"
-#include "base/trace.hh"
-#include "debug/Ethernet.hh"
-#include "debug/EthernetData.hh"
-#include "dev/etherdump.hh"
-#include "dev/etherint.hh"
-#include "dev/etherpkt.hh"
-#include "dev/ethertap.hh"
-
-using namespace std;
-
-/**
- */
-class TapListener
-{
-  protected:
-    /**
-     */
-    class Event : public PollEvent
-    {
-      protected:
-        TapListener *listener;
-
-      public:
-        Event(TapListener *l, int fd, int e)
-            : PollEvent(fd, e), listener(l) {}
-
-        virtual void process(int revent) { listener->accept(); }
-    };
-
-    friend class Event;
-    Event *event;
-
-  protected:
-    ListenSocket listener;
-    EtherTap *tap;
-    int port;
-
-  public:
-    TapListener(EtherTap *t, int p)
-        : event(NULL), tap(t), port(p) {}
-    ~TapListener() { if (event) delete event; }
-
-    void accept();
-    void listen();
-};
-
-void
-TapListener::listen()
-{
-    while (!listener.listen(port, true)) {
-        DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
-        port++;
-    }
-
-    ccprintf(cerr, "Listening for tap connection on port %d\n", port);
-    event = new Event(this, listener.getfd(), POLLIN|POLLERR);
-    pollQueue.schedule(event);
-}
-
-void
-TapListener::accept()
-{
-    // As a consequence of being called from the PollQueue, we might
-    // have been called from a different thread. Migrate to "our"
-    // thread.
-    EventQueue::ScopedMigration migrate(tap->eventQueue());
-
-    if (!listener.islistening())
-        panic("TapListener(accept): cannot accept if we're not listening!");
-
-    int sfd = listener.accept(true);
-    if (sfd != -1)
-        tap->attach(sfd);
-}
-
-/**
- */
-class TapEvent : public PollEvent
-{
-  protected:
-    EtherTap *tap;
-
-  public:
-    TapEvent(EtherTap *_tap, int fd, int e)
-        : PollEvent(fd, e), tap(_tap) {}
-    virtual void process(int revent) { tap->process(revent); }
-};
-
-EtherTap::EtherTap(const Params *p)
-    : EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump),
-      interface(NULL), txEvent(this)
-{
-    if (ListenSocket::allDisabled())
-        fatal("All listeners are disabled! EtherTap can't work!");
-
-    buffer = new char[buflen];
-    listener = new TapListener(this, p->port);
-    listener->listen();
-    interface = new EtherTapInt(name() + ".interface", this);
-}
-
-EtherTap::~EtherTap()
-{
-    if (event)
-        delete event;
-    if (buffer)
-        delete [] buffer;
-
-    delete interface;
-    delete listener;
-}
-
-void
-EtherTap::attach(int fd)
-{
-    if (socket != -1)
-        close(fd);
-
-    buffer_offset = 0;
-    data_len = 0;
-    socket = fd;
-    DPRINTF(Ethernet, "EtherTap attached\n");
-    event = new TapEvent(this, socket, POLLIN|POLLERR);
-    pollQueue.schedule(event);
-}
-
-void
-EtherTap::detach()
-{
-    DPRINTF(Ethernet, "EtherTap detached\n");
-    delete event;
-    event = 0;
-    close(socket);
-    socket = -1;
-}
-
-bool
-EtherTap::recvPacket(EthPacketPtr packet)
-{
-    if (dump)
-        dump->dump(packet);
-
-    DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
-    DDUMP(EthernetData, packet->data, packet->length);
-    uint32_t len = htonl(packet->length);
-    ssize_t ret = write(socket, &len, sizeof(len));
-    if (ret != sizeof(len))
-        return false;
-    ret = write(socket, packet->data, packet->length);
-    if (ret != packet->length)
-        return false;
-
-    interface->recvDone();
-
-    return true;
-}
-
-void
-EtherTap::sendDone()
-{}
-
-void
-EtherTap::process(int revent)
-{
-    if (revent & POLLERR) {
-        detach();
-        return;
-    }
-
-    char *data = buffer + sizeof(uint32_t);
-    if (!(revent & POLLIN))
-        return;
-
-    if (buffer_offset < data_len + sizeof(uint32_t)) {
-        int len = read(socket, buffer + buffer_offset, buflen - buffer_offset);
-        if (len == 0) {
-            detach();
-            return;
-        }
-
-        buffer_offset += len;
-
-        if (data_len == 0)
-            data_len = ntohl(*(uint32_t *)buffer);
-
-        DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d "
-                "data_len=%d\n", len, buffer_offset, data_len);
-    }
-
-    while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) {
-        EthPacketPtr packet;
-        packet = make_shared<EthPacketData>(data_len);
-        packet->length = data_len;
-        memcpy(packet->data, data, data_len);
-
-        buffer_offset -= data_len + sizeof(uint32_t);
-        assert(buffer_offset >= 0);
-        if (buffer_offset > 0) {
-            memmove(buffer, data + data_len, buffer_offset);
-            data_len = ntohl(*(uint32_t *)buffer);
-        } else
-            data_len = 0;
-
-        DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length);
-        DDUMP(EthernetData, packet->data, packet->length);
-        if (!interface->sendPacket(packet)) {
-            DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
-            packetBuffer.push(packet);
-            if (!txEvent.scheduled())
-                schedule(txEvent, curTick() + retryTime);
-        } else if (dump) {
-            dump->dump(packet);
-        }
-    }
-}
-
-void
-EtherTap::retransmit()
-{
-    if (packetBuffer.empty())
-        return;
-
-    EthPacketPtr packet = packetBuffer.front();
-    if (interface->sendPacket(packet)) {
-        if (dump)
-            dump->dump(packet);
-        DPRINTF(Ethernet, "EtherTap retransmit\n");
-        packetBuffer.front() = NULL;
-        packetBuffer.pop();
-    }
-
-    if (!packetBuffer.empty() && !txEvent.scheduled())
-        schedule(txEvent, curTick() + retryTime);
-}
-
-EtherInt*
-EtherTap::getEthPort(const std::string &if_name, int idx)
-{
-    if (if_name == "tap") {
-        if (interface->getPeer())
-            panic("Interface already connected to\n");
-        return interface;
-    }
-    return NULL;
-}
-
-
-//=====================================================================
-
-void
-EtherTap::serialize(CheckpointOut &cp) const
-{
-    SERIALIZE_SCALAR(socket);
-    SERIALIZE_SCALAR(buflen);
-    uint8_t *buffer = (uint8_t *)this->buffer;
-    SERIALIZE_ARRAY(buffer, buflen);
-    SERIALIZE_SCALAR(buffer_offset);
-    SERIALIZE_SCALAR(data_len);
-
-    bool tapevent_present = false;
-    if (event) {
-        tapevent_present = true;
-        SERIALIZE_SCALAR(tapevent_present);
-        event->serialize(cp);
-    }
-    else {
-        SERIALIZE_SCALAR(tapevent_present);
-    }
-}
-
-void
-EtherTap::unserialize(CheckpointIn &cp)
-{
-    UNSERIALIZE_SCALAR(socket);
-    UNSERIALIZE_SCALAR(buflen);
-    uint8_t *buffer = (uint8_t *)this->buffer;
-    UNSERIALIZE_ARRAY(buffer, buflen);
-    UNSERIALIZE_SCALAR(buffer_offset);
-    UNSERIALIZE_SCALAR(data_len);
-
-    bool tapevent_present;
-    UNSERIALIZE_SCALAR(tapevent_present);
-    if (tapevent_present) {
-        event = new TapEvent(this, socket, POLLIN|POLLERR);
-
-        event->unserialize(cp);
-
-        if (event->queued()) {
-            pollQueue.schedule(event);
-        }
-    }
-}
-
-//=====================================================================
-
-EtherTap *
-EtherTapParams::create()
-{
-    return new EtherTap(this);
-}
diff --git a/src/dev/ethertap.hh b/src/dev/ethertap.hh
deleted file mode 100644 (file)
index 5755032..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2003-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-/* @file
- * Interface to connect a simulated ethernet device to the real world
- */
-
-#ifndef __ETHERTAP_HH__
-#define __ETHERTAP_HH__
-
-#include <queue>
-#include <string>
-
-#include "base/pollevent.hh"
-#include "dev/etherint.hh"
-#include "dev/etherobject.hh"
-#include "dev/etherpkt.hh"
-#include "params/EtherTap.hh"
-#include "sim/eventq.hh"
-#include "sim/sim_object.hh"
-
-class TapEvent;
-class TapListener;
-class EtherTapInt;
-
-/*
- * Interface to connect a simulated ethernet device to the real world
- */
-class EtherTap : public EtherObject
-{
-  protected:
-    friend class TapEvent;
-    TapEvent *event;
-
-  protected:
-    friend class TapListener;
-    TapListener *listener;
-    int socket;
-    char *buffer;
-    int buflen;
-    uint32_t buffer_offset;
-    uint32_t data_len;
-
-    EtherDump *dump;
-
-    void attach(int fd);
-    void detach();
-
-  protected:
-    std::string device;
-    std::queue<EthPacketPtr> packetBuffer;
-    EtherTapInt *interface;
-
-    void process(int revent);
-    void enqueue(EthPacketData *packet);
-    void retransmit();
-
-    /*
-     */
-    class TxEvent : public Event
-    {
-      protected:
-        EtherTap *tap;
-
-      public:
-        TxEvent(EtherTap *_tap) : tap(_tap) {}
-        void process() { tap->retransmit(); }
-        virtual const char *description() const
-            { return "EtherTap retransmit"; }
-    };
-
-    friend class TxEvent;
-    TxEvent txEvent;
-
-  public:
-    typedef EtherTapParams Params;
-    EtherTap(const Params *p);
-    virtual ~EtherTap();
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    EtherInt *getEthPort(const std::string &if_name, int idx) override;
-
-    virtual bool recvPacket(EthPacketPtr packet);
-    virtual void sendDone();
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-};
-
-class EtherTapInt : public EtherInt
-{
-  private:
-    EtherTap *tap;
-  public:
-    EtherTapInt(const std::string &name, EtherTap *t)
-            : EtherInt(name), tap(t)
-    { }
-
-    virtual bool recvPacket(EthPacketPtr pkt) { return tap->recvPacket(pkt); }
-    virtual void sendDone() { tap->sendDone(); }
-};
-
-
-#endif // __ETHERTAP_HH__
diff --git a/src/dev/i8254xGBe.cc b/src/dev/i8254xGBe.cc
deleted file mode 100644 (file)
index 50126e6..0000000
+++ /dev/null
@@ -1,2562 +0,0 @@
-/*
- * Copyright (c) 2006 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Device model for Intel's 8254x line of gigabit ethernet controllers.
- * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
- * fewest workarounds in the driver. It will probably work with most of the
- * other MACs with slight modifications.
- */
-
-
-/*
- * @todo really there are multiple dma engines.. we should implement them.
- */
-
-#include <algorithm>
-#include <memory>
-
-#include "base/inet.hh"
-#include "base/trace.hh"
-#include "debug/Drain.hh"
-#include "debug/EthernetAll.hh"
-#include "dev/i8254xGBe.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "params/IGbE.hh"
-#include "sim/stats.hh"
-#include "sim/system.hh"
-
-using namespace iGbReg;
-using namespace Net;
-
-IGbE::IGbE(const Params *p)
-    : EtherDevice(p), etherInt(NULL), cpa(NULL),
-      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
-      txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
-      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), 
-      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), 
-      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),  
-      rdtrEvent(this), radvEvent(this),
-      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
-      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
-      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
-      lastInterrupt(0)
-{
-    etherInt = new IGbEInt(name() + ".int", this);
-
-    // Initialized internal registers per Intel documentation
-    // All registers intialized to 0 by per register constructor
-    regs.ctrl.fd(1);
-    regs.ctrl.lrst(1);
-    regs.ctrl.speed(2);
-    regs.ctrl.frcspd(1);
-    regs.sts.speed(3); // Say we're 1000Mbps
-    regs.sts.fd(1); // full duplex
-    regs.sts.lu(1); // link up
-    regs.eecd.fwe(1);
-    regs.eecd.ee_type(1);
-    regs.imr = 0;
-    regs.iam = 0;
-    regs.rxdctl.gran(1);
-    regs.rxdctl.wthresh(1);
-    regs.fcrth(1);
-    regs.tdwba = 0;
-    regs.rlpml = 0;
-    regs.sw_fw_sync = 0;
-
-    regs.pba.rxa(0x30);
-    regs.pba.txa(0x10);
-
-    eeOpBits            = 0;
-    eeAddrBits          = 0;
-    eeDataBits          = 0;
-    eeOpcode            = 0;
-
-    // clear all 64 16 bit words of the eeprom
-    memset(&flash, 0, EEPROM_SIZE*2);
-
-    // Set the MAC address
-    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
-    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
-        flash[x] = htobe(flash[x]);
-
-    uint16_t csum = 0;
-    for (int x = 0; x < EEPROM_SIZE; x++)
-        csum += htobe(flash[x]);
-
-
-    // Magic happy checksum value
-    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
-
-    // Store the MAC address as queue ID
-    macAddr = p->hardware_address;
-
-    rxFifo.clear();
-    txFifo.clear();
-}
-
-IGbE::~IGbE()
-{
-    delete etherInt;
-}
-
-void
-IGbE::init()
-{
-    cpa = CPA::cpa();
-    PciDevice::init();
-}
-
-EtherInt*
-IGbE::getEthPort(const std::string &if_name, int idx)
-{
-
-    if (if_name == "interface") {
-        if (etherInt->getPeer())
-            panic("Port already connected to\n");
-        return etherInt;
-    }
-    return NULL;
-}
-
-Tick
-IGbE::writeConfig(PacketPtr pkt)
-{
-    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
-    if (offset < PCI_DEVICE_SPECIFIC)
-        PciDevice::writeConfig(pkt);
-    else
-        panic("Device specific PCI config space not implemented.\n");
-
-    //
-    // Some work may need to be done here based for the pci COMMAND bits.
-    //
-
-    return configDelay;
-}
-
-// Handy macro for range-testing register access addresses
-#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
-
-Tick
-IGbE::read(PacketPtr pkt)
-{
-    int bar;
-    Addr daddr;
-
-    if (!getBAR(pkt->getAddr(), bar, daddr))
-        panic("Invalid PCI memory access to unmapped memory.\n");
-
-    // Only Memory register BAR is allowed
-    assert(bar == 0);
-
-    // Only 32bit accesses allowed
-    assert(pkt->getSize() == 4);
-
-    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
-
-    //
-    // Handle read of register here
-    //
-
-
-    switch (daddr) {
-      case REG_CTRL:
-        pkt->set<uint32_t>(regs.ctrl());
-        break;
-      case REG_STATUS:
-        pkt->set<uint32_t>(regs.sts());
-        break;
-      case REG_EECD:
-        pkt->set<uint32_t>(regs.eecd());
-        break;
-      case REG_EERD:
-        pkt->set<uint32_t>(regs.eerd());
-        break;
-      case REG_CTRL_EXT:
-        pkt->set<uint32_t>(regs.ctrl_ext());
-        break;
-      case REG_MDIC:
-        pkt->set<uint32_t>(regs.mdic());
-        break;
-      case REG_ICR:
-        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
-                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
-        pkt->set<uint32_t>(regs.icr());
-        if (regs.icr.int_assert() || regs.imr == 0) {
-            regs.icr = regs.icr() & ~mask(30);
-            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
-        }
-        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
-            regs.imr &= ~regs.iam;
-        chkInterrupt();
-        break;
-      case REG_EICR:
-        // This is only useful for MSI, but the driver reads it every time
-        // Just don't do anything
-        pkt->set<uint32_t>(0);
-        break;
-      case REG_ITR:
-        pkt->set<uint32_t>(regs.itr());
-        break;
-      case REG_RCTL:
-        pkt->set<uint32_t>(regs.rctl());
-        break;
-      case REG_FCTTV:
-        pkt->set<uint32_t>(regs.fcttv());
-        break;
-      case REG_TCTL:
-        pkt->set<uint32_t>(regs.tctl());
-        break;
-      case REG_PBA:
-        pkt->set<uint32_t>(regs.pba());
-        break;
-      case REG_WUC:
-      case REG_LEDCTL:
-        pkt->set<uint32_t>(0); // We don't care, so just return 0
-        break;
-      case REG_FCRTL:
-        pkt->set<uint32_t>(regs.fcrtl());
-        break;
-      case REG_FCRTH:
-        pkt->set<uint32_t>(regs.fcrth());
-        break;
-      case REG_RDBAL:
-        pkt->set<uint32_t>(regs.rdba.rdbal());
-        break;
-      case REG_RDBAH:
-        pkt->set<uint32_t>(regs.rdba.rdbah());
-        break;
-      case REG_RDLEN:
-        pkt->set<uint32_t>(regs.rdlen());
-        break;
-      case REG_SRRCTL:
-        pkt->set<uint32_t>(regs.srrctl());
-        break;
-      case REG_RDH:
-        pkt->set<uint32_t>(regs.rdh());
-        break;
-      case REG_RDT:
-        pkt->set<uint32_t>(regs.rdt());
-        break;
-      case REG_RDTR:
-        pkt->set<uint32_t>(regs.rdtr());
-        if (regs.rdtr.fpd()) {
-            rxDescCache.writeback(0);
-            DPRINTF(EthernetIntr,
-                    "Posting interrupt because of RDTR.FPD write\n");
-            postInterrupt(IT_RXT);
-            regs.rdtr.fpd(0);
-        }
-        break;
-      case REG_RXDCTL:
-        pkt->set<uint32_t>(regs.rxdctl());
-        break;
-      case REG_RADV:
-        pkt->set<uint32_t>(regs.radv());
-        break;
-      case REG_TDBAL:
-        pkt->set<uint32_t>(regs.tdba.tdbal());
-        break;
-      case REG_TDBAH:
-        pkt->set<uint32_t>(regs.tdba.tdbah());
-        break;
-      case REG_TDLEN:
-        pkt->set<uint32_t>(regs.tdlen());
-        break;
-      case REG_TDH:
-        pkt->set<uint32_t>(regs.tdh());
-        break;
-      case REG_TXDCA_CTL:
-        pkt->set<uint32_t>(regs.txdca_ctl());
-        break;
-      case REG_TDT:
-        pkt->set<uint32_t>(regs.tdt());
-        break;
-      case REG_TIDV:
-        pkt->set<uint32_t>(regs.tidv());
-        break;
-      case REG_TXDCTL:
-        pkt->set<uint32_t>(regs.txdctl());
-        break;
-      case REG_TADV:
-        pkt->set<uint32_t>(regs.tadv());
-        break;
-      case REG_TDWBAL:
-        pkt->set<uint32_t>(regs.tdwba & mask(32));
-        break;
-      case REG_TDWBAH:
-        pkt->set<uint32_t>(regs.tdwba >> 32);
-        break;
-      case REG_RXCSUM:
-        pkt->set<uint32_t>(regs.rxcsum());
-        break;
-      case REG_RLPML:
-        pkt->set<uint32_t>(regs.rlpml);
-        break;
-      case REG_RFCTL:
-        pkt->set<uint32_t>(regs.rfctl());
-        break;
-      case REG_MANC:
-        pkt->set<uint32_t>(regs.manc());
-        break;
-      case REG_SWSM:
-        pkt->set<uint32_t>(regs.swsm());
-        regs.swsm.smbi(1);
-        break;
-      case REG_FWSM:
-        pkt->set<uint32_t>(regs.fwsm());
-        break;
-      case REG_SWFWSYNC:
-        pkt->set<uint32_t>(regs.sw_fw_sync);
-        break;
-      default:
-        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
-            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
-            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
-            !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE))
-            panic("Read request to unknown register number: %#x\n", daddr);
-        else
-            pkt->set<uint32_t>(0);
-    };
-
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-Tick
-IGbE::write(PacketPtr pkt)
-{
-    int bar;
-    Addr daddr;
-
-
-    if (!getBAR(pkt->getAddr(), bar, daddr))
-        panic("Invalid PCI memory access to unmapped memory.\n");
-
-    // Only Memory register BAR is allowed
-    assert(bar == 0);
-
-    // Only 32bit accesses allowed
-    assert(pkt->getSize() == sizeof(uint32_t));
-
-    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
-            daddr, pkt->get<uint32_t>());
-
-    //
-    // Handle write of register here
-    //
-    uint32_t val = pkt->get<uint32_t>();
-
-    Regs::RCTL oldrctl;
-    Regs::TCTL oldtctl;
-
-    switch (daddr) {
-      case REG_CTRL:
-        regs.ctrl = val;
-        if (regs.ctrl.tfce())
-            warn("TX Flow control enabled, should implement\n");
-        if (regs.ctrl.rfce())
-            warn("RX Flow control enabled, should implement\n");
-        break;
-      case REG_CTRL_EXT:
-        regs.ctrl_ext = val;
-        break;
-      case REG_STATUS:
-        regs.sts = val;
-        break;
-      case REG_EECD:
-        int oldClk;
-        oldClk = regs.eecd.sk();
-        regs.eecd = val;
-        // See if this is a eeprom access and emulate accordingly
-        if (!oldClk && regs.eecd.sk()) {
-            if (eeOpBits < 8) {
-                eeOpcode = eeOpcode << 1 | regs.eecd.din();
-                eeOpBits++;
-            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
-                eeAddr = eeAddr << 1 | regs.eecd.din();
-                eeAddrBits++;
-            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
-                assert(eeAddr>>1 < EEPROM_SIZE);
-                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
-                        flash[eeAddr>>1] >> eeDataBits & 0x1,
-                        flash[eeAddr>>1]);
-                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
-                eeDataBits++;
-            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
-                regs.eecd.dout(0);
-                eeDataBits++;
-            } else
-                panic("What's going on with eeprom interface? opcode:"
-                      " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
-                      (uint32_t)eeOpBits, (uint32_t)eeAddr,
-                      (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
-
-            // Reset everything for the next command
-            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
-                (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
-                eeOpBits = 0;
-                eeAddrBits = 0;
-                eeDataBits = 0;
-                eeOpcode = 0;
-                eeAddr = 0;
-            }
-
-            DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
-                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
-                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
-            if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
-                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
-                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
-                      (uint32_t)eeOpBits);
-
-
-        }
-        // If driver requests eeprom access, immediately give it to it
-        regs.eecd.ee_gnt(regs.eecd.ee_req());
-        break;
-      case REG_EERD:
-        regs.eerd = val;
-        if (regs.eerd.start()) {
-            regs.eerd.done(1);
-            assert(regs.eerd.addr() < EEPROM_SIZE);
-            regs.eerd.data(flash[regs.eerd.addr()]);
-            regs.eerd.start(0);
-            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
-                    regs.eerd.addr(), regs.eerd.data());
-        }
-        break;
-      case REG_MDIC:
-        regs.mdic = val;
-        if (regs.mdic.i())
-            panic("No support for interrupt on mdic complete\n");
-        if (regs.mdic.phyadd() != 1)
-            panic("No support for reading anything but phy\n");
-        DPRINTF(Ethernet, "%s phy address %x\n",
-                regs.mdic.op() == 1 ? "Writing" : "Reading",
-                regs.mdic.regadd());
-        switch (regs.mdic.regadd()) {
-          case PHY_PSTATUS:
-            regs.mdic.data(0x796D); // link up
-            break;
-          case PHY_PID:
-            regs.mdic.data(params()->phy_pid);
-            break;
-          case PHY_EPID:
-            regs.mdic.data(params()->phy_epid);
-            break;
-          case PHY_GSTATUS:
-            regs.mdic.data(0x7C00);
-            break;
-          case PHY_EPSTATUS:
-            regs.mdic.data(0x3000);
-            break;
-          case PHY_AGC:
-            regs.mdic.data(0x180); // some random length
-            break;
-          default:
-            regs.mdic.data(0);
-        }
-        regs.mdic.r(1);
-        break;
-      case REG_ICR:
-        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
-                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
-        if (regs.ctrl_ext.iame())
-            regs.imr &= ~regs.iam;
-        regs.icr = ~bits(val,30,0) & regs.icr();
-        chkInterrupt();
-        break;
-      case REG_ITR:
-        regs.itr = val;
-        break;
-      case REG_ICS:
-        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
-        postInterrupt((IntTypes)val);
-        break;
-      case REG_IMS:
-        regs.imr |= val;
-        chkInterrupt();
-        break;
-      case REG_IMC:
-        regs.imr &= ~val;
-        chkInterrupt();
-        break;
-      case REG_IAM:
-        regs.iam = val;
-        break;
-      case REG_RCTL:
-        oldrctl = regs.rctl;
-        regs.rctl = val;
-        if (regs.rctl.rst()) {
-            rxDescCache.reset();
-            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
-            rxFifo.clear();
-            regs.rctl.rst(0);
-        }
-        if (regs.rctl.en())
-            rxTick = true;
-        restartClock();
-        break;
-      case REG_FCTTV:
-        regs.fcttv = val;
-        break;
-      case REG_TCTL:
-        regs.tctl = val;
-        oldtctl = regs.tctl;
-        regs.tctl = val;
-        if (regs.tctl.en())
-            txTick = true;
-        restartClock();
-        if (regs.tctl.en() && !oldtctl.en()) {
-            txDescCache.reset();
-        }
-        break;
-      case REG_PBA:
-        regs.pba.rxa(val);
-        regs.pba.txa(64 - regs.pba.rxa());
-        break;
-      case REG_WUC:
-      case REG_LEDCTL:
-      case REG_FCAL:
-      case REG_FCAH:
-      case REG_FCT:
-      case REG_VET:
-      case REG_AIFS:
-      case REG_TIPG:
-        ; // We don't care, so don't store anything
-        break;
-      case REG_IVAR0:
-        warn("Writing to IVAR0, ignoring...\n");
-        break;
-      case REG_FCRTL:
-        regs.fcrtl = val;
-        break;
-      case REG_FCRTH:
-        regs.fcrth = val;
-        break;
-      case REG_RDBAL:
-        regs.rdba.rdbal( val & ~mask(4));
-        rxDescCache.areaChanged();
-        break;
-      case REG_RDBAH:
-        regs.rdba.rdbah(val);
-        rxDescCache.areaChanged();
-        break;
-      case REG_RDLEN:
-        regs.rdlen = val & ~mask(7);
-        rxDescCache.areaChanged();
-        break;
-      case REG_SRRCTL:
-        regs.srrctl = val;
-        break;
-      case REG_RDH:
-        regs.rdh = val;
-        rxDescCache.areaChanged();
-        break;
-      case REG_RDT:
-        regs.rdt = val;
-        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
-        if (drainState() == DrainState::Running) {
-            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
-            rxDescCache.fetchDescriptors();
-        } else {
-            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
-        }
-        break;
-      case REG_RDTR:
-        regs.rdtr = val;
-        break;
-      case REG_RADV:
-        regs.radv = val;
-        break;
-      case REG_RXDCTL:
-        regs.rxdctl = val;
-        break;
-      case REG_TDBAL:
-        regs.tdba.tdbal( val & ~mask(4));
-        txDescCache.areaChanged();
-        break;
-      case REG_TDBAH:
-        regs.tdba.tdbah(val);
-        txDescCache.areaChanged();
-        break;
-      case REG_TDLEN:
-        regs.tdlen = val & ~mask(7);
-        txDescCache.areaChanged();
-        break;
-      case REG_TDH:
-        regs.tdh = val;
-        txDescCache.areaChanged();
-        break;
-      case REG_TXDCA_CTL:
-        regs.txdca_ctl = val;
-        if (regs.txdca_ctl.enabled())
-            panic("No support for DCA\n");
-        break;
-      case REG_TDT:
-        regs.tdt = val;
-        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
-        if (drainState() == DrainState::Running) {
-            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
-            txDescCache.fetchDescriptors();
-        } else {
-            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
-        }
-        break;
-      case REG_TIDV:
-        regs.tidv = val;
-        break;
-      case REG_TXDCTL:
-        regs.txdctl = val;
-        break;
-      case REG_TADV:
-        regs.tadv = val;
-        break;
-      case REG_TDWBAL:
-        regs.tdwba &= ~mask(32);
-        regs.tdwba |= val;
-        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
-                                        regs.tdwba & mask(1));
-        break;
-      case REG_TDWBAH:
-        regs.tdwba &= mask(32);
-        regs.tdwba |= (uint64_t)val << 32;
-        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
-                                        regs.tdwba & mask(1));
-        break;
-      case REG_RXCSUM:
-        regs.rxcsum = val;
-        break;
-      case REG_RLPML:
-        regs.rlpml = val;
-        break;
-      case REG_RFCTL:
-        regs.rfctl = val;
-        if (regs.rfctl.exsten())
-            panic("Extended RX descriptors not implemented\n");
-        break;
-      case REG_MANC:
-        regs.manc = val;
-        break;
-      case REG_SWSM:
-        regs.swsm = val;
-        if (regs.fwsm.eep_fw_semaphore())
-            regs.swsm.swesmbi(0);
-        break;
-      case REG_SWFWSYNC:
-        regs.sw_fw_sync = val;
-        break;
-      default:
-        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
-            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
-            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4))
-            panic("Write request to unknown register number: %#x\n", daddr);
-    };
-
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-void
-IGbE::postInterrupt(IntTypes t, bool now)
-{
-    assert(t);
-
-    // Interrupt is already pending
-    if (t & regs.icr() && !now)
-        return;
-
-    regs.icr = regs.icr() | t;
-
-    Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
-    DPRINTF(EthernetIntr,
-            "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
-            curTick(), regs.itr.interval(), itr_interval);
-
-    if (regs.itr.interval() == 0 || now ||
-        lastInterrupt + itr_interval <= curTick()) {
-        if (interEvent.scheduled()) {
-            deschedule(interEvent);
-        }
-        cpuPostInt();
-    } else {
-        Tick int_time = lastInterrupt + itr_interval;
-        assert(int_time > 0);
-        DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
-                int_time);
-        if (!interEvent.scheduled()) {
-            schedule(interEvent, int_time);
-        }
-    }
-}
-
-void
-IGbE::delayIntEvent()
-{
-    cpuPostInt();
-}
-
-
-void
-IGbE::cpuPostInt()
-{
-
-    postedInterrupts++;
-
-    if (!(regs.icr() & regs.imr)) {
-        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
-        return;
-    }
-
-    DPRINTF(Ethernet, "Posting Interrupt\n");
-
-
-    if (interEvent.scheduled()) {
-        deschedule(interEvent);
-    }
-
-    if (rdtrEvent.scheduled()) {
-        regs.icr.rxt0(1);
-        deschedule(rdtrEvent);
-    }
-    if (radvEvent.scheduled()) {
-        regs.icr.rxt0(1);
-        deschedule(radvEvent);
-    }
-    if (tadvEvent.scheduled()) {
-        regs.icr.txdw(1);
-        deschedule(tadvEvent);
-    }
-    if (tidvEvent.scheduled()) {
-        regs.icr.txdw(1);
-        deschedule(tidvEvent);
-    }
-
-    regs.icr.int_assert(1);
-    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
-            regs.icr());
-
-    intrPost();
-
-    lastInterrupt = curTick();
-}
-
-void
-IGbE::cpuClearInt()
-{
-    if (regs.icr.int_assert()) {
-        regs.icr.int_assert(0);
-        DPRINTF(EthernetIntr,
-                "EINT: Clearing interrupt to CPU now. Vector %#x\n",
-                regs.icr());
-        intrClear();
-    }
-}
-
-void
-IGbE::chkInterrupt()
-{
-    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
-            regs.imr);
-    // Check if we need to clear the cpu interrupt
-    if (!(regs.icr() & regs.imr)) {
-        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
-        if (interEvent.scheduled())
-            deschedule(interEvent);
-        if (regs.icr.int_assert())
-            cpuClearInt();
-    }
-    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
-            regs.itr(), regs.itr.interval());
-
-    if (regs.icr() & regs.imr) {
-        if (regs.itr.interval() == 0)  {
-            cpuPostInt();
-        } else {
-            DPRINTF(Ethernet,
-                    "Possibly scheduling interrupt because of imr write\n");
-            if (!interEvent.scheduled()) {
-                Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
-                DPRINTF(Ethernet, "Scheduling for %d\n", t);
-                schedule(interEvent, t);
-            }
-        }
-    }
-}
-
-
-///////////////////////////// IGbE::DescCache //////////////////////////////
-
-template<class T>
-IGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
-    : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
-      wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
-      wbDelayEvent(this), fetchDelayEvent(this), fetchEvent(this),
-      wbEvent(this)
-{
-    fetchBuf = new T[size];
-    wbBuf = new T[size];
-}
-
-template<class T>
-IGbE::DescCache<T>::~DescCache()
-{
-    reset();
-    delete[] fetchBuf;
-    delete[] wbBuf;
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::areaChanged()
-{
-    if (usedCache.size() > 0 || curFetching || wbOut)
-        panic("Descriptor Address, Length or Head changed. Bad\n");
-    reset();
-
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::writeback(Addr aMask)
-{
-    int curHead = descHead();
-    int max_to_wb = usedCache.size();
-
-    // Check if this writeback is less restrictive that the previous
-    // and if so setup another one immediately following it
-    if (wbOut) {
-        if (aMask < wbAlignment) {
-            moreToWb = true;
-            wbAlignment = aMask;
-        }
-        DPRINTF(EthernetDesc,
-                "Writing back already in process, returning\n");
-        return;
-    }
-
-    moreToWb = false;
-    wbAlignment = aMask;
-   
-
-    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
-            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
-            curHead, descTail(), descLen(), cachePnt, max_to_wb,
-            descLeft());
-
-    if (max_to_wb + curHead >= descLen()) {
-        max_to_wb = descLen() - curHead;
-        moreToWb = true;
-        // this is by definition aligned correctly
-    } else if (wbAlignment != 0) {
-        // align the wb point to the mask
-        max_to_wb = max_to_wb & ~wbAlignment;
-    }
-
-    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
-
-    if (max_to_wb <= 0) {
-        if (usedCache.size())
-            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
-        else
-            igbe->anWe(annSmWb, annUsedCacheQ);
-        return;
-    }
-
-    wbOut = max_to_wb;
-
-    assert(!wbDelayEvent.scheduled()); 
-    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
-    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
-}
-            
-template<class T>
-void
-IGbE::DescCache<T>::writeback1()
-{
-    // If we're draining delay issuing this DMA
-    if (igbe->drainState() != DrainState::Running) {
-        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
-        return;
-    }
-
-    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
-            
-    for (int x = 0; x < wbOut; x++) {
-        assert(usedCache.size());
-        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
-        igbe->anPq(annSmWb, annUsedCacheQ);
-        igbe->anPq(annSmWb, annDescQ);
-        igbe->anQ(annSmWb, annUsedDescQ);
-    }
-
-    
-    igbe->anBegin(annSmWb, "Writeback Desc DMA");
-
-    assert(wbOut);
-    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
-                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
-                   igbe->wbCompDelay);
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::fetchDescriptors()
-{
-    size_t max_to_fetch;
-
-    if (curFetching) {
-        DPRINTF(EthernetDesc,
-                "Currently fetching %d descriptors, returning\n",
-                curFetching);
-        return;
-    }
-
-    if (descTail() >= cachePnt)
-        max_to_fetch = descTail() - cachePnt;
-    else
-        max_to_fetch = descLen() - cachePnt;
-
-    size_t free_cache = size - usedCache.size() - unusedCache.size();
-
-    if (!max_to_fetch)
-        igbe->anWe(annSmFetch, annUnusedDescQ);
-    else
-        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
-
-    if (max_to_fetch) {
-        if (!free_cache)
-            igbe->anWf(annSmFetch, annDescQ);
-        else
-            igbe->anRq(annSmFetch, annDescQ, free_cache);
-    }
-
-    max_to_fetch = std::min(max_to_fetch, free_cache);
-            
-
-    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
-            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
-            descHead(), descTail(), descLen(), cachePnt,
-            max_to_fetch, descLeft());
-
-    // Nothing to do
-    if (max_to_fetch == 0)
-        return;
-            
-    // So we don't have two descriptor fetches going on at once
-    curFetching = max_to_fetch;
-
-    assert(!fetchDelayEvent.scheduled());
-    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
-    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::fetchDescriptors1()
-{
-    // If we're draining delay issuing this DMA
-    if (igbe->drainState() != DrainState::Running) {
-        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
-        return;
-    }
-
-    igbe->anBegin(annSmFetch, "Fetch Desc");
-
-    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
-            descBase() + cachePnt * sizeof(T),
-            pciToDma(descBase() + cachePnt * sizeof(T)),
-            curFetching * sizeof(T));
-    assert(curFetching);
-    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
-                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
-                  igbe->fetchCompDelay);
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::fetchComplete()
-{
-    T *newDesc;
-    igbe->anBegin(annSmFetch, "Fetch Complete");
-    for (int x = 0; x < curFetching; x++) {
-        newDesc = new T;
-        memcpy(newDesc, &fetchBuf[x], sizeof(T));
-        unusedCache.push_back(newDesc);
-        igbe->anDq(annSmFetch, annUnusedDescQ);
-        igbe->anQ(annSmFetch, annUnusedCacheQ);
-        igbe->anQ(annSmFetch, annDescQ);
-    }
-
-
-#ifndef NDEBUG
-    int oldCp = cachePnt;
-#endif
-
-    cachePnt += curFetching;
-    assert(cachePnt <= descLen());
-    if (cachePnt == descLen())
-        cachePnt = 0;
-
-    curFetching = 0;
-
-    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
-            oldCp, cachePnt);
-
-    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
-                                                             cachePnt)) == 0)
-    {
-        igbe->anWe(annSmFetch, annUnusedDescQ);
-    } else if (!(size - usedCache.size() - unusedCache.size())) {
-        igbe->anWf(annSmFetch, annDescQ);
-    } else {
-        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
-    }
-
-    enableSm();
-    igbe->checkDrain();
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::wbComplete()
-{
-
-    igbe->anBegin(annSmWb, "Finish Writeback");
-
-    long  curHead = descHead();
-#ifndef NDEBUG
-    long oldHead = curHead;
-#endif
-            
-    for (int x = 0; x < wbOut; x++) {
-        assert(usedCache.size());
-        delete usedCache[0];
-        usedCache.pop_front();
-
-        igbe->anDq(annSmWb, annUsedCacheQ);
-        igbe->anDq(annSmWb, annDescQ);
-    }
-
-    curHead += wbOut;
-    wbOut = 0;
-
-    if (curHead >= descLen())
-        curHead -= descLen();
-
-    // Update the head
-    updateHead(curHead);
-
-    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
-            oldHead, curHead);
-
-    // If we still have more to wb, call wb now
-    actionAfterWb();
-    if (moreToWb) {
-        moreToWb = false;
-        DPRINTF(EthernetDesc, "Writeback has more todo\n");
-        writeback(wbAlignment);
-    }
-
-    if (!wbOut) {
-        igbe->checkDrain();
-        if (usedCache.size())
-            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
-        else
-            igbe->anWe(annSmWb, annUsedCacheQ);
-    }
-    fetchAfterWb();
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::reset()
-{
-    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
-    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
-        delete usedCache[x];
-    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
-        delete unusedCache[x];
-
-    usedCache.clear();
-    unusedCache.clear();
-
-    cachePnt = 0;
-
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::serialize(CheckpointOut &cp) const
-{
-    SERIALIZE_SCALAR(cachePnt);
-    SERIALIZE_SCALAR(curFetching);
-    SERIALIZE_SCALAR(wbOut);
-    SERIALIZE_SCALAR(moreToWb);
-    SERIALIZE_SCALAR(wbAlignment);
-
-    typename CacheType::size_type usedCacheSize = usedCache.size();
-    SERIALIZE_SCALAR(usedCacheSize);
-    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
-        arrayParamOut(cp, csprintf("usedCache_%d", x),
-                      (uint8_t*)usedCache[x],sizeof(T));
-    }
-
-    typename CacheType::size_type unusedCacheSize = unusedCache.size();
-    SERIALIZE_SCALAR(unusedCacheSize);
-    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
-        arrayParamOut(cp, csprintf("unusedCache_%d", x),
-                      (uint8_t*)unusedCache[x],sizeof(T));
-    }
-
-    Tick fetch_delay = 0, wb_delay = 0;
-    if (fetchDelayEvent.scheduled())
-        fetch_delay = fetchDelayEvent.when();
-    SERIALIZE_SCALAR(fetch_delay);
-    if (wbDelayEvent.scheduled())
-        wb_delay = wbDelayEvent.when();
-    SERIALIZE_SCALAR(wb_delay);
-
-
-}
-
-template<class T>
-void
-IGbE::DescCache<T>::unserialize(CheckpointIn &cp)
-{
-    UNSERIALIZE_SCALAR(cachePnt);
-    UNSERIALIZE_SCALAR(curFetching);
-    UNSERIALIZE_SCALAR(wbOut);
-    UNSERIALIZE_SCALAR(moreToWb);
-    UNSERIALIZE_SCALAR(wbAlignment);
-
-    typename CacheType::size_type usedCacheSize;
-    UNSERIALIZE_SCALAR(usedCacheSize);
-    T *temp;
-    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
-        temp = new T;
-        arrayParamIn(cp, csprintf("usedCache_%d", x),
-                     (uint8_t*)temp,sizeof(T));
-        usedCache.push_back(temp);
-    }
-
-    typename CacheType::size_type unusedCacheSize;
-    UNSERIALIZE_SCALAR(unusedCacheSize);
-    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
-        temp = new T;
-        arrayParamIn(cp, csprintf("unusedCache_%d", x),
-                     (uint8_t*)temp,sizeof(T));
-        unusedCache.push_back(temp);
-    }
-    Tick fetch_delay = 0, wb_delay = 0;
-    UNSERIALIZE_SCALAR(fetch_delay);
-    UNSERIALIZE_SCALAR(wb_delay);
-    if (fetch_delay)
-        igbe->schedule(fetchDelayEvent, fetch_delay);
-    if (wb_delay)
-        igbe->schedule(wbDelayEvent, wb_delay);
-
-
-}
-
-///////////////////////////// IGbE::RxDescCache //////////////////////////////
-
-IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
-    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), 
-      pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
-
-{
-    annSmFetch = "RX Desc Fetch";
-    annSmWb = "RX Desc Writeback";
-    annUnusedDescQ = "RX Unused Descriptors";
-    annUnusedCacheQ = "RX Unused Descriptor Cache";
-    annUsedCacheQ = "RX Used Descriptor Cache";
-    annUsedDescQ = "RX Used Descriptors";
-    annDescQ = "RX Descriptors";
-}
-
-void
-IGbE::RxDescCache::pktSplitDone()
-{
-    splitCount++;
-    DPRINTF(EthernetDesc,
-            "Part of split packet done: splitcount now %d\n", splitCount);
-    assert(splitCount <= 2);
-    if (splitCount != 2)
-        return;
-    splitCount = 0;
-    DPRINTF(EthernetDesc,
-            "Part of split packet done: calling pktComplete()\n");
-    pktComplete();
-}
-
-int
-IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
-{
-    assert(unusedCache.size());
-    //if (!unusedCache.size())
-    //    return false;
-
-    pktPtr = packet;
-    pktDone = false;
-    unsigned buf_len, hdr_len;
-
-    RxDesc *desc = unusedCache.front();
-    switch (igbe->regs.srrctl.desctype()) {
-      case RXDT_LEGACY:
-        assert(pkt_offset == 0);
-        bytesCopied = packet->length;
-        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
-                packet->length, igbe->regs.rctl.descSize());
-        assert(packet->length < igbe->regs.rctl.descSize());
-        igbe->dmaWrite(pciToDma(desc->legacy.buf),
-                       packet->length, &pktEvent, packet->data,
-                       igbe->rxWriteDelay);
-        break;
-      case RXDT_ADV_ONEBUF:
-        assert(pkt_offset == 0);
-        bytesCopied = packet->length;
-        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
-            igbe->regs.rctl.descSize();
-        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
-                packet->length, igbe->regs.srrctl(), buf_len);
-        assert(packet->length < buf_len);
-        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
-                       packet->length, &pktEvent, packet->data,
-                       igbe->rxWriteDelay);
-        desc->adv_wb.header_len = htole(0);
-        desc->adv_wb.sph = htole(0);
-        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
-        break;
-      case RXDT_ADV_SPLIT_A:
-        int split_point;
-        
-        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
-            igbe->regs.rctl.descSize();
-        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; 
-        DPRINTF(EthernetDesc,
-                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
-                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
-                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
-                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
-                desc->adv_read.pkt, buf_len);
-
-        split_point = hsplit(pktPtr);
-
-        if (packet->length <= hdr_len) {
-            bytesCopied = packet->length;
-            assert(pkt_offset == 0);
-            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
-            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
-                           packet->length, &pktEvent, packet->data,
-                           igbe->rxWriteDelay);
-            desc->adv_wb.header_len = htole((uint16_t)packet->length);
-            desc->adv_wb.sph = htole(0);
-            desc->adv_wb.pkt_len = htole(0);
-        } else if (split_point) {
-            if (pkt_offset) {
-                // we are only copying some data, header/data has already been
-                // copied
-                int max_to_copy =
-                    std::min(packet->length - pkt_offset, buf_len);
-                bytesCopied += max_to_copy;
-                DPRINTF(EthernetDesc,
-                        "Hdr split: Continuing data buffer copy\n");
-                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
-                               max_to_copy, &pktEvent,
-                               packet->data + pkt_offset, igbe->rxWriteDelay);
-                desc->adv_wb.header_len = htole(0);
-                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
-                desc->adv_wb.sph = htole(0);
-            } else {
-                int max_to_copy =
-                    std::min(packet->length - split_point, buf_len);
-                bytesCopied += max_to_copy + split_point;
-                
-                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
-                        split_point);
-                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
-                               split_point, &pktHdrEvent,
-                               packet->data, igbe->rxWriteDelay);
-                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
-                               max_to_copy, &pktDataEvent,
-                               packet->data + split_point, igbe->rxWriteDelay);
-                desc->adv_wb.header_len = htole(split_point);
-                desc->adv_wb.sph = 1;
-                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
-            }
-        } else {
-            panic("Header split not fitting within header buffer or "
-                  "undecodable packet not fitting in header unsupported\n");
-        }
-        break;
-      default:
-        panic("Unimplemnted RX receive buffer type: %d\n",
-              igbe->regs.srrctl.desctype());
-    }
-    return bytesCopied;
-
-}
-
-void
-IGbE::RxDescCache::pktComplete()
-{
-    assert(unusedCache.size());
-    RxDesc *desc;
-    desc = unusedCache.front();
-
-    igbe->anBegin("RXS", "Update Desc");
-
-    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
-    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
-            "stripcrc offset: %d value written: %d %d\n",
-            pktPtr->length, bytesCopied, crcfixup,
-            htole((uint16_t)(pktPtr->length + crcfixup)),
-            (uint16_t)(pktPtr->length + crcfixup));
-
-    // no support for anything but starting at 0
-    assert(igbe->regs.rxcsum.pcss() == 0);
-
-    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
-
-    uint16_t status = RXDS_DD;
-    uint8_t err = 0;
-    uint16_t ext_err = 0;
-    uint16_t csum = 0;
-    uint16_t ptype = 0;
-    uint16_t ip_id = 0;
-
-    assert(bytesCopied <= pktPtr->length);
-    if (bytesCopied == pktPtr->length)
-        status |= RXDS_EOP;
-
-    IpPtr ip(pktPtr);
-
-    if (ip) {
-        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
-        ptype |= RXDP_IPV4;
-        ip_id = ip->id();
-
-        if (igbe->regs.rxcsum.ipofld()) {
-            DPRINTF(EthernetDesc, "Checking IP checksum\n");
-            status |= RXDS_IPCS;
-            csum = htole(cksum(ip));
-            igbe->rxIpChecksums++;
-            if (cksum(ip) != 0) {
-                err |= RXDE_IPE;
-                ext_err |= RXDEE_IPE;
-                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
-            }
-        }
-        TcpPtr tcp(ip);
-        if (tcp && igbe->regs.rxcsum.tuofld()) {
-            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
-            status |= RXDS_TCPCS;
-            ptype |= RXDP_TCP;
-            csum = htole(cksum(tcp));
-            igbe->rxTcpChecksums++;
-            if (cksum(tcp) != 0) {
-                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
-                err |= RXDE_TCPE;
-                ext_err |= RXDEE_TCPE;
-            }
-        }
-
-        UdpPtr udp(ip);
-        if (udp && igbe->regs.rxcsum.tuofld()) {
-            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
-            status |= RXDS_UDPCS;
-            ptype |= RXDP_UDP;
-            csum = htole(cksum(udp));
-            igbe->rxUdpChecksums++;
-            if (cksum(udp) != 0) {
-                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
-                ext_err |= RXDEE_TCPE;
-                err |= RXDE_TCPE;
-            }
-        }
-    } else { // if ip
-        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
-    }
-
-    switch (igbe->regs.srrctl.desctype()) {
-      case RXDT_LEGACY:
-        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
-        desc->legacy.status = htole(status);
-        desc->legacy.errors = htole(err);
-        // No vlan support at this point... just set it to 0
-        desc->legacy.vlan = 0;
-        break;
-      case RXDT_ADV_SPLIT_A:
-      case RXDT_ADV_ONEBUF:
-        desc->adv_wb.rss_type = htole(0);
-        desc->adv_wb.pkt_type = htole(ptype);
-        if (igbe->regs.rxcsum.pcsd()) {
-            // no rss support right now
-            desc->adv_wb.rss_hash = htole(0);
-        } else {
-            desc->adv_wb.id = htole(ip_id);
-            desc->adv_wb.csum = htole(csum);
-        }
-        desc->adv_wb.status = htole(status);
-        desc->adv_wb.errors = htole(ext_err);
-        // no vlan support
-        desc->adv_wb.vlan_tag = htole(0); 
-        break;
-      default:
-        panic("Unimplemnted RX receive buffer type %d\n",
-              igbe->regs.srrctl.desctype());
-    }
-
-    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
-            desc->adv_read.pkt, desc->adv_read.hdr);
-
-    if (bytesCopied == pktPtr->length) {
-        DPRINTF(EthernetDesc,
-                "Packet completely written to descriptor buffers\n");
-        // Deal with the rx timer interrupts
-        if (igbe->regs.rdtr.delay()) {
-            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
-            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
-            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
-        }
-
-        if (igbe->regs.radv.idv()) {
-            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
-            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
-            if (!igbe->radvEvent.scheduled()) {
-                igbe->schedule(igbe->radvEvent, curTick() + delay);
-            }
-        }
-
-        // if neither radv or rdtr, maybe itr is set...
-        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
-            DPRINTF(EthernetSM,
-                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
-            igbe->postInterrupt(IT_RXT);
-        }
-
-        // If the packet is small enough, interrupt appropriately
-        // I wonder if this is delayed or not?!
-        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
-            DPRINTF(EthernetSM,
-                    "RXS: Posting IT_SRPD beacuse small packet received\n");
-            igbe->postInterrupt(IT_SRPD);
-        }
-        bytesCopied = 0;
-    }
-
-    pktPtr = NULL;
-    igbe->checkDrain();
-    enableSm();
-    pktDone = true;
-
-    igbe->anBegin("RXS", "Done Updating Desc");
-    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
-    igbe->anDq("RXS", annUnusedCacheQ);
-    unusedCache.pop_front();
-    igbe->anQ("RXS", annUsedCacheQ);
-    usedCache.push_back(desc);
-}
-
-void
-IGbE::RxDescCache::enableSm()
-{
-    if (igbe->drainState() != DrainState::Draining) {
-        igbe->rxTick = true;
-        igbe->restartClock();
-    }
-}
-
-bool
-IGbE::RxDescCache::packetDone()
-{
-    if (pktDone) {
-        pktDone = false;
-        return true;
-    }
-    return false;
-}
-
-bool
-IGbE::RxDescCache::hasOutstandingEvents()
-{
-    return pktEvent.scheduled() || wbEvent.scheduled() ||
-        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
-        pktDataEvent.scheduled();
-         
-}
-
-void
-IGbE::RxDescCache::serialize(CheckpointOut &cp) const
-{
-    DescCache<RxDesc>::serialize(cp);
-    SERIALIZE_SCALAR(pktDone);
-    SERIALIZE_SCALAR(splitCount);
-    SERIALIZE_SCALAR(bytesCopied);
-}
-
-void
-IGbE::RxDescCache::unserialize(CheckpointIn &cp)
-{
-    DescCache<RxDesc>::unserialize(cp);
-    UNSERIALIZE_SCALAR(pktDone);
-    UNSERIALIZE_SCALAR(splitCount);
-    UNSERIALIZE_SCALAR(bytesCopied);
-}
-
-
-///////////////////////////// IGbE::TxDescCache //////////////////////////////
-
-IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
-    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
-      pktWaiting(false), pktMultiDesc(false),
-      completionAddress(0), completionEnabled(false),
-      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
-      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
-      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
-      pktEvent(this), headerEvent(this), nullEvent(this)
-{
-    annSmFetch = "TX Desc Fetch";
-    annSmWb = "TX Desc Writeback";
-    annUnusedDescQ = "TX Unused Descriptors";
-    annUnusedCacheQ = "TX Unused Descriptor Cache";
-    annUsedCacheQ = "TX Used Descriptor Cache";
-    annUsedDescQ = "TX Used Descriptors";
-    annDescQ = "TX Descriptors";
-}
-
-void
-IGbE::TxDescCache::processContextDesc()
-{
-    assert(unusedCache.size());
-    TxDesc *desc;
-    
-    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
-
-    while (!useTso && unusedCache.size() &&
-           TxdOp::isContext(unusedCache.front())) {
-        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
-
-        desc = unusedCache.front();
-        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", 
-                desc->d1, desc->d2);
-
-        
-        // is this going to be a tcp or udp packet?
-        isTcp = TxdOp::tcp(desc) ? true : false;
-
-        // setup all the TSO variables, they'll be ignored if we don't use 
-        // tso for this connection
-        tsoHeaderLen = TxdOp::hdrlen(desc);
-        tsoMss  = TxdOp::mss(desc);
-
-        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
-            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
-                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
-                    TxdOp::mss(desc), TxdOp::getLen(desc));
-            useTso = true;
-            tsoTotalLen = TxdOp::getLen(desc);
-            tsoLoadedHeader = false;
-            tsoDescBytesUsed = 0;
-            tsoUsedLen = 0;
-            tsoPrevSeq = 0;
-            tsoPktHasHeader = false;
-            tsoPkts = 0;
-            tsoCopyBytes = 0;
-        }
-
-        TxdOp::setDd(desc);
-        unusedCache.pop_front();
-        igbe->anDq("TXS", annUnusedCacheQ);
-        usedCache.push_back(desc);
-        igbe->anQ("TXS", annUsedCacheQ);
-    }
-
-    if (!unusedCache.size())
-        return;
-
-    desc = unusedCache.front();
-    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && 
-        TxdOp::tse(desc)) {
-        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
-                "hdrlen: %d mss: %d paylen %d\n", 
-                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
-        useTso = true;
-        tsoTotalLen = TxdOp::getTsoLen(desc);
-        tsoLoadedHeader = false;
-        tsoDescBytesUsed = 0;
-        tsoUsedLen = 0;
-        tsoPrevSeq = 0;
-        tsoPktHasHeader = false;
-        tsoPkts = 0;
-    }
-
-    if (useTso && !tsoLoadedHeader) {
-        // we need to fetch a header
-        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
-        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
-        pktWaiting = true;
-        assert(tsoHeaderLen <= 256);
-        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
-                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
-    }
-}
-
-void
-IGbE::TxDescCache::headerComplete()
-{
-    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
-    pktWaiting = false;
-
-    assert(unusedCache.size());
-    TxDesc *desc = unusedCache.front();
-    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
-            TxdOp::getLen(desc), tsoHeaderLen);
-
-    if (TxdOp::getLen(desc) == tsoHeaderLen) {
-        tsoDescBytesUsed = 0;
-        tsoLoadedHeader = true;
-        unusedCache.pop_front();
-        usedCache.push_back(desc);
-    } else {
-        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
-        tsoDescBytesUsed = tsoHeaderLen;
-        tsoLoadedHeader = true;
-    }
-    enableSm();
-    igbe->checkDrain();
-}
-
-unsigned
-IGbE::TxDescCache::getPacketSize(EthPacketPtr p)
-{
-    if (!unusedCache.size())
-        return 0;
-    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
-
-    assert(!useTso || tsoLoadedHeader);
-    TxDesc *desc = unusedCache.front();
-
-    if (useTso) {
-        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
-                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
-        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
-                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
-                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
-
-        if (tsoPktHasHeader) 
-            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
-                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
-        else
-            tsoCopyBytes =  std::min(tsoMss,
-                                     TxdOp::getLen(desc) - tsoDescBytesUsed); 
-        unsigned pkt_size =
-            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); 
-
-        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
-                "this descLen: %d\n",
-                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
-        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
-        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
-        return pkt_size;
-    }
-
-    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
-            TxdOp::getLen(unusedCache.front()));
-    return TxdOp::getLen(desc);
-}
-
-void
-IGbE::TxDescCache::getPacketData(EthPacketPtr p)
-{
-    assert(unusedCache.size());
-
-    TxDesc *desc;
-    desc = unusedCache.front();
-
-    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
-            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
-    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
-           TxdOp::getLen(desc));
-
-    pktPtr = p;
-
-    pktWaiting = true;
-
-    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
-    
-    if (useTso) {
-        assert(tsoLoadedHeader);
-        if (!tsoPktHasHeader) {
-            DPRINTF(EthernetDesc,
-                    "Loading TSO header (%d bytes) into start of packet\n",
-                    tsoHeaderLen);
-            memcpy(p->data, &tsoHeader,tsoHeaderLen);
-            p->length +=tsoHeaderLen;
-            tsoPktHasHeader = true;
-        }
-    }
-  
-    if (useTso) {
-        DPRINTF(EthernetDesc,
-                "Starting DMA of packet at offset %d length: %d\n",
-                p->length, tsoCopyBytes);
-        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
-                      + tsoDescBytesUsed,
-                      tsoCopyBytes, &pktEvent, p->data + p->length,
-                      igbe->txReadDelay);
-        tsoDescBytesUsed += tsoCopyBytes;
-        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
-    } else {
-        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
-                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
-                      igbe->txReadDelay);
-    }
-}
-
-void
-IGbE::TxDescCache::pktComplete()
-{
-
-    TxDesc *desc;
-    assert(unusedCache.size());
-    assert(pktPtr);
-
-    igbe->anBegin("TXS", "Update Desc");
-
-    DPRINTF(EthernetDesc, "DMA of packet complete\n");
-
-
-    desc = unusedCache.front();
-    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
-           TxdOp::getLen(desc));
-
-    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
-            desc->d1, desc->d2);
-
-    // Set the length of the data in the EtherPacket
-    if (useTso) {
-        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
-            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
-            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
-        pktPtr->length += tsoCopyBytes;
-        tsoUsedLen += tsoCopyBytes;
-        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
-            tsoDescBytesUsed, tsoCopyBytes);
-    } else
-        pktPtr->length += TxdOp::getLen(desc);
-    
-
-
-    if ((!TxdOp::eop(desc) && !useTso) || 
-        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
-         tsoTotalLen != tsoUsedLen && useTso)) {
-        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
-        igbe->anDq("TXS", annUnusedCacheQ);
-        unusedCache.pop_front();
-        igbe->anQ("TXS", annUsedCacheQ);
-        usedCache.push_back(desc);
-
-        tsoDescBytesUsed = 0;
-        pktDone = true;
-        pktWaiting = false;
-        pktMultiDesc = true;
-
-        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
-                pktPtr->length);
-        pktPtr = NULL;
-
-        enableSm();
-        igbe->checkDrain();
-        return;
-    }
-
-
-    pktMultiDesc = false;
-    // no support for vlans
-    assert(!TxdOp::vle(desc));
-
-    // we only support single packet descriptors at this point
-    if (!useTso)
-        assert(TxdOp::eop(desc));
-
-    // set that this packet is done
-    if (TxdOp::rs(desc))
-        TxdOp::setDd(desc);
-
-    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
-            desc->d1, desc->d2);
-
-    if (useTso) {
-        IpPtr ip(pktPtr);
-        if (ip) {
-            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
-                    tsoPkts);
-            ip->id(ip->id() + tsoPkts++);
-            ip->len(pktPtr->length - EthPtr(pktPtr)->size()); 
-        
-            TcpPtr tcp(ip);
-            if (tcp) {
-                DPRINTF(EthernetDesc,
-                        "TSO: Modifying TCP header. old seq %d + %d\n",
-                        tcp->seq(), tsoPrevSeq);
-                tcp->seq(tcp->seq() + tsoPrevSeq);
-                if (tsoUsedLen != tsoTotalLen)
-                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
-            }
-            UdpPtr udp(ip);
-            if (udp) {
-                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
-                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
-            }
-        }
-        tsoPrevSeq = tsoUsedLen;
-    }
-
-    if (DTRACE(EthernetDesc)) {
-        IpPtr ip(pktPtr);
-        if (ip)
-            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
-                    ip->id());
-        else
-            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
-    }
-
-    // Checksums are only ofloaded for new descriptor types
-    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
-        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
-        IpPtr ip(pktPtr);
-        assert(ip);
-        if (TxdOp::ixsm(desc)) {
-            ip->sum(0);
-            ip->sum(cksum(ip));
-            igbe->txIpChecksums++;
-            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
-        }
-        if (TxdOp::txsm(desc)) {
-            TcpPtr tcp(ip);
-            UdpPtr udp(ip);
-            if (tcp) {
-                tcp->sum(0);
-                tcp->sum(cksum(tcp));
-                igbe->txTcpChecksums++;
-                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
-            } else if (udp) {
-                assert(udp);
-                udp->sum(0);
-                udp->sum(cksum(udp));
-                igbe->txUdpChecksums++;
-                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
-            } else {
-                panic("Told to checksum, but don't know how\n");
-            }
-        }
-    }
-
-    if (TxdOp::ide(desc)) {
-        // Deal with the rx timer interrupts
-        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
-        if (igbe->regs.tidv.idv()) {
-            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
-            DPRINTF(EthernetDesc, "setting tidv\n");
-            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
-        }
-
-        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
-            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
-            DPRINTF(EthernetDesc, "setting tadv\n");
-            if (!igbe->tadvEvent.scheduled()) {
-                igbe->schedule(igbe->tadvEvent, curTick() + delay);
-            }
-        }
-    }
-
-
-    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
-        DPRINTF(EthernetDesc, "Descriptor Done\n");
-        igbe->anDq("TXS", annUnusedCacheQ);
-        unusedCache.pop_front();
-        igbe->anQ("TXS", annUsedCacheQ);
-        usedCache.push_back(desc);
-        tsoDescBytesUsed = 0;
-    }
-
-    if (useTso && tsoUsedLen == tsoTotalLen)
-        useTso = false;
-
-
-    DPRINTF(EthernetDesc,
-            "------Packet of %d bytes ready for transmission-------\n",
-            pktPtr->length);
-    pktDone = true;
-    pktWaiting = false;
-    pktPtr = NULL;
-    tsoPktHasHeader = false;
-
-    if (igbe->regs.txdctl.wthresh() == 0) {
-        igbe->anBegin("TXS", "Desc Writeback");
-        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
-        writeback(0);
-    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
-               descInBlock(usedCache.size())) {
-        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
-        igbe->anBegin("TXS", "Desc Writeback");
-        writeback((igbe->cacheBlockSize()-1)>>4);
-    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
-        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
-        igbe->anBegin("TXS", "Desc Writeback");
-        writeback((igbe->cacheBlockSize()-1)>>4);
-    }
-
-    enableSm();
-    igbe->checkDrain();
-}
-
-void
-IGbE::TxDescCache::actionAfterWb() 
-{
-    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
-            completionEnabled);
-    igbe->postInterrupt(iGbReg::IT_TXDW);
-    if (completionEnabled) { 
-        descEnd = igbe->regs.tdh();
-        DPRINTF(EthernetDesc,
-                "Completion writing back value: %d to addr: %#x\n", descEnd,
-                completionAddress);
-        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
-                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
-    }
-}
-
-void
-IGbE::TxDescCache::serialize(CheckpointOut &cp) const
-{
-    DescCache<TxDesc>::serialize(cp);
-
-    SERIALIZE_SCALAR(pktDone);
-    SERIALIZE_SCALAR(isTcp);
-    SERIALIZE_SCALAR(pktWaiting);
-    SERIALIZE_SCALAR(pktMultiDesc);
-
-    SERIALIZE_SCALAR(useTso);
-    SERIALIZE_SCALAR(tsoHeaderLen);
-    SERIALIZE_SCALAR(tsoMss);
-    SERIALIZE_SCALAR(tsoTotalLen);
-    SERIALIZE_SCALAR(tsoUsedLen);
-    SERIALIZE_SCALAR(tsoPrevSeq);;
-    SERIALIZE_SCALAR(tsoPktPayloadBytes);
-    SERIALIZE_SCALAR(tsoLoadedHeader);
-    SERIALIZE_SCALAR(tsoPktHasHeader);
-    SERIALIZE_ARRAY(tsoHeader, 256);
-    SERIALIZE_SCALAR(tsoDescBytesUsed);
-    SERIALIZE_SCALAR(tsoCopyBytes);
-    SERIALIZE_SCALAR(tsoPkts);
-
-    SERIALIZE_SCALAR(completionAddress);
-    SERIALIZE_SCALAR(completionEnabled);
-    SERIALIZE_SCALAR(descEnd);
-}
-
-void
-IGbE::TxDescCache::unserialize(CheckpointIn &cp)
-{
-    DescCache<TxDesc>::unserialize(cp);
-
-    UNSERIALIZE_SCALAR(pktDone);
-    UNSERIALIZE_SCALAR(isTcp);
-    UNSERIALIZE_SCALAR(pktWaiting);
-    UNSERIALIZE_SCALAR(pktMultiDesc);
-
-    UNSERIALIZE_SCALAR(useTso);
-    UNSERIALIZE_SCALAR(tsoHeaderLen);
-    UNSERIALIZE_SCALAR(tsoMss);
-    UNSERIALIZE_SCALAR(tsoTotalLen);
-    UNSERIALIZE_SCALAR(tsoUsedLen);
-    UNSERIALIZE_SCALAR(tsoPrevSeq);;
-    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
-    UNSERIALIZE_SCALAR(tsoLoadedHeader);
-    UNSERIALIZE_SCALAR(tsoPktHasHeader);
-    UNSERIALIZE_ARRAY(tsoHeader, 256);
-    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
-    UNSERIALIZE_SCALAR(tsoCopyBytes);
-    UNSERIALIZE_SCALAR(tsoPkts);
-
-    UNSERIALIZE_SCALAR(completionAddress);
-    UNSERIALIZE_SCALAR(completionEnabled);
-    UNSERIALIZE_SCALAR(descEnd);
-}
-
-bool
-IGbE::TxDescCache::packetAvailable()
-{
-    if (pktDone) {
-        pktDone = false;
-        return true;
-    }
-    return false;
-}
-
-void
-IGbE::TxDescCache::enableSm()
-{
-    if (igbe->drainState() != DrainState::Draining) {
-        igbe->txTick = true;
-        igbe->restartClock();
-    }
-}
-
-bool
-IGbE::TxDescCache::hasOutstandingEvents()
-{
-    return pktEvent.scheduled() || wbEvent.scheduled() ||
-        fetchEvent.scheduled();
-}
-
-
-///////////////////////////////////// IGbE /////////////////////////////////
-
-void
-IGbE::restartClock()
-{
-    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
-        drainState() == DrainState::Running)
-        schedule(tickEvent, clockEdge(Cycles(1)));
-}
-
-DrainState
-IGbE::drain()
-{
-    unsigned int count(0);
-    if (rxDescCache.hasOutstandingEvents() ||
-        txDescCache.hasOutstandingEvents()) {
-        count++;
-    }
-
-    txFifoTick = false;
-    txTick = false;
-    rxTick = false;
-
-    if (tickEvent.scheduled())
-        deschedule(tickEvent);
-
-    if (count) {
-        DPRINTF(Drain, "IGbE not drained\n");
-        return DrainState::Draining;
-    } else
-        return DrainState::Drained;
-}
-
-void
-IGbE::drainResume()
-{
-    Drainable::drainResume();
-
-    txFifoTick = true;
-    txTick = true;
-    rxTick = true;
-
-    restartClock();
-    DPRINTF(EthernetSM, "resuming from drain");
-}
-
-void
-IGbE::checkDrain()
-{
-    if (drainState() != DrainState::Draining)
-        return;
-
-    txFifoTick = false;
-    txTick = false;
-    rxTick = false;
-    if (!rxDescCache.hasOutstandingEvents() &&
-        !txDescCache.hasOutstandingEvents()) {
-        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
-        signalDrainDone();
-    }
-}
-
-void
-IGbE::txStateMachine()
-{
-    if (!regs.tctl.en()) {
-        txTick = false;
-        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
-        return;
-    }
-
-    // If we have a packet available and it's length is not 0 (meaning it's not
-    // a multidescriptor packet) put it in the fifo, otherwise an the next
-    // iteration we'll get the rest of the data
-    if (txPacket && txDescCache.packetAvailable()
-        && !txDescCache.packetMultiDesc() && txPacket->length) {
-        anQ("TXS", "TX FIFO Q");
-        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
-#ifndef NDEBUG
-        bool success =
-#endif
-            txFifo.push(txPacket);
-        txFifoTick = true && drainState() != DrainState::Draining;
-        assert(success);
-        txPacket = NULL;
-        anBegin("TXS", "Desc Writeback");
-        txDescCache.writeback((cacheBlockSize()-1)>>4);
-        return;
-    }
-
-    // Only support descriptor granularity
-    if (regs.txdctl.lwthresh() &&
-        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
-        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
-        postInterrupt(IT_TXDLOW);
-    }
-
-    if (!txPacket) {
-        txPacket = std::make_shared<EthPacketData>(16384);
-    }
-
-    if (!txDescCache.packetWaiting()) {
-        if (txDescCache.descLeft() == 0) {
-            postInterrupt(IT_TXQE);
-            anBegin("TXS", "Desc Writeback");
-            txDescCache.writeback(0);
-            anBegin("TXS", "Desc Fetch");
-            anWe("TXS", txDescCache.annUnusedCacheQ);
-            txDescCache.fetchDescriptors();
-            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
-                    "writeback stopping ticking and posting TXQE\n");
-            txTick = false;
-            return;
-        }
-
-
-        if (!(txDescCache.descUnused())) {
-            anBegin("TXS", "Desc Fetch");
-            txDescCache.fetchDescriptors();
-            anWe("TXS", txDescCache.annUnusedCacheQ);
-            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
-                    "fetching and stopping ticking\n");
-            txTick = false;
-            return;
-        }
-        anPq("TXS", txDescCache.annUnusedCacheQ);
-
-
-        txDescCache.processContextDesc();
-        if (txDescCache.packetWaiting()) {
-            DPRINTF(EthernetSM,
-                    "TXS: Fetching TSO header, stopping ticking\n");
-            txTick = false;
-            return;
-        }
-
-        unsigned size = txDescCache.getPacketSize(txPacket);
-        if (size > 0 && txFifo.avail() > size) {
-            anRq("TXS", "TX FIFO Q");
-            anBegin("TXS", "DMA Packet");
-            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
-                    "beginning DMA of next packet\n", size);
-            txFifo.reserve(size);
-            txDescCache.getPacketData(txPacket);
-        } else if (size == 0) {
-            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
-            DPRINTF(EthernetSM,
-                    "TXS: No packets to get, writing back used descriptors\n");
-            anBegin("TXS", "Desc Writeback");
-            txDescCache.writeback(0);
-        } else {
-            anWf("TXS", "TX FIFO Q");
-            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
-                    "available in FIFO\n");
-            txTick = false;
-        }
-
-
-        return;
-    }
-    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
-    txTick = false;
-}
-
-bool
-IGbE::ethRxPkt(EthPacketPtr pkt)
-{
-    rxBytes += pkt->length;
-    rxPackets++;
-
-    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
-    anBegin("RXQ", "Wire Recv");
-
-
-    if (!regs.rctl.en()) {
-        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
-        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
-        return true;
-    }
-
-    // restart the state machines if they are stopped
-    rxTick = true && drainState() != DrainState::Draining;
-    if ((rxTick || txTick) && !tickEvent.scheduled()) {
-        DPRINTF(EthernetSM,
-                "RXS: received packet into fifo, starting ticking\n");
-        restartClock();
-    }
-
-    if (!rxFifo.push(pkt)) {
-        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
-        postInterrupt(IT_RXO, true);
-        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
-        return false;
-    }
-
-    if (CPA::available() && cpa->enabled()) {
-        assert(sys->numSystemsRunning <= 2);
-        System *other_sys;
-        if (sys->systemList[0] == sys)
-            other_sys = sys->systemList[1];
-        else
-            other_sys = sys->systemList[0];
-
-        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
-        anQ("RXQ", "RX FIFO Q");
-        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
-    }
-
-    return true;
-}
-
-
-void
-IGbE::rxStateMachine()
-{
-    if (!regs.rctl.en()) {
-        rxTick = false;
-        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
-        return;
-    }
-
-    // If the packet is done check for interrupts/descriptors/etc
-    if (rxDescCache.packetDone()) {
-        rxDmaPacket = false;
-        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
-        int descLeft = rxDescCache.descLeft();
-        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
-                descLeft, regs.rctl.rdmts(), regs.rdlen());
-        switch (regs.rctl.rdmts()) {
-          case 2: if (descLeft > .125 * regs.rdlen()) break;
-          case 1: if (descLeft > .250 * regs.rdlen()) break;
-          case 0: if (descLeft > .500 * regs.rdlen())  break;
-            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
-                    "because of descriptors left\n");
-            postInterrupt(IT_RXDMT);
-            break;
-        }
-
-        if (rxFifo.empty())
-            rxDescCache.writeback(0);
-
-        if (descLeft == 0) {
-            anBegin("RXS", "Writeback Descriptors");
-            rxDescCache.writeback(0);
-            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
-                    " writeback and stopping ticking\n");
-            rxTick = false;
-        }
-
-        // only support descriptor granulaties
-        assert(regs.rxdctl.gran());
-
-        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
-            DPRINTF(EthernetSM,
-                    "RXS: Writing back because WTHRESH >= descUsed\n");
-            anBegin("RXS", "Writeback Descriptors");
-            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
-                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
-            else
-                rxDescCache.writeback((cacheBlockSize()-1)>>4);
-        }
-
-        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
-            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
-             regs.rxdctl.hthresh())) {
-            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
-                    "descUnused < PTHRESH\n");
-            anBegin("RXS", "Fetch Descriptors");
-            rxDescCache.fetchDescriptors();
-        }
-
-        if (rxDescCache.descUnused() == 0) {
-            anBegin("RXS", "Fetch Descriptors");
-            rxDescCache.fetchDescriptors();
-            anWe("RXS", rxDescCache.annUnusedCacheQ);
-            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
-                    "fetching descriptors and stopping ticking\n");
-            rxTick = false;
-        }
-        return;
-    }
-
-    if (rxDmaPacket) {
-        DPRINTF(EthernetSM,
-                "RXS: stopping ticking until packet DMA completes\n");
-        rxTick = false;
-        return;
-    }
-
-    if (!rxDescCache.descUnused()) {
-        anBegin("RXS", "Fetch Descriptors");
-        rxDescCache.fetchDescriptors();
-        anWe("RXS", rxDescCache.annUnusedCacheQ);
-        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
-                "stopping ticking\n");
-        rxTick = false;
-        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
-        return;
-    }
-    anPq("RXS", rxDescCache.annUnusedCacheQ);
-
-    if (rxFifo.empty()) {
-        anWe("RXS", "RX FIFO Q");
-        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
-        rxTick = false;
-        return;
-    }
-    anPq("RXS", "RX FIFO Q");
-    anBegin("RXS", "Get Desc");
-
-    EthPacketPtr pkt;
-    pkt = rxFifo.front();
-
-
-    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
-    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
-    if (pktOffset == pkt->length) {
-        anBegin( "RXS", "FIFO Dequeue");
-        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
-        pktOffset = 0;
-        anDq("RXS", "RX FIFO Q");
-        rxFifo.pop();
-    }
-
-    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
-    rxTick = false;
-    rxDmaPacket = true;
-    anBegin("RXS", "DMA Packet");
-}
-
-void
-IGbE::txWire()
-{
-    if (txFifo.empty()) {
-        anWe("TXQ", "TX FIFO Q");
-        txFifoTick = false;
-        return;
-    }
-
-
-    anPq("TXQ", "TX FIFO Q");
-    if (etherInt->sendPacket(txFifo.front())) {
-        anQ("TXQ", "WireQ");
-        if (DTRACE(EthernetSM)) {
-            IpPtr ip(txFifo.front());
-            if (ip)
-                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
-                        ip->id());
-            else
-                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
-        }
-        anDq("TXQ", "TX FIFO Q");
-        anBegin("TXQ", "Wire Send");
-        DPRINTF(EthernetSM,
-                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
-                txFifo.avail());
-
-        txBytes += txFifo.front()->length;
-        txPackets++;
-        txFifoTick = false;
-
-        txFifo.pop();
-    } else {
-        // We'll get woken up when the packet ethTxDone() gets called
-        txFifoTick = false;
-    }
-}
-
-void
-IGbE::tick()
-{
-    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
-
-    if (rxTick)
-        rxStateMachine();
-
-    if (txTick)
-        txStateMachine();
-
-    if (txFifoTick)
-        txWire();
-
-
-    if (rxTick || txTick || txFifoTick)
-        schedule(tickEvent, curTick() + clockPeriod());
-}
-
-void
-IGbE::ethTxDone()
-{
-    anBegin("TXQ", "Send Done");
-    // restart the tx state machines if they are stopped
-    // fifo to send another packet
-    // tx sm to put more data into the fifo
-    txFifoTick = true && drainState() != DrainState::Draining;
-    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
-        txTick = true;
-
-    restartClock();
-    txWire();
-    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
-}
-
-void
-IGbE::serialize(CheckpointOut &cp) const
-{
-    PciDevice::serialize(cp);
-
-    regs.serialize(cp);
-    SERIALIZE_SCALAR(eeOpBits);
-    SERIALIZE_SCALAR(eeAddrBits);
-    SERIALIZE_SCALAR(eeDataBits);
-    SERIALIZE_SCALAR(eeOpcode);
-    SERIALIZE_SCALAR(eeAddr);
-    SERIALIZE_SCALAR(lastInterrupt);
-    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
-
-    rxFifo.serialize("rxfifo", cp);
-    txFifo.serialize("txfifo", cp);
-
-    bool txPktExists = txPacket != nullptr;
-    SERIALIZE_SCALAR(txPktExists);
-    if (txPktExists)
-        txPacket->serialize("txpacket", cp);
-
-    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
-        inter_time = 0;
-
-    if (rdtrEvent.scheduled())
-        rdtr_time = rdtrEvent.when();
-    SERIALIZE_SCALAR(rdtr_time);
-
-    if (radvEvent.scheduled())
-        radv_time = radvEvent.when();
-    SERIALIZE_SCALAR(radv_time);
-
-    if (tidvEvent.scheduled())
-        tidv_time = tidvEvent.when();
-    SERIALIZE_SCALAR(tidv_time);
-
-    if (tadvEvent.scheduled())
-        tadv_time = tadvEvent.when();
-    SERIALIZE_SCALAR(tadv_time);
-
-    if (interEvent.scheduled())
-        inter_time = interEvent.when();
-    SERIALIZE_SCALAR(inter_time);
-
-    SERIALIZE_SCALAR(pktOffset);
-
-    txDescCache.serializeSection(cp, "TxDescCache");
-    rxDescCache.serializeSection(cp, "RxDescCache");
-}
-
-void
-IGbE::unserialize(CheckpointIn &cp)
-{
-    PciDevice::unserialize(cp);
-
-    regs.unserialize(cp);
-    UNSERIALIZE_SCALAR(eeOpBits);
-    UNSERIALIZE_SCALAR(eeAddrBits);
-    UNSERIALIZE_SCALAR(eeDataBits);
-    UNSERIALIZE_SCALAR(eeOpcode);
-    UNSERIALIZE_SCALAR(eeAddr);
-    UNSERIALIZE_SCALAR(lastInterrupt);
-    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
-
-    rxFifo.unserialize("rxfifo", cp);
-    txFifo.unserialize("txfifo", cp);
-
-    bool txPktExists;
-    UNSERIALIZE_SCALAR(txPktExists);
-    if (txPktExists) {
-        txPacket = std::make_shared<EthPacketData>(16384);
-        txPacket->unserialize("txpacket", cp);
-    }
-
-    rxTick = true;
-    txTick = true;
-    txFifoTick = true;
-
-    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
-    UNSERIALIZE_SCALAR(rdtr_time);
-    UNSERIALIZE_SCALAR(radv_time);
-    UNSERIALIZE_SCALAR(tidv_time);
-    UNSERIALIZE_SCALAR(tadv_time);
-    UNSERIALIZE_SCALAR(inter_time);
-
-    if (rdtr_time)
-        schedule(rdtrEvent, rdtr_time);
-
-    if (radv_time)
-        schedule(radvEvent, radv_time);
-
-    if (tidv_time)
-        schedule(tidvEvent, tidv_time);
-
-    if (tadv_time)
-        schedule(tadvEvent, tadv_time);
-
-    if (inter_time)
-        schedule(interEvent, inter_time);
-
-    UNSERIALIZE_SCALAR(pktOffset);
-
-    txDescCache.unserializeSection(cp, "TxDescCache");
-    rxDescCache.unserializeSection(cp, "RxDescCache");
-}
-
-IGbE *
-IGbEParams::create()
-{
-    return new IGbE(this);
-}
diff --git a/src/dev/i8254xGBe.hh b/src/dev/i8254xGBe.hh
deleted file mode 100644 (file)
index 700f49f..0000000
+++ /dev/null
@@ -1,560 +0,0 @@
-/*
- * Copyright (c) 2006 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Device model for Intel's 8254x line of gigabit ethernet controllers.
- */
-
-#ifndef __DEV_I8254XGBE_HH__
-#define __DEV_I8254XGBE_HH__
-
-#include <deque>
-#include <string>
-
-#include "base/cp_annotate.hh"
-#include "base/inet.hh"
-#include "debug/EthernetDesc.hh"
-#include "debug/EthernetIntr.hh"
-#include "dev/etherdevice.hh"
-#include "dev/etherint.hh"
-#include "dev/etherpkt.hh"
-#include "dev/i8254xGBe_defs.hh"
-#include "dev/pci/device.hh"
-#include "dev/pktfifo.hh"
-#include "params/IGbE.hh"
-#include "sim/eventq.hh"
-
-class IGbEInt;
-
-class IGbE : public EtherDevice
-{
-  private:
-    IGbEInt *etherInt;
-    CPA *cpa;
-
-    // device registers
-    iGbReg::Regs regs;
-
-    // eeprom data, status and control bits
-    int eeOpBits, eeAddrBits, eeDataBits;
-    uint8_t eeOpcode, eeAddr;
-    uint16_t flash[iGbReg::EEPROM_SIZE];
-
-    // packet fifos
-    PacketFifo rxFifo;
-    PacketFifo txFifo;
-
-    // Packet that we are currently putting into the txFifo
-    EthPacketPtr txPacket;
-
-    // Should to Rx/Tx State machine tick?
-    bool rxTick;
-    bool txTick;
-    bool txFifoTick;
-
-    bool rxDmaPacket;
-
-    // Number of bytes copied from current RX packet
-    unsigned pktOffset;
-
-    // Delays in managaging descriptors
-    Tick fetchDelay, wbDelay;
-    Tick fetchCompDelay, wbCompDelay;
-    Tick rxWriteDelay, txReadDelay;
-
-    // Event and function to deal with RDTR timer expiring
-    void rdtrProcess() {
-        rxDescCache.writeback(0);
-        DPRINTF(EthernetIntr,
-                "Posting RXT interrupt because RDTR timer expired\n");
-        postInterrupt(iGbReg::IT_RXT);
-    }
-
-    //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
-    EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
-
-    // Event and function to deal with RADV timer expiring
-    void radvProcess() {
-        rxDescCache.writeback(0);
-        DPRINTF(EthernetIntr,
-                "Posting RXT interrupt because RADV timer expired\n");
-        postInterrupt(iGbReg::IT_RXT);
-    }
-
-    //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
-    EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
-
-    // Event and function to deal with TADV timer expiring
-    void tadvProcess() {
-        txDescCache.writeback(0);
-        DPRINTF(EthernetIntr,
-                "Posting TXDW interrupt because TADV timer expired\n");
-        postInterrupt(iGbReg::IT_TXDW);
-    }
-
-    //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
-    EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
-
-    // Event and function to deal with TIDV timer expiring
-    void tidvProcess() {
-        txDescCache.writeback(0);
-        DPRINTF(EthernetIntr,
-                "Posting TXDW interrupt because TIDV timer expired\n");
-        postInterrupt(iGbReg::IT_TXDW);
-    }
-    //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
-    EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
-
-    // Main event to tick the device
-    void tick();
-    //friend class EventWrapper<IGbE, &IGbE::tick>;
-    EventWrapper<IGbE, &IGbE::tick> tickEvent;
-
-
-    uint64_t macAddr;
-
-    void rxStateMachine();
-    void txStateMachine();
-    void txWire();
-
-    /** Write an interrupt into the interrupt pending register and check mask
-     * and interrupt limit timer before sending interrupt to CPU
-     * @param t the type of interrupt we are posting
-     * @param now should we ignore the interrupt limiting timer
-     */
-    void postInterrupt(iGbReg::IntTypes t, bool now = false);
-
-    /** Check and see if changes to the mask register have caused an interrupt
-     * to need to be sent or perhaps removed an interrupt cause.
-     */
-    void chkInterrupt();
-
-    /** Send an interrupt to the cpu
-     */
-    void delayIntEvent();
-    void cpuPostInt();
-    // Event to moderate interrupts
-    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
-
-    /** Clear the interupt line to the cpu
-     */
-    void cpuClearInt();
-
-    Tick intClock() { return SimClock::Int::ns * 1024; }
-
-    /** This function is used to restart the clock so it can handle things like
-     * draining and resume in one place. */
-    void restartClock();
-
-    /** Check if all the draining things that need to occur have occured and
-     * handle the drain event if so.
-     */
-    void checkDrain();
-
-    void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
-        if (cpa)
-            cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
-    }
-
-    void anQ(std::string sm, std::string q) {
-        if (cpa)
-            cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
-    }
-
-    void anDq(std::string sm, std::string q) {
-        if (cpa)
-            cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
-    }
-
-    void anPq(std::string sm, std::string q, int num = 1) {
-        if (cpa)
-            cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
-    }
-
-    void anRq(std::string sm, std::string q, int num = 1) {
-        if (cpa)
-            cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
-    }
-
-    void anWe(std::string sm, std::string q) {
-        if (cpa)
-            cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
-    }
-
-    void anWf(std::string sm, std::string q) {
-        if (cpa)
-            cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
-    }
-
-
-    template<class T>
-    class DescCache : public Serializable
-    {
-      protected:
-        virtual Addr descBase() const = 0;
-        virtual long descHead() const = 0;
-        virtual long descTail() const = 0;
-        virtual long descLen() const = 0;
-        virtual void updateHead(long h) = 0;
-        virtual void enableSm() = 0;
-        virtual void actionAfterWb() {}
-        virtual void fetchAfterWb() = 0;
-
-        typedef std::deque<T *> CacheType;
-        CacheType usedCache;
-        CacheType unusedCache;
-
-        T *fetchBuf;
-        T *wbBuf;
-
-        // Pointer to the device we cache for
-        IGbE *igbe;
-
-        // Name of this  descriptor cache
-        std::string _name;
-
-        // How far we've cached
-        int cachePnt;
-
-        // The size of the descriptor cache
-        int size;
-
-        // How many descriptors we are currently fetching
-        int curFetching;
-
-        // How many descriptors we are currently writing back
-        int wbOut;
-
-        // if the we wrote back to the end of the descriptor ring and are going
-        // to have to wrap and write more
-        bool moreToWb;
-
-        // What the alignment is of the next descriptor writeback
-        Addr wbAlignment;
-
-        /** The packet that is currently being dmad to memory if any */
-        EthPacketPtr pktPtr;
-
-        /** Shortcut for DMA address translation */
-        Addr pciToDma(Addr a) { return igbe->pciToDma(a); }
-
-      public:
-        /** Annotate sm*/
-        std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
-            annUsedDescQ, annUnusedCacheQ, annDescQ;
-
-        DescCache(IGbE *i, const std::string n, int s);
-        virtual ~DescCache();
-
-        std::string name() { return _name; }
-
-        /** If the address/len/head change when we've got descriptors that are
-         * dirty that is very bad. This function checks that we don't and if we
-         * do panics.
-         */
-        void areaChanged();
-
-        void writeback(Addr aMask);
-        void writeback1();
-        EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
-
-        /** Fetch a chunk of descriptors into the descriptor cache.
-         * Calls fetchComplete when the memory system returns the data
-         */
-        void fetchDescriptors();
-        void fetchDescriptors1();
-        EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
-
-        /** Called by event when dma to read descriptors is completed
-         */
-        void fetchComplete();
-        EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
-
-        /** Called by event when dma to writeback descriptors is completed
-         */
-        void wbComplete();
-        EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
-
-        /* Return the number of descriptors left in the ring, so the device has
-         * a way to figure out if it needs to interrupt.
-         */
-        unsigned
-        descLeft() const
-        {
-            unsigned left = unusedCache.size();
-            if (cachePnt > descTail())
-                left += (descLen() - cachePnt + descTail());
-            else
-                left += (descTail() - cachePnt);
-
-            return left;
-        }
-
-        /* Return the number of descriptors used and not written back.
-         */
-        unsigned descUsed() const { return usedCache.size(); }
-
-        /* Return the number of cache unused descriptors we have. */
-        unsigned descUnused() const { return unusedCache.size(); }
-
-        /* Get into a state where the descriptor address/head/etc colud be
-         * changed */
-        void reset();
-
-
-        void serialize(CheckpointOut &cp) const override;
-        void unserialize(CheckpointIn &cp) override;
-
-        virtual bool hasOutstandingEvents() {
-            return wbEvent.scheduled() || fetchEvent.scheduled();
-        }
-
-    };
-
-
-    class RxDescCache : public DescCache<iGbReg::RxDesc>
-    {
-      protected:
-        Addr descBase() const override { return igbe->regs.rdba(); }
-        long descHead() const override { return igbe->regs.rdh(); }
-        long descLen() const override { return igbe->regs.rdlen() >> 4; }
-        long descTail() const override { return igbe->regs.rdt(); }
-        void updateHead(long h) override { igbe->regs.rdh(h); }
-        void enableSm() override;
-        void fetchAfterWb() override {
-            if (!igbe->rxTick && igbe->drainState() == DrainState::Running)
-                fetchDescriptors();
-        }
-
-        bool pktDone;
-
-        /** Variable to head with header/data completion events */
-        int splitCount;
-
-        /** Bytes of packet that have been copied, so we know when to
-            set EOP */
-        unsigned bytesCopied;
-
-      public:
-        RxDescCache(IGbE *i, std::string n, int s);
-
-        /** Write the given packet into the buffer(s) pointed to by the
-         * descriptor and update the book keeping. Should only be called when
-         * there are no dma's pending.
-         * @param packet ethernet packet to write
-         * @param pkt_offset bytes already copied from the packet to memory
-         * @return pkt_offset + number of bytes copied during this call
-         */
-        int writePacket(EthPacketPtr packet, int pkt_offset);
-
-        /** Called by event when dma to write packet is completed
-         */
-        void pktComplete();
-
-        /** Check if the dma on the packet has completed and RX state machine
-         * can continue
-         */
-        bool packetDone();
-
-        EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
-
-        // Event to handle issuing header and data write at the same time
-        // and only callking pktComplete() when both are completed
-        void pktSplitDone();
-        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
-        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
-
-        bool hasOutstandingEvents() override;
-
-        void serialize(CheckpointOut &cp) const override;
-        void unserialize(CheckpointIn &cp) override;
-    };
-    friend class RxDescCache;
-
-    RxDescCache rxDescCache;
-
-    class TxDescCache  : public DescCache<iGbReg::TxDesc>
-    {
-      protected:
-        Addr descBase() const override { return igbe->regs.tdba(); }
-        long descHead() const override { return igbe->regs.tdh(); }
-        long descTail() const override { return igbe->regs.tdt(); }
-        long descLen() const override { return igbe->regs.tdlen() >> 4; }
-        void updateHead(long h) override { igbe->regs.tdh(h); }
-        void enableSm() override;
-        void actionAfterWb() override;
-        void fetchAfterWb() override {
-            if (!igbe->txTick && igbe->drainState() == DrainState::Running)
-                fetchDescriptors();
-        }
-        
-
-
-        bool pktDone;
-        bool isTcp;
-        bool pktWaiting;
-        bool pktMultiDesc;
-        Addr completionAddress;
-        bool completionEnabled;
-        uint32_t descEnd;
-        
-
-        // tso variables
-        bool useTso;
-        Addr tsoHeaderLen;
-        Addr tsoMss;
-        Addr tsoTotalLen;
-        Addr tsoUsedLen;
-        Addr tsoPrevSeq;
-        Addr tsoPktPayloadBytes;
-        bool tsoLoadedHeader;
-        bool tsoPktHasHeader;
-        uint8_t tsoHeader[256];
-        Addr tsoDescBytesUsed;
-        Addr tsoCopyBytes;
-        int tsoPkts;
-
-      public:
-        TxDescCache(IGbE *i, std::string n, int s);
-
-        /** Tell the cache to DMA a packet from main memory into its buffer and
-         * return the size the of the packet to reserve space in tx fifo.
-         * @return size of the packet
-         */
-        unsigned getPacketSize(EthPacketPtr p);
-        void getPacketData(EthPacketPtr p);
-        void processContextDesc();
-
-        /** Return the number of dsecriptors in a cache block for threshold
-         * operations.
-         */
-        unsigned
-        descInBlock(unsigned num_desc)
-        {
-            return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc);
-        }
-
-        /** Ask if the packet has been transfered so the state machine can give
-         * it to the fifo.
-         * @return packet available in descriptor cache
-         */
-        bool packetAvailable();
-
-        /** Ask if we are still waiting for the packet to be transfered.
-         * @return packet still in transit.
-         */
-        bool packetWaiting() { return pktWaiting; }
-
-        /** Ask if this packet is composed of multiple descriptors
-         * so even if we've got data, we need to wait for more before
-         * we can send it out.
-         * @return packet can't be sent out because it's a multi-descriptor
-         * packet
-         */
-        bool packetMultiDesc() { return pktMultiDesc;}
-
-        /** Called by event when dma to write packet is completed
-         */
-        void pktComplete();
-        EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
-
-        void headerComplete();
-        EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
-
-
-        void completionWriteback(Addr a, bool enabled) {
-            DPRINTF(EthernetDesc,
-                    "Completion writeback Addr: %#x enabled: %d\n", 
-                    a, enabled);
-            completionAddress = a;
-            completionEnabled = enabled;
-        }
-
-        bool hasOutstandingEvents() override;
-
-        void nullCallback() {
-            DPRINTF(EthernetDesc, "Completion writeback complete\n");
-        }
-        EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
-
-        void serialize(CheckpointOut &cp) const override;
-        void unserialize(CheckpointIn &cp) override;
-    };
-
-    friend class TxDescCache;
-
-    TxDescCache txDescCache;
-
-  public:
-    typedef IGbEParams Params;
-    const Params *
-    params() const {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    IGbE(const Params *params);
-    ~IGbE();
-    void init() override;
-
-    EtherInt *getEthPort(const std::string &if_name, int idx) override;
-
-    Tick lastInterrupt;
-
-    Tick read(PacketPtr pkt) override;
-    Tick write(PacketPtr pkt) override;
-
-    Tick writeConfig(PacketPtr pkt) override;
-
-    bool ethRxPkt(EthPacketPtr packet);
-    void ethTxDone();
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-
-    DrainState drain() override;
-    void drainResume() override;
-
-};
-
-class IGbEInt : public EtherInt
-{
-  private:
-    IGbE *dev;
-
-  public:
-    IGbEInt(const std::string &name, IGbE *d)
-        : EtherInt(name), dev(d)
-    { }
-
-    virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
-    virtual void sendDone() { dev->ethTxDone(); }
-};
-
-#endif //__DEV_I8254XGBE_HH__
diff --git a/src/dev/i8254xGBe_defs.hh b/src/dev/i8254xGBe_defs.hh
deleted file mode 100644 (file)
index 79a9413..0000000
+++ /dev/null
@@ -1,854 +0,0 @@
-/*
- * Copyright (c) 2006 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Ali Saidi
- */
-
-/* @file
- * Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers.
- */
-#include "base/bitfield.hh"
-
-namespace iGbReg {
-
-
-// Registers used by the Intel GbE NIC
-const uint32_t REG_CTRL     = 0x00000;
-const uint32_t REG_STATUS   = 0x00008;
-const uint32_t REG_EECD     = 0x00010;
-const uint32_t REG_EERD     = 0x00014;
-const uint32_t REG_CTRL_EXT = 0x00018;
-const uint32_t REG_MDIC     = 0x00020;
-const uint32_t REG_FCAL     = 0x00028;
-const uint32_t REG_FCAH     = 0x0002C;
-const uint32_t REG_FCT      = 0x00030;
-const uint32_t REG_VET      = 0x00038;
-const uint32_t REG_PBA      = 0x01000;
-const uint32_t REG_ICR      = 0x000C0;
-const uint32_t REG_ITR      = 0x000C4;
-const uint32_t REG_ICS      = 0x000C8;
-const uint32_t REG_IMS      = 0x000D0;
-const uint32_t REG_IMC      = 0x000D8;
-const uint32_t REG_IAM      = 0x000E0;
-const uint32_t REG_RCTL     = 0x00100;
-const uint32_t REG_FCTTV    = 0x00170;
-const uint32_t REG_TIPG     = 0x00410;
-const uint32_t REG_AIFS     = 0x00458;
-const uint32_t REG_LEDCTL   = 0x00e00;
-const uint32_t REG_EICR     = 0x01580;
-const uint32_t REG_IVAR0    = 0x01700;
-const uint32_t REG_FCRTL    = 0x02160;
-const uint32_t REG_FCRTH    = 0x02168;
-const uint32_t REG_RDBAL    = 0x02800;
-const uint32_t REG_RDBAH    = 0x02804;
-const uint32_t REG_RDLEN    = 0x02808;
-const uint32_t REG_SRRCTL   = 0x0280C;
-const uint32_t REG_RDH      = 0x02810;
-const uint32_t REG_RDT      = 0x02818;
-const uint32_t REG_RDTR     = 0x02820;
-const uint32_t REG_RXDCTL   = 0x02828;
-const uint32_t REG_RADV     = 0x0282C;
-const uint32_t REG_TCTL     = 0x00400;
-const uint32_t REG_TDBAL    = 0x03800;
-const uint32_t REG_TDBAH    = 0x03804;
-const uint32_t REG_TDLEN    = 0x03808;
-const uint32_t REG_TDH      = 0x03810;
-const uint32_t REG_TXDCA_CTL = 0x03814;
-const uint32_t REG_TDT      = 0x03818;
-const uint32_t REG_TIDV     = 0x03820;
-const uint32_t REG_TXDCTL   = 0x03828;
-const uint32_t REG_TADV     = 0x0382C;
-const uint32_t REG_TDWBAL   = 0x03838;
-const uint32_t REG_TDWBAH   = 0x0383C;
-const uint32_t REG_CRCERRS  = 0x04000;
-const uint32_t REG_RXCSUM   = 0x05000;
-const uint32_t REG_RLPML    = 0x05004;
-const uint32_t REG_RFCTL    = 0x05008;
-const uint32_t REG_MTA      = 0x05200;
-const uint32_t REG_RAL      = 0x05400;
-const uint32_t REG_RAH      = 0x05404;
-const uint32_t REG_VFTA     = 0x05600;
-
-const uint32_t REG_WUC      = 0x05800;
-const uint32_t REG_MANC     = 0x05820;
-const uint32_t REG_SWSM     = 0x05B50;
-const uint32_t REG_FWSM     = 0x05B54;
-const uint32_t REG_SWFWSYNC = 0x05B5C;
-
-const uint8_t EEPROM_READ_OPCODE_SPI    = 0x03;
-const uint8_t EEPROM_RDSR_OPCODE_SPI    = 0x05;
-const uint8_t EEPROM_SIZE               = 64;
-const uint16_t EEPROM_CSUM              = 0xBABA;
-
-const uint8_t VLAN_FILTER_TABLE_SIZE    = 128;
-const uint8_t RCV_ADDRESS_TABLE_SIZE    = 24;
-const uint8_t MULTICAST_TABLE_SIZE      = 128;
-const uint32_t STATS_REGS_SIZE           = 0x228;
-
-
-// Registers in that are accessed in the PHY
-const uint8_t PHY_PSTATUS       = 0x1;
-const uint8_t PHY_PID           = 0x2;
-const uint8_t PHY_EPID          = 0x3;
-const uint8_t PHY_GSTATUS       = 10;
-const uint8_t PHY_EPSTATUS      = 15;
-const uint8_t PHY_AGC           = 18;
-
-// Receive Descriptor Status Flags
-const uint16_t RXDS_DYNINT      = 0x800;
-const uint16_t RXDS_UDPV        = 0x400;
-const uint16_t RXDS_CRCV        = 0x100;
-const uint16_t RXDS_PIF         = 0x080;
-const uint16_t RXDS_IPCS        = 0x040;
-const uint16_t RXDS_TCPCS       = 0x020;
-const uint16_t RXDS_UDPCS       = 0x010;
-const uint16_t RXDS_VP          = 0x008;
-const uint16_t RXDS_IXSM        = 0x004;
-const uint16_t RXDS_EOP         = 0x002;
-const uint16_t RXDS_DD          = 0x001;
-
-// Receive Descriptor Error Flags
-const uint8_t RXDE_RXE         = 0x80;
-const uint8_t RXDE_IPE         = 0x40;
-const uint8_t RXDE_TCPE        = 0x20;
-const uint8_t RXDE_SEQ         = 0x04;
-const uint8_t RXDE_SE          = 0x02;
-const uint8_t RXDE_CE          = 0x01;
-
-// Receive Descriptor Extended Error Flags
-const uint16_t RXDEE_HBO       = 0x008;
-const uint16_t RXDEE_CE        = 0x010;
-const uint16_t RXDEE_LE        = 0x020;
-const uint16_t RXDEE_PE        = 0x080;
-const uint16_t RXDEE_OSE       = 0x100;
-const uint16_t RXDEE_USE       = 0x200;
-const uint16_t RXDEE_TCPE      = 0x400;
-const uint16_t RXDEE_IPE       = 0x800;
-
-
-// Receive Descriptor Types
-const uint8_t RXDT_LEGACY      = 0x00;
-const uint8_t RXDT_ADV_ONEBUF  = 0x01;
-const uint8_t RXDT_ADV_SPLIT_A = 0x05;
-
-// Receive Descriptor Packet Types
-const uint16_t RXDP_IPV4       = 0x001;
-const uint16_t RXDP_IPV4E      = 0x002;
-const uint16_t RXDP_IPV6       = 0x004;
-const uint16_t RXDP_IPV6E      = 0x008;
-const uint16_t RXDP_TCP        = 0x010;
-const uint16_t RXDP_UDP        = 0x020;
-const uint16_t RXDP_SCTP       = 0x040;
-const uint16_t RXDP_NFS        = 0x080;
-
-// Interrupt types
-enum IntTypes
-{
-    IT_NONE    = 0x00000, //dummy value
-    IT_TXDW    = 0x00001,
-    IT_TXQE    = 0x00002,
-    IT_LSC     = 0x00004,
-    IT_RXSEQ   = 0x00008,
-    IT_RXDMT   = 0x00010,
-    IT_RXO     = 0x00040,
-    IT_RXT     = 0x00080,
-    IT_MADC    = 0x00200,
-    IT_RXCFG   = 0x00400,
-    IT_GPI0    = 0x02000,
-    IT_GPI1    = 0x04000,
-    IT_TXDLOW  = 0x08000,
-    IT_SRPD    = 0x10000,
-    IT_ACK     = 0x20000
-};
-
-// Receive Descriptor struct
-struct RxDesc {
-    union { 
-        struct {
-            Addr buf;
-            uint16_t len;
-            uint16_t csum;
-            uint8_t status;
-            uint8_t errors;
-            uint16_t vlan;
-        } legacy;
-        struct {
-            Addr pkt;
-            Addr hdr;
-        } adv_read;
-        struct {
-            uint16_t rss_type:4;
-            uint16_t pkt_type:12;
-            uint16_t __reserved1:5;
-            uint16_t header_len:10;
-            uint16_t sph:1;
-            union {
-                struct {
-                    uint16_t id;
-                    uint16_t csum;
-                };
-                uint32_t rss_hash;
-            };
-            uint32_t status:20;
-            uint32_t errors:12;
-            uint16_t pkt_len;
-            uint16_t vlan_tag;
-        } adv_wb ;
-    };
-};
-
-struct TxDesc {
-    uint64_t d1;
-    uint64_t d2;
-};
-
-namespace TxdOp {
-const uint8_t TXD_CNXT = 0x0;
-const uint8_t TXD_DATA = 0x1;
-const uint8_t TXD_ADVCNXT = 0x2;
-const uint8_t TXD_ADVDATA = 0x3;
-
-inline bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); }
-inline uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); }
-inline bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; }
-inline bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); }
-inline bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT);  }
-inline bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); }
-inline bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); }
-
-inline Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
-inline Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
-inline void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
-
-inline bool ide(TxDesc *d)  { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); }
-inline bool vle(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
-inline bool rs(TxDesc *d)   { return bits(d->d2, 27,27); }
-inline bool ic(TxDesc *d)   { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
-inline bool tse(TxDesc *d)  {
-    if (isTypes(d, TXD_CNXT, TXD_DATA))
-        return bits(d->d2, 26,26); 
-    if (isType(d, TXD_ADVDATA))
-        return bits(d->d2, 31, 31);
-    return false;
-}
-
-inline bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
-inline bool eop(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
-inline bool ip(TxDesc *d)   { assert(isContext(d)); return bits(d->d2, 25,25); }
-inline bool tcp(TxDesc *d)  { assert(isContext(d)); return bits(d->d2, 24,24); }
-
-inline uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
-inline uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
-
-inline bool ixsm(TxDesc *d)  { return isData(d) && bits(d->d2, 40,40); }
-inline bool txsm(TxDesc *d)  { return isData(d) && bits(d->d2, 41,41); }
-
-inline int tucse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,63,48); }
-inline int tucso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,47,40); }
-inline int tucss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,39,32); }
-inline int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
-inline int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
-inline int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
-inline int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
-inline int hdrlen(TxDesc *d) {
-    assert(isContext(d)); 
-    if (!isAdvDesc(d))
-        return bits(d->d2,47,40);
-    return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9); 
-}
-
-inline int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); }
-inline int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); }
-} // namespace TxdOp
-
-
-#define ADD_FIELD32(NAME, OFFSET, BITS) \
-    inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-#define ADD_FIELD64(NAME, OFFSET, BITS) \
-    inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
-    inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
-
-struct Regs : public Serializable {
-    template<class T>
-    struct Reg {
-        T _data;
-        T operator()() { return _data; }
-        const Reg<T> &operator=(T d) { _data = d; return *this;}
-        bool operator==(T d) { return d == _data; }
-        void operator()(T d) { _data = d; }
-        Reg() { _data = 0; }
-        void serialize(CheckpointOut &cp) const
-        {
-            SERIALIZE_SCALAR(_data);
-        }
-        void unserialize(CheckpointIn &cp)
-        {
-            UNSERIALIZE_SCALAR(_data);
-        }
-    };
-
-    struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(fd,0,1);       // full duplex
-        ADD_FIELD32(bem,1,1);      // big endian mode
-        ADD_FIELD32(pcipr,2,1);    // PCI priority
-        ADD_FIELD32(lrst,3,1);     // link reset
-        ADD_FIELD32(tme,4,1);      // test mode enable
-        ADD_FIELD32(asde,5,1);     // Auto-speed detection
-        ADD_FIELD32(slu,6,1);      // Set link up
-        ADD_FIELD32(ilos,7,1);     // invert los-of-signal
-        ADD_FIELD32(speed,8,2);    // speed selection bits
-        ADD_FIELD32(be32,10,1);    // big endian mode 32
-        ADD_FIELD32(frcspd,11,1);  // force speed
-        ADD_FIELD32(frcdpx,12,1);  // force duplex
-        ADD_FIELD32(duden,13,1);   // dock/undock enable
-        ADD_FIELD32(dudpol,14,1);  // dock/undock polarity
-        ADD_FIELD32(fphyrst,15,1); // force phy reset
-        ADD_FIELD32(extlen,16,1);  // external link status enable
-        ADD_FIELD32(rsvd,17,1);    // reserved
-        ADD_FIELD32(sdp0d,18,1);   // software controlled pin data
-        ADD_FIELD32(sdp1d,19,1);   // software controlled pin data
-        ADD_FIELD32(sdp2d,20,1);   // software controlled pin data
-        ADD_FIELD32(sdp3d,21,1);   // software controlled pin data
-        ADD_FIELD32(sdp0i,22,1);   // software controlled pin dir
-        ADD_FIELD32(sdp1i,23,1);   // software controlled pin dir
-        ADD_FIELD32(sdp2i,24,1);   // software controlled pin dir
-        ADD_FIELD32(sdp3i,25,1);   // software controlled pin dir
-        ADD_FIELD32(rst,26,1);     // reset
-        ADD_FIELD32(rfce,27,1);    // receive flow control enable
-        ADD_FIELD32(tfce,28,1);    // transmit flow control enable
-        ADD_FIELD32(rte,29,1);     // routing tag enable
-        ADD_FIELD32(vme,30,1);     // vlan enable
-        ADD_FIELD32(phyrst,31,1);  // phy reset
-    };
-    CTRL ctrl;
-
-    struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(fd,0,1);       // full duplex
-        ADD_FIELD32(lu,1,1);       // link up
-        ADD_FIELD32(func,2,2);     // function id
-        ADD_FIELD32(txoff,4,1);    // transmission paused
-        ADD_FIELD32(tbimode,5,1);  // tbi mode
-        ADD_FIELD32(speed,6,2);    // link speed
-        ADD_FIELD32(asdv,8,2);     // auto speed detection value
-        ADD_FIELD32(mtxckok,10,1); // mtx clock running ok
-        ADD_FIELD32(pci66,11,1);   // In 66Mhz pci slot
-        ADD_FIELD32(bus64,12,1);   // in 64 bit slot
-        ADD_FIELD32(pcix,13,1);    // Pci mode
-        ADD_FIELD32(pcixspd,14,2); // pci x speed
-    };
-    STATUS sts;
-
-    struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(sk,0,1);       // clack input to the eeprom
-        ADD_FIELD32(cs,1,1);       // chip select to eeprom
-        ADD_FIELD32(din,2,1);      // data input to eeprom
-        ADD_FIELD32(dout,3,1);     // data output bit
-        ADD_FIELD32(fwe,4,2);      // flash write enable
-        ADD_FIELD32(ee_req,6,1);   // request eeprom access
-        ADD_FIELD32(ee_gnt,7,1);   // grant eeprom access
-        ADD_FIELD32(ee_pres,8,1);  // eeprom present
-        ADD_FIELD32(ee_size,9,1);  // eeprom size
-        ADD_FIELD32(ee_sz1,10,1);  // eeprom size
-        ADD_FIELD32(rsvd,11,2);    // reserved
-        ADD_FIELD32(ee_type,13,1); // type of eeprom
-    } ;
-    EECD eecd;
-
-    struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(start,0,1);  // start read
-        ADD_FIELD32(done,1,1);   // done read
-        ADD_FIELD32(addr,2,14);   // address
-        ADD_FIELD32(data,16,16); // data
-    };
-    EERD eerd;
-
-    struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(gpi_en,0,4);      // enable interrupts from gpio
-        ADD_FIELD32(phyint,5,1);      // reads the phy internal int status
-        ADD_FIELD32(sdp2_data,6,1);   // data from gpio sdp
-        ADD_FIELD32(spd3_data,7,1);   // data frmo gpio sdp
-        ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2
-        ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2
-        ADD_FIELD32(asdchk,12,1);     // initiate auto-speed-detection
-        ADD_FIELD32(eerst,13,1);      // reset the eeprom
-        ADD_FIELD32(spd_byps,15,1);   // bypass speed select
-        ADD_FIELD32(ro_dis,17,1);     // disable relaxed memory ordering
-        ADD_FIELD32(vreg,21,1);       // power down the voltage regulator
-        ADD_FIELD32(link_mode,22,2);  // interface to talk to the link
-        ADD_FIELD32(iame, 27,1);      // interrupt acknowledge auto-mask ??
-        ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device
-        ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ??
-    };
-    CTRL_EXT ctrl_ext;
-
-    struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(data,0,16);   // data
-        ADD_FIELD32(regadd,16,5); // register address
-        ADD_FIELD32(phyadd,21,5); // phy addresses
-        ADD_FIELD32(op,26,2);     // opcode
-        ADD_FIELD32(r,28,1);      // ready
-        ADD_FIELD32(i,29,1);      // interrupt
-        ADD_FIELD32(e,30,1);      // error
-    };
-    MDIC mdic;
-
-    struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(txdw,0,1)   // tx descr witten back
-        ADD_FIELD32(txqe,1,1)   // tx queue empty
-        ADD_FIELD32(lsc,2,1)    // link status change
-        ADD_FIELD32(rxseq,3,1)  // rcv sequence error
-        ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh
-        ADD_FIELD32(rsvd1,5,1)  // reserved
-        ADD_FIELD32(rxo,6,1)    // receive overrunn
-        ADD_FIELD32(rxt0,7,1)   // receiver timer interrupt
-        ADD_FIELD32(mdac,9,1)   // mdi/o access complete
-        ADD_FIELD32(rxcfg,10,1)  // recv /c/ ordered sets
-        ADD_FIELD32(phyint,12,1) // phy interrupt
-        ADD_FIELD32(gpi1,13,1)   // gpi int 1
-        ADD_FIELD32(gpi2,14,1)   // gpi int 2
-        ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
-        ADD_FIELD32(srpd,16,1)   // small receive packet detected
-        ADD_FIELD32(ack,17,1);    // receive ack frame
-        ADD_FIELD32(int_assert, 31,1); // interrupt caused a system interrupt
-    };
-    ICR icr;
-
-    uint32_t imr; // register that contains the current interrupt mask
-
-    struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval
-                                     // specified in 256ns interrupts
-    };
-    ITR itr;
-
-    // When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write
-    // causes the IAM register contents to be written into the IMC
-    // automatically clearing all interrupts that have a bit in the IAM set
-    uint32_t iam;
-
-    struct RCTL : public Reg<uint32_t> { // 0x0100 RCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rst,0,1);   // Reset
-        ADD_FIELD32(en,1,1);    // Enable
-        ADD_FIELD32(sbp,2,1);   // Store bad packets
-        ADD_FIELD32(upe,3,1);   // Unicast Promiscuous enabled
-        ADD_FIELD32(mpe,4,1);   // Multicast promiscuous enabled
-        ADD_FIELD32(lpe,5,1);   // long packet reception enabled
-        ADD_FIELD32(lbm,6,2);   //
-        ADD_FIELD32(rdmts,8,2); //
-        ADD_FIELD32(mo,12,2);    //
-        ADD_FIELD32(mdr,14,1);   //
-        ADD_FIELD32(bam,15,1);   //
-        ADD_FIELD32(bsize,16,2); //
-        ADD_FIELD32(vfe,18,1);   //
-        ADD_FIELD32(cfien,19,1); //
-        ADD_FIELD32(cfi,20,1);   //
-        ADD_FIELD32(dpf,22,1);   // discard pause frames
-        ADD_FIELD32(pmcf,23,1);  // pass mac control  frames
-        ADD_FIELD32(bsex,25,1);  // buffer size extension
-        ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet
-        unsigned descSize()
-        {
-            switch(bsize()) {
-                case 0: return bsex() == 0 ? 2048 : 0;
-                case 1: return bsex() == 0 ? 1024 : 16384;
-                case 2: return bsex() == 0 ? 512 : 8192;
-                case 3: return bsex() == 0 ? 256 : 4096;
-                default:
-                        return 0;
-            }
-        }
-    };
-    RCTL rctl;
-
-    struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(ttv,0,16);    // Transmit Timer Value
-    };
-    FCTTV fcttv;
-
-    struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rst,0,1);    // Reset
-        ADD_FIELD32(en,1,1);     // Enable
-        ADD_FIELD32(bce,2,1);    // busy check enable
-        ADD_FIELD32(psp,3,1);    // pad short packets
-        ADD_FIELD32(ct,4,8);     // collision threshold
-        ADD_FIELD32(cold,12,10); // collision distance
-        ADD_FIELD32(swxoff,22,1); // software xoff transmission
-        ADD_FIELD32(pbe,23,1);    // packet burst enable
-        ADD_FIELD32(rtlc,24,1);   // retransmit late collisions
-        ADD_FIELD32(nrtu,25,1);   // on underrun no TX
-        ADD_FIELD32(mulr,26,1);   // multiple request
-    };
-    TCTL tctl;
-
-    struct PBA : public Reg<uint32_t> { // 0x1000 PBA Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rxa,0,16);
-        ADD_FIELD32(txa,16,16);
-    };
-    PBA pba;
-
-    struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have
-                               // a larger buffer
-        ADD_FIELD32(xone, 31,1);
-    };
-    FCRTL fcrtl;
-
-    struct FCRTH : public Reg<uint32_t> { // 0x2168 FCRTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have
-                               //a larger buffer
-        ADD_FIELD32(xfce, 31,1);
-    };
-    FCRTH fcrth;
-
-    struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
-        using Reg<uint64_t>::operator=;
-        ADD_FIELD64(rdbal,0,32); // base address of rx descriptor ring
-        ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
-    };
-    RDBA rdba;
-
-    struct RDLEN : public Reg<uint32_t> { // 0x2808 RDLEN Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
-    };
-    RDLEN rdlen;
-
-    struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(pktlen, 0, 8);
-        ADD_FIELD32(hdrlen, 8, 8); // guess based on header, not documented
-        ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv,
-                                     //101 hdr split
-        unsigned bufLen() { return pktlen() << 10; }
-        unsigned hdrLen() { return hdrlen() << 6; }
-    };
-    SRRCTL srrctl;
-
-    struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rdh,0,16); // head of the descriptor ring
-    };
-    RDH rdh;
-
-    struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(rdt,0,16); // tail of the descriptor ring
-    };
-    RDT rdt;
-
-    struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(delay,0,16); // receive delay timer
-        ADD_FIELD32(fpd, 31,1);   // flush partial descriptor block ??
-    };
-    RDTR rdtr;
-
-    struct RXDCTL : public Reg<uint32_t> { // 0x2828 RXDCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(pthresh,0,6);   // prefetch threshold, less that this
-                                    // consider prefetch
-        ADD_FIELD32(hthresh,8,6);   // number of descriptors in host mem to
-                                    // consider prefetch
-        ADD_FIELD32(wthresh,16,6);  // writeback threshold
-        ADD_FIELD32(gran,24,1);     // granularity 0 = desc, 1 = cacheline
-    };
-    RXDCTL rxdctl;
-
-    struct RADV : public Reg<uint32_t> { // 0x282C RADV Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(idv,0,16); // absolute interrupt delay
-    };
-    RADV radv;
-
-    struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(idv,0,12); // size to interrutp on small packets
-    };
-    RSRPD rsrpd;
-
-    struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
-        using Reg<uint64_t>::operator=;
-        ADD_FIELD64(tdbal,0,32); // base address of transmit descriptor ring
-        ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
-    };
-    TDBA tdba;
-
-    struct TDLEN : public Reg<uint32_t> { // 0x3808 TDLEN Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
-    };
-    TDLEN tdlen;
-
-    struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(tdh,0,16); // head of the descriptor ring
-    };
-    TDH tdh;
-
-    struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(cpu_mask, 0, 5);
-        ADD_FIELD32(enabled, 5,1);
-        ADD_FIELD32(relax_ordering, 6, 1);
-    };
-    TXDCA_CTL txdca_ctl;
-
-    struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
-    };
-    TDT tdt;
-
-    struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(idv,0,16); // interrupt delay
-    };
-    TIDV tidv;
-
-    struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(pthresh, 0,6);  // if number of descriptors control has is
-                                    // below this number, a prefetch is considered
-        ADD_FIELD32(hthresh,8,8);   // number of valid descriptors is host memory
-                                    // before a prefetch is considered
-        ADD_FIELD32(wthresh,16,6);  // number of descriptors to keep until
-                                    // writeback is considered
-        ADD_FIELD32(gran, 24,1);    // granulatiry of above values (0 = cacheline,
-                                    // 1 == desscriptor)
-        ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt
-                                    // below this level
-    };
-    TXDCTL txdctl;
-
-    struct TADV : public Reg<uint32_t> { // 0x382C TADV Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(idv,0,16); // absolute interrupt delay
-    };
-    TADV tadv;
-/*
-    struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register
-        using Reg<uint64_t>::operator=;
-        ADD_FIELD64(en,0,1); // enable  transmit description ring address writeback
-        ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback
-        ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring
-    };
-    TDWBA tdwba;*/
-    uint64_t tdwba;
-
-    struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(pcss,0,8);
-        ADD_FIELD32(ipofld,8,1);
-        ADD_FIELD32(tuofld,9,1);
-        ADD_FIELD32(pcsd, 13,1);
-    };
-    RXCSUM rxcsum;
-
-    uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size
-
-    struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(iscsi_dis,0,1);
-        ADD_FIELD32(iscsi_dwc,1,5);
-        ADD_FIELD32(nfsw_dis,6,1);
-        ADD_FIELD32(nfsr_dis,7,1);
-        ADD_FIELD32(nfs_ver,8,2);
-        ADD_FIELD32(ipv6_dis,10,1);
-        ADD_FIELD32(ipv6xsum_dis,11,1);
-        ADD_FIELD32(ackdis,13,1);
-        ADD_FIELD32(ipfrsp_dis,14,1);
-        ADD_FIELD32(exsten,15,1);
-    };
-    RFCTL rfctl;
-
-    struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(smbus,0,1);    // SMBus enabled #####
-        ADD_FIELD32(asf,1,1);      // ASF enabled #####
-        ADD_FIELD32(ronforce,2,1); // reset of force
-        ADD_FIELD32(rsvd,3,5);     // reserved
-        ADD_FIELD32(rmcp1,8,1);    // rcmp1 filtering
-        ADD_FIELD32(rmcp2,9,1);    // rcmp2 filtering
-        ADD_FIELD32(ipv4,10,1);     // enable ipv4
-        ADD_FIELD32(ipv6,11,1);     // enable ipv6
-        ADD_FIELD32(snap,12,1);     // accept snap
-        ADD_FIELD32(arp,13,1);      // filter arp #####
-        ADD_FIELD32(neighbor,14,1); // neighbor discovery
-        ADD_FIELD32(arp_resp,15,1); // arp response
-        ADD_FIELD32(tcorst,16,1);   // tco reset happened
-        ADD_FIELD32(rcvtco,17,1);   // receive tco enabled ######
-        ADD_FIELD32(blkphyrst,18,1);// block phy resets ########
-        ADD_FIELD32(rcvall,19,1);   // receive all
-        ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ######
-        ADD_FIELD32(mng2host,21,1); // mng2 host packets #######
-        ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering
-        ADD_FIELD32(xsumfilter,23,1); // checksum filtering
-        ADD_FIELD32(brfilter,24,1); // broadcast filtering
-        ADD_FIELD32(smbreq,25,1);   // smb request
-        ADD_FIELD32(smbgnt,26,1);   // smb grant
-        ADD_FIELD32(smbclkin,27,1); // smbclkin
-        ADD_FIELD32(smbdatain,28,1); // smbdatain
-        ADD_FIELD32(smbdataout,29,1); // smb data out
-        ADD_FIELD32(smbclkout,30,1); // smb clock out
-    };
-    MANC manc;
-
-    struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(smbi,0,1); // Semaphone bit
-        ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore
-        ADD_FIELD32(wmng, 2,1); // Wake MNG clock
-        ADD_FIELD32(reserved, 3, 29);
-    };
-    SWSM swsm;
-
-    struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register
-        using Reg<uint32_t>::operator=;
-        ADD_FIELD32(eep_fw_semaphore,0,1); 
-        ADD_FIELD32(fw_mode, 1,3); 
-        ADD_FIELD32(ide, 4,1); 
-        ADD_FIELD32(sol, 5,1);
-        ADD_FIELD32(eep_roload, 6,1);
-        ADD_FIELD32(reserved, 7,8);
-        ADD_FIELD32(fw_val_bit, 15, 1);
-        ADD_FIELD32(reset_cnt, 16, 3);
-        ADD_FIELD32(ext_err_ind, 19, 6);
-        ADD_FIELD32(reserved2, 25, 7);
-    };
-    FWSM fwsm;
-
-    uint32_t sw_fw_sync;
-
-    void serialize(CheckpointOut &cp) const override
-    {
-        paramOut(cp, "ctrl", ctrl._data);
-        paramOut(cp, "sts", sts._data);
-        paramOut(cp, "eecd", eecd._data);
-        paramOut(cp, "eerd", eerd._data);
-        paramOut(cp, "ctrl_ext", ctrl_ext._data);
-        paramOut(cp, "mdic", mdic._data);
-        paramOut(cp, "icr", icr._data);
-        SERIALIZE_SCALAR(imr);
-        paramOut(cp, "itr", itr._data);
-        SERIALIZE_SCALAR(iam);
-        paramOut(cp, "rctl", rctl._data);
-        paramOut(cp, "fcttv", fcttv._data);
-        paramOut(cp, "tctl", tctl._data);
-        paramOut(cp, "pba", pba._data);
-        paramOut(cp, "fcrtl", fcrtl._data);
-        paramOut(cp, "fcrth", fcrth._data);
-        paramOut(cp, "rdba", rdba._data);
-        paramOut(cp, "rdlen", rdlen._data);
-        paramOut(cp, "srrctl", srrctl._data);
-        paramOut(cp, "rdh", rdh._data);
-        paramOut(cp, "rdt", rdt._data);
-        paramOut(cp, "rdtr", rdtr._data);
-        paramOut(cp, "rxdctl", rxdctl._data);
-        paramOut(cp, "radv", radv._data);
-        paramOut(cp, "rsrpd", rsrpd._data);
-        paramOut(cp, "tdba", tdba._data);
-        paramOut(cp, "tdlen", tdlen._data);
-        paramOut(cp, "tdh", tdh._data);
-        paramOut(cp, "txdca_ctl", txdca_ctl._data);
-        paramOut(cp, "tdt", tdt._data);
-        paramOut(cp, "tidv", tidv._data);
-        paramOut(cp, "txdctl", txdctl._data);
-        paramOut(cp, "tadv", tadv._data);
-        //paramOut(cp, "tdwba", tdwba._data);
-        SERIALIZE_SCALAR(tdwba);
-        paramOut(cp, "rxcsum", rxcsum._data);
-        SERIALIZE_SCALAR(rlpml);
-        paramOut(cp, "rfctl", rfctl._data);
-        paramOut(cp, "manc", manc._data);
-        paramOut(cp, "swsm", swsm._data);
-        paramOut(cp, "fwsm", fwsm._data);
-        SERIALIZE_SCALAR(sw_fw_sync);
-    }
-
-    void unserialize(CheckpointIn &cp) override
-    {
-        paramIn(cp, "ctrl", ctrl._data);
-        paramIn(cp, "sts", sts._data);
-        paramIn(cp, "eecd", eecd._data);
-        paramIn(cp, "eerd", eerd._data);
-        paramIn(cp, "ctrl_ext", ctrl_ext._data);
-        paramIn(cp, "mdic", mdic._data);
-        paramIn(cp, "icr", icr._data);
-        UNSERIALIZE_SCALAR(imr);
-        paramIn(cp, "itr", itr._data);
-        UNSERIALIZE_SCALAR(iam);
-        paramIn(cp, "rctl", rctl._data);
-        paramIn(cp, "fcttv", fcttv._data);
-        paramIn(cp, "tctl", tctl._data);
-        paramIn(cp, "pba", pba._data);
-        paramIn(cp, "fcrtl", fcrtl._data);
-        paramIn(cp, "fcrth", fcrth._data);
-        paramIn(cp, "rdba", rdba._data);
-        paramIn(cp, "rdlen", rdlen._data);
-        paramIn(cp, "srrctl", srrctl._data);
-        paramIn(cp, "rdh", rdh._data);
-        paramIn(cp, "rdt", rdt._data);
-        paramIn(cp, "rdtr", rdtr._data);
-        paramIn(cp, "rxdctl", rxdctl._data);
-        paramIn(cp, "radv", radv._data);
-        paramIn(cp, "rsrpd", rsrpd._data);
-        paramIn(cp, "tdba", tdba._data);
-        paramIn(cp, "tdlen", tdlen._data);
-        paramIn(cp, "tdh", tdh._data);
-        paramIn(cp, "txdca_ctl", txdca_ctl._data);
-        paramIn(cp, "tdt", tdt._data);
-        paramIn(cp, "tidv", tidv._data);
-        paramIn(cp, "txdctl", txdctl._data);
-        paramIn(cp, "tadv", tadv._data);
-        UNSERIALIZE_SCALAR(tdwba);
-        //paramIn(cp, "tdwba", tdwba._data);
-        paramIn(cp, "rxcsum", rxcsum._data);
-        UNSERIALIZE_SCALAR(rlpml);
-        paramIn(cp, "rfctl", rfctl._data);
-        paramIn(cp, "manc", manc._data);
-        paramIn(cp, "swsm", swsm._data);
-        paramIn(cp, "fwsm", fwsm._data);
-        UNSERIALIZE_SCALAR(sw_fw_sync);
-    }
-};
-} // namespace iGbReg
diff --git a/src/dev/multi_etherlink.cc b/src/dev/multi_etherlink.cc
deleted file mode 100644 (file)
index b7d411a..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * Device module for a full duplex ethernet link for multi gem5 simulations.
- */
-
-#include "dev/multi_etherlink.hh"
-
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <unistd.h>
-
-#include <cmath>
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/random.hh"
-#include "base/trace.hh"
-#include "debug/EthernetData.hh"
-#include "debug/MultiEthernet.hh"
-#include "debug/MultiEthernetPkt.hh"
-#include "dev/etherdump.hh"
-#include "dev/etherint.hh"
-#include "dev/etherlink.hh"
-#include "dev/etherobject.hh"
-#include "dev/etherpkt.hh"
-#include "dev/multi_iface.hh"
-#include "dev/tcp_iface.hh"
-#include "params/EtherLink.hh"
-#include "sim/core.hh"
-#include "sim/serialize.hh"
-#include "sim/system.hh"
-
-using namespace std;
-
-MultiEtherLink::MultiEtherLink(const Params *p)
-    : EtherObject(p)
-{
-    DPRINTF(MultiEthernet,"MultiEtherLink::MultiEtherLink() "
-            "link delay:%llu\n", p->delay);
-
-    txLink = new TxLink(name() + ".link0", this, p->speed, p->delay_var,
-                        p->dump);
-    rxLink = new RxLink(name() + ".link1", this, p->delay, p->dump);
-
-    // create the multi (TCP) interface to talk to the peer gem5 processes.
-    multiIface = new TCPIface(p->server_name, p->server_port, p->multi_rank,
-                              p->sync_start, p->sync_repeat, this);
-
-    localIface = new LocalIface(name() + ".int0", txLink, rxLink, multiIface);
-}
-
-MultiEtherLink::~MultiEtherLink()
-{
-    delete txLink;
-    delete rxLink;
-    delete localIface;
-    delete multiIface;
-}
-
-EtherInt*
-MultiEtherLink::getEthPort(const std::string &if_name, int idx)
-{
-    if (if_name != "int0") {
-        return nullptr;
-    } else {
-        panic_if(localIface->getPeer(), "interface already connected to");
-    }
-    return localIface;
-}
-
-void MultiEtherLink::memWriteback()
-{
-    DPRINTF(MultiEthernet,"MultiEtherLink::memWriteback() called\n");
-    multiIface->drainDone();
-}
-
-void
-MultiEtherLink::serialize(CheckpointOut &cp) const
-{
-    multiIface->serialize("multiIface", cp);
-    txLink->serialize("txLink", cp);
-    rxLink->serialize("rxLink", cp);
-}
-
-void
-MultiEtherLink::unserialize(CheckpointIn &cp)
-{
-    multiIface->unserialize("multiIface", cp);
-    txLink->unserialize("txLink", cp);
-    rxLink->unserialize("rxLink", cp);
-}
-
-void
-MultiEtherLink::init()
-{
-    DPRINTF(MultiEthernet,"MultiEtherLink::init() called\n");
-    multiIface->initRandom();
-}
-
-void
-MultiEtherLink::startup()
-{
-    DPRINTF(MultiEthernet,"MultiEtherLink::startup() called\n");
-    multiIface->startPeriodicSync();
-}
-
-void
-MultiEtherLink::RxLink::setMultiInt(MultiIface *m)
-{
-    assert(!multiIface);
-    multiIface = m;
-    // Spawn a new receiver thread that will process messages
-    // coming in from peer gem5 processes.
-    // The receive thread will also schedule a (receive) doneEvent
-    // for each incoming data packet.
-    multiIface->spawnRecvThread(&doneEvent, linkDelay);
-}
-
-void
-MultiEtherLink::RxLink::rxDone()
-{
-    assert(!busy());
-
-    // retrieve the packet that triggered the receive done event
-    packet = multiIface->packetIn();
-
-    if (dump)
-        dump->dump(packet);
-
-    DPRINTF(MultiEthernetPkt, "MultiEtherLink::MultiLink::rxDone() "
-            "packet received: len=%d\n", packet->length);
-    DDUMP(EthernetData, packet->data, packet->length);
-
-    localIface->sendPacket(packet);
-
-    packet = nullptr;
-}
-
-void
-MultiEtherLink::TxLink::txDone()
-{
-    if (dump)
-        dump->dump(packet);
-
-    packet = nullptr;
-    assert(!busy());
-
-    localIface->sendDone();
-}
-
-bool
-MultiEtherLink::TxLink::transmit(EthPacketPtr pkt)
-{
-    if (busy()) {
-        DPRINTF(MultiEthernet, "packet not sent, link busy\n");
-        return false;
-    }
-
-    packet = pkt;
-    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
-    if (delayVar != 0)
-        delay += random_mt.random<Tick>(0, delayVar);
-
-    // send the packet to the peers
-    assert(multiIface);
-    multiIface->packetOut(pkt, delay);
-
-    // schedule the send done event
-    parent->schedule(doneEvent, curTick() + delay);
-
-    return true;
-}
-
-void
-MultiEtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
-{
-    bool packet_exists = (packet != nullptr);
-    paramOut(cp, base + ".packet_exists", packet_exists);
-    if (packet_exists)
-        packet->serialize(base + ".packet", cp);
-
-    bool event_scheduled = event->scheduled();
-    paramOut(cp, base + ".event_scheduled", event_scheduled);
-    if (event_scheduled) {
-        Tick event_time = event->when();
-        paramOut(cp, base + ".event_time", event_time);
-    }
-}
-
-void
-MultiEtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
-{
-    bool packet_exists;
-    paramIn(cp, base + ".packet_exists", packet_exists);
-    if (packet_exists) {
-        packet = make_shared<EthPacketData>(16384);
-        packet->unserialize(base + ".packet", cp);
-    }
-
-    bool event_scheduled;
-    paramIn(cp, base + ".event_scheduled", event_scheduled);
-    if (event_scheduled) {
-        Tick event_time;
-        paramIn(cp, base + ".event_time", event_time);
-        parent->schedule(*event, event_time);
-    }
-}
-
-MultiEtherLink::LocalIface::LocalIface(const std::string &name,
-                                       TxLink *tx,
-                                       RxLink *rx,
-                                       MultiIface *m) :
-    EtherInt(name), txLink(tx)
-{
-    tx->setLocalInt(this);
-    rx->setLocalInt(this);
-    tx->setMultiInt(m);
-    rx->setMultiInt(m);
-}
-
-MultiEtherLink *
-MultiEtherLinkParams::create()
-{
-    return new MultiEtherLink(this);
-}
-
-
diff --git a/src/dev/multi_etherlink.hh b/src/dev/multi_etherlink.hh
deleted file mode 100644 (file)
index 68e96f8..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * Device module for a full duplex ethernet link for multi gem5 simulations.
- *
- * See comments in dev/multi_iface.hh for a generic description of multi
- * gem5 simulations.
- *
- * This class is meant to be a drop in replacement for the EtherLink class for
- * multi gem5 runs.
- *
- */
-#ifndef __DEV_MULTIETHERLINK_HH__
-#define __DEV_MULTIETHERLINK_HH__
-
-#include <iostream>
-
-#include "dev/etherlink.hh"
-#include "params/MultiEtherLink.hh"
-
-class MultiIface;
-class EthPacketData;
-
-/**
- * Model for a fixed bandwidth full duplex ethernet link.
- */
-class MultiEtherLink : public EtherObject
-{
-  protected:
-    class LocalIface;
-
-    /**
-     * Model base class for a single uni-directional link.
-     *
-     * The link will encapsulate and transfer Ethernet packets to/from
-     * the message server.
-     */
-    class Link
-    {
-      protected:
-        std::string objName;
-        MultiEtherLink *parent;
-        LocalIface *localIface;
-        EtherDump *dump;
-        MultiIface *multiIface;
-        Event *event;
-        EthPacketPtr packet;
-
-      public:
-        Link(const std::string &name, MultiEtherLink *p,
-             EtherDump *d, Event *e) :
-            objName(name), parent(p), localIface(nullptr), dump(d),
-            multiIface(nullptr), event(e) {}
-
-        ~Link() {}
-
-        const std::string name() const { return objName; }
-        bool busy() const { return (bool)packet; }
-        void setLocalInt(LocalIface *i) { assert(!localIface); localIface=i; }
-
-        void serialize(const std::string &base, CheckpointOut &cp) const;
-        void unserialize(const std::string &base, CheckpointIn &cp);
-    };
-
-    /**
-     * Model for a send link.
-     */
-    class TxLink : public Link
-    {
-      protected:
-        /**
-         * Per byte send delay
-         */
-        double ticksPerByte;
-        /**
-         * Random component of the send delay
-         */
-        Tick delayVar;
-
-        /**
-         * Send done callback. Called from doneEvent.
-         */
-        void txDone();
-        typedef EventWrapper<TxLink, &TxLink::txDone> DoneEvent;
-        friend void DoneEvent::process();
-        DoneEvent doneEvent;
-
-      public:
-        TxLink(const std::string &name, MultiEtherLink *p,
-               double invBW, Tick delay_var, EtherDump *d) :
-            Link(name, p, d, &doneEvent), ticksPerByte(invBW),
-            delayVar(delay_var), doneEvent(this) {}
-        ~TxLink() {}
-
-        /**
-         * Register the multi interface to be used to talk to the
-         * peer gem5 processes.
-         */
-        void setMultiInt(MultiIface *m) { assert(!multiIface); multiIface=m; }
-
-        /**
-         * Initiate sending of a packet via this link.
-         *
-         * @param packet Ethernet packet to send
-         */
-        bool transmit(EthPacketPtr packet);
-    };
-
-    /**
-     * Model for a receive link.
-     */
-    class RxLink : public Link
-    {
-      protected:
-
-        /**
-         * Transmission delay for the simulated Ethernet link.
-         */
-        Tick linkDelay;
-
-        /**
-         * Receive done callback method. Called from doneEvent.
-         */
-        void rxDone() ;
-        typedef EventWrapper<RxLink, &RxLink::rxDone> DoneEvent;
-        friend void DoneEvent::process();
-        DoneEvent doneEvent;
-
-      public:
-
-        RxLink(const std::string &name, MultiEtherLink *p,
-               Tick delay, EtherDump *d) :
-            Link(name, p, d, &doneEvent),
-            linkDelay(delay), doneEvent(this) {}
-        ~RxLink() {}
-
-        /**
-         * Register our multi interface to talk to the peer gem5 processes.
-         */
-        void setMultiInt(MultiIface *m);
-    };
-
-    /**
-     * Interface to the local simulated system
-     */
-    class LocalIface : public EtherInt
-    {
-      private:
-        TxLink *txLink;
-
-      public:
-        LocalIface(const std::string &name, TxLink *tx, RxLink *rx,
-                   MultiIface *m);
-
-        bool recvPacket(EthPacketPtr pkt) { return txLink->transmit(pkt); }
-        void sendDone() { peer->sendDone(); }
-        bool isBusy() { return txLink->busy(); }
-    };
-
-
-  protected:
-    /**
-     * Interface to talk to the peer gem5 processes.
-     */
-    MultiIface *multiIface;
-    /**
-     * Send link
-     */
-    TxLink *txLink;
-    /**
-     * Receive link
-     */
-    RxLink *rxLink;
-    LocalIface *localIface;
-
-  public:
-    typedef MultiEtherLinkParams Params;
-    MultiEtherLink(const Params *p);
-    ~MultiEtherLink();
-
-    const Params *
-    params() const
-    {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    virtual EtherInt *getEthPort(const std::string &if_name,
-                                 int idx) override;
-
-    void memWriteback() override;
-    void init() override;
-    void startup() override;
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-};
-
-#endif // __DEV_MULTIETHERLINK_HH__
diff --git a/src/dev/multi_iface.cc b/src/dev/multi_iface.cc
deleted file mode 100644 (file)
index c924c1a..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * The interface class for multi gem5 simulations.
- */
-
-#include "dev/multi_iface.hh"
-
-#include <queue>
-#include <thread>
-
-#include "base/random.hh"
-#include "base/trace.hh"
-#include "debug/MultiEthernet.hh"
-#include "debug/MultiEthernetPkt.hh"
-#include "dev/etherpkt.hh"
-#include "sim/sim_exit.hh"
-#include "sim/sim_object.hh"
-
-
-MultiIface::Sync *MultiIface::sync = nullptr;
-MultiIface::SyncEvent *MultiIface::syncEvent = nullptr;
-unsigned MultiIface::recvThreadsNum = 0;
-MultiIface *MultiIface::master = nullptr;
-
-bool
-MultiIface::Sync::run(SyncTrigger t, Tick sync_tick)
-{
-    std::unique_lock<std::mutex> sync_lock(lock);
-
-    trigger = t;
-    if (trigger != SyncTrigger::periodic) {
-        DPRINTF(MultiEthernet,"MultiIface::Sync::run() trigger:%d\n",
-                (unsigned)trigger);
-    }
-
-    switch (state) {
-      case SyncState::asyncCkpt:
-        switch (trigger) {
-          case SyncTrigger::ckpt:
-            assert(MultiIface::syncEvent->interrupted == false);
-            state = SyncState::busy;
-            break;
-          case SyncTrigger::periodic:
-            if (waitNum == 0) {
-                // So all recv threads got an async checkpoint request already
-                // and a simExit is scheduled at the end of the current tick
-                // (i.e. it is a periodic sync scheduled at the same tick as
-                // the simExit).
-                state = SyncState::idle;
-                DPRINTF(MultiEthernet,"MultiIface::Sync::run() interrupted "
-                "due to async ckpt scheduled\n");
-                return false;
-            } else {
-                // we still need to wait for some receiver thread to get the
-                // aysnc ckpt request. We are going to proceed as 'interrupted'
-                // periodic sync.
-                state = SyncState::interrupted;
-                DPRINTF(MultiEthernet,"MultiIface::Sync::run() interrupted "
-                "due to ckpt request is coming in\n");
-            }
-            break;
-          case SyncTrigger::atomic:
-            assert(trigger != SyncTrigger::atomic);
-        }
-        break;
-      case SyncState::idle:
-        state = SyncState::busy;
-        break;
-        // Only one sync can be active at any time
-      case SyncState::interrupted:
-      case SyncState::busy:
-        assert(state != SyncState::interrupted);
-        assert(state != SyncState::busy);
-        break;
-    }
-    // Kick-off the sync unless we are in the middle of an interrupted
-    // periodic sync
-    if (state != SyncState::interrupted) {
-        assert(waitNum == 0);
-        waitNum = MultiIface::recvThreadsNum;
-        // initiate the global synchronisation
-        assert(MultiIface::master != nullptr);
-        MultiIface::master->syncRaw(triggerToMsg[(unsigned)trigger], sync_tick);
-    }
-    // now wait until all receiver threads complete the synchronisation
-    auto lf = [this]{ return waitNum == 0; };
-    cv.wait(sync_lock, lf);
-
-    // we are done
-    assert(state == SyncState::busy || state == SyncState::interrupted);
-    bool ret = (state != SyncState::interrupted);
-    state = SyncState::idle;
-    return ret;
-}
-
-void
-MultiIface::Sync::progress(MsgType msg)
-{
-    std::unique_lock<std::mutex> sync_lock(lock);
-
-    switch (msg) {
-      case MsgType::cmdAtomicSyncAck:
-        assert(state == SyncState::busy && trigger == SyncTrigger::atomic);
-        break;
-      case MsgType::cmdPeriodicSyncAck:
-        assert(state == SyncState::busy && trigger == SyncTrigger::periodic);
-        break;
-      case MsgType::cmdCkptSyncAck:
-        assert(state == SyncState::busy && trigger == SyncTrigger::ckpt);
-        break;
-      case MsgType::cmdCkptSyncReq:
-        switch (state) {
-          case SyncState::busy:
-            if (trigger == SyncTrigger::ckpt) {
-                // We are already in a checkpoint sync but got another ckpt
-                // sync request. This may happen if two (or more) peer gem5
-                // processes try to start a ckpt nearly at the same time.
-                // Incrementing waitNum here (before decrementing it below)
-                // effectively results in ignoring this new ckpt sync request.
-                waitNum++;
-                break;
-            }
-            assert (waitNum == recvThreadsNum);
-            state = SyncState::interrupted;
-            // we need to fall over here to handle "recvThreadsNum == 1" case
-          case SyncState::interrupted:
-            assert(trigger == SyncTrigger::periodic);
-            assert(waitNum >= 1);
-            if (waitNum == 1) {
-                exitSimLoop("checkpoint");
-            }
-            break;
-          case SyncState::idle:
-            // There is no on-going sync so we got an async ckpt request. If we
-            // are the only receiver thread then we need to schedule the
-            // checkpoint. Otherwise, only change the state to 'asyncCkpt' and
-            // let the last receiver thread to schedule the checkpoint at the
-            // 'asyncCkpt' case.
-            // Note that a periodic or resume sync may start later and that can
-            // trigger a state change to 'interrupted' (so the checkpoint may
-            // get scheduled at 'interrupted' case finally).
-            assert(waitNum == 0);
-            state = SyncState::asyncCkpt;
-            waitNum = MultiIface::recvThreadsNum;
-            // we need to fall over here to handle "recvThreadsNum == 1" case
-          case SyncState::asyncCkpt:
-            assert(waitNum >= 1);
-            if (waitNum == 1)
-                exitSimLoop("checkpoint");
-            break;
-          default:
-            panic("Unexpected state for checkpoint request message");
-            break;
-        }
-        break;
-      default:
-        panic("Unknown msg type");
-        break;
-    }
-    waitNum--;
-    assert(state != SyncState::idle);
-    // Notify the simultaion thread if there is an on-going sync.
-    if (state != SyncState::asyncCkpt) {
-        sync_lock.unlock();
-        cv.notify_one();
-    }
-}
-
-void MultiIface::SyncEvent::start(Tick start, Tick interval)
-{
-    assert(!scheduled());
-    if (interval == 0)
-        panic("Multi synchronisation period must be greater than zero");
-    repeat = interval;
-    schedule(start);
-}
-
-void
-MultiIface::SyncEvent::adjust(Tick start_tick, Tick repeat_tick)
-{
-    // The new multi interface may require earlier start of the
-    // synchronisation.
-    assert(scheduled() == true);
-    if (start_tick < when())
-        reschedule(start_tick);
-    // The new multi interface may require more frequent synchronisation.
-    if (repeat == 0)
-        panic("Multi synchronisation period must be greater than zero");
-    if (repeat < repeat_tick)
-        repeat = repeat_tick;
-}
-
-void
-MultiIface::SyncEvent::process()
-{
-    /*
-     * Note that this is a global event so this process method will be called
-     * by only exactly one thread.
-     */
-    // if we are draining the system then we must not start a periodic sync (as
-    // it is not sure that all peer gem5 will reach this tick before taking
-    // the checkpoint).
-    if (isDraining == true) {
-        assert(interrupted == false);
-        interrupted = true;
-        DPRINTF(MultiEthernet,"MultiIface::SyncEvent::process() interrupted "
-                "due to draining\n");
-        return;
-    }
-    if (interrupted == false)
-        scheduledAt = curTick();
-    /*
-     * We hold the eventq lock at this point but the receiver thread may
-     * need the lock to schedule new recv events while waiting for the
-     * multi sync to complete.
-     * Note that the other simulation threads also release their eventq
-     * locks while waiting for us due to the global event semantics.
-     */
-    curEventQueue()->unlock();
-    // we do a global sync here
-    interrupted = !MultiIface::sync->run(SyncTrigger::periodic, scheduledAt);
-    // Global sync completed or got interrupted.
-    // we are expected to exit with the eventq lock held
-    curEventQueue()->lock();
-    // schedule the next global sync event if this one completed. Otherwise
-    // (i.e. this one was interrupted by a checkpoint request), we will 
-    // reschedule this one after the draining is complete.
-    if (!interrupted)
-        schedule(scheduledAt + repeat);
-}
-
-void MultiIface::SyncEvent::resume()
-{
-    Tick sync_tick;
-    assert(!scheduled());
-    if (interrupted) {
-        assert(curTick() >= scheduledAt);
-        // We have to complete the interrupted periodic sync asap.
-        // Note that this sync might be interrupted now again with a checkpoint
-        // request from a peer gem5...
-        sync_tick = curTick();
-        schedule(sync_tick);
-    } else {
-        // So we completed the last periodic sync, let's find  out the tick for
-        // next one
-        assert(curTick() > scheduledAt);
-        sync_tick = scheduledAt + repeat;
-        if (sync_tick < curTick())
-            panic("Cannot resume periodic synchronisation");
-        schedule(sync_tick);
-    }
-    DPRINTF(MultiEthernet,
-            "MultiIface::SyncEvent periodic sync resumed at %lld "
-            "(curTick:%lld)\n", sync_tick, curTick());
-}
-
-void MultiIface::SyncEvent::serialize(const std::string &base,
-                                      CheckpointOut &cp) const
-{
-    // Save the periodic multi sync schedule information
-    paramOut(cp, base + ".periodicSyncRepeat", repeat);
-    paramOut(cp, base + ".periodicSyncInterrupted", interrupted);
-    paramOut(cp, base + ".periodicSyncAt", scheduledAt);
-}
-
-void MultiIface::SyncEvent::unserialize(const std::string &base,
-                                        CheckpointIn &cp)
-{
-    paramIn(cp, base + ".periodicSyncRepeat", repeat);
-    paramIn(cp, base + ".periodicSyncInterrupted", interrupted);
-    paramIn(cp, base + ".periodicSyncAt", scheduledAt);
-}
-
-MultiIface::MultiIface(unsigned multi_rank,
-                       Tick sync_start,
-                       Tick sync_repeat,
-                       EventManager *em) :
-    syncStart(sync_start), syncRepeat(sync_repeat),
-    recvThread(nullptr), eventManager(em), recvDone(nullptr),
-    scheduledRecvPacket(nullptr), linkDelay(0), rank(multi_rank)
-{
-    DPRINTF(MultiEthernet, "MultiIface() ctor rank:%d\n",multi_rank);
-    if (master == nullptr) {
-        assert(sync == nullptr);
-        assert(syncEvent == nullptr);
-        sync = new Sync();
-        syncEvent = new SyncEvent();
-        master = this;
-    }
-}
-
-MultiIface::~MultiIface()
-{
-    assert(recvThread);
-    delete recvThread;
-    if (this == master) {
-        assert(syncEvent);
-        delete syncEvent;
-        assert(sync);
-        delete sync;
-    }
-}
-
-void
-MultiIface::packetOut(EthPacketPtr pkt, Tick send_delay)
-{
-    MultiHeaderPkt::Header header_pkt;
-    unsigned address_length = MultiHeaderPkt::maxAddressLength();
-
-    // Prepare a multi header packet for the Ethernet packet we want to
-    // send out.
-    header_pkt.msgType = MsgType::dataDescriptor;
-    header_pkt.sendTick  = curTick();
-    header_pkt.sendDelay = send_delay;
-
-    // Store also the source and destination addresses.
-    pkt->packAddress(header_pkt.srcAddress, header_pkt.dstAddress,
-                     address_length);
-
-    header_pkt.dataPacketLength = pkt->size();
-
-    // Send out the multi hedare packet followed by the Ethernet packet.
-    sendRaw(&header_pkt, sizeof(header_pkt), header_pkt.dstAddress);
-    sendRaw(pkt->data, pkt->size(), header_pkt.dstAddress);
-    DPRINTF(MultiEthernetPkt,
-            "MultiIface::sendDataPacket() done size:%d send_delay:%llu "
-            "src:0x%02x%02x%02x%02x%02x%02x "
-            "dst:0x%02x%02x%02x%02x%02x%02x\n",
-            pkt->size(), send_delay,
-            header_pkt.srcAddress[0], header_pkt.srcAddress[1],
-            header_pkt.srcAddress[2], header_pkt.srcAddress[3],
-            header_pkt.srcAddress[4], header_pkt.srcAddress[5],
-            header_pkt.dstAddress[0], header_pkt.dstAddress[1],
-            header_pkt.dstAddress[2], header_pkt.dstAddress[3],
-            header_pkt.dstAddress[4], header_pkt.dstAddress[5]);
-}
-
-bool
-MultiIface::recvHeader(MultiHeaderPkt::Header &header_pkt)
-{
-    // Blocking receive of an incoming multi header packet.
-    return recvRaw((void *)&header_pkt, sizeof(header_pkt));
-}
-
-void
-MultiIface::recvData(const MultiHeaderPkt::Header &header_pkt)
-{
-    // We are here beacuse a header packet has been received implying
-    // that an Ethernet (data) packet is coming in next.
-    assert(header_pkt.msgType == MsgType::dataDescriptor);
-    // Allocate storage for the incoming Ethernet packet.
-    EthPacketPtr new_packet(new EthPacketData(header_pkt.dataPacketLength));
-    // Now execute the blocking receive and store the incoming data directly
-    // in the new EthPacketData object.
-    if (! recvRaw((void *)(new_packet->data), header_pkt.dataPacketLength))
-        panic("Missing data packet");
-
-    new_packet->length = header_pkt.dataPacketLength;
-    // Grab the event queue lock to schedule a new receive event for the
-    // data packet.
-    curEventQueue()->lock();
-    // Compute the receive tick. It includes the send delay and the
-    // simulated link delay.
-    Tick recv_tick = header_pkt.sendTick + header_pkt.sendDelay + linkDelay;
-    DPRINTF(MultiEthernetPkt, "MultiIface::recvThread() packet receive, "
-            "send_tick:%llu send_delay:%llu link_delay:%llu recv_tick:%llu\n",
-            header_pkt.sendTick, header_pkt.sendDelay, linkDelay, recv_tick);
-
-    if (recv_tick <= curTick()) {
-        panic("Simulators out of sync - missed packet receive by %llu ticks",
-              curTick() - recv_tick);
-    }
-    // Now we are about to schedule a recvDone event for the new data packet.
-    // We use the same recvDone object for all incoming data packets. If
-    // that is already scheduled - i.e. a receive event for a previous
-    // data packet is already pending - then we have to check whether the
-    // receive tick for the new packet is earlier than that of the currently
-    // pending event. Packets may arrive out-of-order with respect to
-    // simulated receive time. If that is the case, we need to re-schedule the
-    // recvDone event for the new packet. Otherwise, we save the packet
-    // pointer and the recv tick for the new packet in the recvQueue. See
-    // the implementation of the packetIn() method for comments on how this
-    // information is retrieved from the recvQueue by the simulation thread.
-    if (!recvDone->scheduled()) {
-        assert(recvQueue.size() == 0);
-        assert(scheduledRecvPacket == nullptr);
-        scheduledRecvPacket = new_packet;
-        eventManager->schedule(recvDone, recv_tick);
-    } else if (recvDone->when() > recv_tick) {
-        recvQueue.emplace(scheduledRecvPacket, recvDone->when());
-        eventManager->reschedule(recvDone, recv_tick);
-        scheduledRecvPacket = new_packet;
-    } else {
-        recvQueue.emplace(new_packet, recv_tick);
-    }
-    curEventQueue()->unlock();
-}
-
-void
-MultiIface::recvThreadFunc()
-{
-    EthPacketPtr new_packet;
-    MultiHeaderPkt::Header header;
-
-    // The new receiver thread shares the event queue with the simulation
-    // thread (associated with the simulated Ethernet link).
-    curEventQueue(eventManager->eventQueue());
-    // Main loop to wait for and process any incoming message.
-    for (;;) {
-        // recvHeader() blocks until the next multi header packet comes in.
-        if (!recvHeader(header)) {
-            // We lost connection to the peer gem5 processes most likely
-            // because one of them called m5 exit. So we stop here.
-            exit_message("info", 0, "Message server closed connection, "
-                         "simulation is exiting");
-        }
-        // We got a valid multi header packet, let's process it
-        if (header.msgType == MsgType::dataDescriptor) {
-            recvData(header);
-        } else {
-            // everything else must be synchronisation related command
-            sync->progress(header.msgType);
-        }
-    }
-}
-
-EthPacketPtr
-MultiIface::packetIn()
-{
-    // We are called within the process() method of the recvDone event. We
-    // return the packet that triggered the current receive event.
-    // If there is further packets in the recvQueue, we also have to schedule
-    // the recvEvent for the next packet with the smallest receive tick.
-    // The priority queue container ensures that smallest receive tick is
-    // always on the top of the queue.
-    assert(scheduledRecvPacket != nullptr);
-    EthPacketPtr next_packet = scheduledRecvPacket;
-
-    if (! recvQueue.empty()) {
-        eventManager->schedule(recvDone, recvQueue.top().second);
-        scheduledRecvPacket = recvQueue.top().first;
-        recvQueue.pop();
-    } else {
-        scheduledRecvPacket = nullptr;
-    }
-
-    return next_packet;
-}
-
-void
-MultiIface::spawnRecvThread(Event *recv_done, Tick link_delay)
-{
-    assert(recvThread == nullptr);
-    // all receive thread must be spawned before simulation starts
-    assert(eventManager->eventQueue()->getCurTick() == 0);
-
-    recvDone = recv_done;
-    linkDelay = link_delay;
-
-    recvThread = new std::thread(&MultiIface::recvThreadFunc, this);
-
-    recvThreadsNum++;
-}
-
-DrainState
-MultiIface::drain()
-{
-    DPRINTF(MultiEthernet,"MultiIFace::drain() called\n");
-
-    // This can be called multiple times in the same drain cycle.
-    if (master == this) {
-        syncEvent->isDraining = true;
-    }
-
-    return DrainState::Drained;
-}
-
-void MultiIface::drainDone() {
-    if (master == this) {
-        assert(syncEvent->isDraining == true);
-        syncEvent->isDraining = false;
-        // We need to resume the interrupted periodic sync here now that the
-        // draining is done. If the last periodic sync completed before the
-        // checkpoint then the next one is already scheduled.
-        if (syncEvent->interrupted)
-            syncEvent->resume();
-    }
-}
-
-void MultiIface::serialize(const std::string &base, CheckpointOut &cp) const
-{
-    // Drain the multi interface before the checkpoint is taken. We cannot call
-    // this as part of the normal drain cycle because this multi sync has to be
-    // called exactly once after the system is fully drained.
-    // Note that every peer will take a checkpoint but they may take it at
-    // different ticks.
-    // This sync request may interrupt an on-going periodic sync in some peers.
-    sync->run(SyncTrigger::ckpt, curTick());
-
-    // Save the periodic multi sync status
-    syncEvent->serialize(base, cp);
-
-    unsigned n_rx_packets = recvQueue.size();
-    if (scheduledRecvPacket != nullptr)
-        n_rx_packets++;
-
-    paramOut(cp, base + ".nRxPackets", n_rx_packets);
-
-    if (n_rx_packets > 0) {
-        assert(recvDone->scheduled());
-        scheduledRecvPacket->serialize(base + ".rxPacket[0]", cp);
-    }
-
-    for (unsigned i=1; i < n_rx_packets; i++)  {
-        const RecvInfo recv_info = recvQueue.impl().at(i-1);
-        recv_info.first->serialize(base + csprintf(".rxPacket[%d]", i), cp);
-        Tick rx_tick = recv_info.second;
-        paramOut(cp, base + csprintf(".rxTick[%d]", i), rx_tick);
-    }
-}
-
-void MultiIface::unserialize(const std::string &base, CheckpointIn &cp)
-{
-    assert(recvQueue.size() == 0);
-    assert(scheduledRecvPacket == nullptr);
-    assert(recvDone->scheduled() == false);
-
-    // restore periodic sync info
-    syncEvent->unserialize(base, cp);
-
-    unsigned n_rx_packets;
-    paramIn(cp, base + ".nRxPackets", n_rx_packets);
-
-    if (n_rx_packets > 0) {
-        scheduledRecvPacket = std::make_shared<EthPacketData>(16384);
-        scheduledRecvPacket->unserialize(base + ".rxPacket[0]", cp);
-        // Note: receive event will be scheduled when the link is unserialized
-    }
-
-    for (unsigned i=1; i < n_rx_packets; i++) {
-        EthPacketPtr rx_packet = std::make_shared<EthPacketData>(16384);
-        rx_packet->unserialize(base + csprintf(".rxPacket[%d]", i), cp);
-        Tick rx_tick = 0;
-        paramIn(cp, base + csprintf(".rxTick[%d]", i), rx_tick);
-        assert(rx_tick > 0);
-        recvQueue.emplace(rx_packet,rx_tick);
-    }
-}
-
-void MultiIface::initRandom()
-{
-    // Initialize the seed for random generator to avoid the same sequence
-    // in all gem5 peer processes
-    assert(master != nullptr);
-    if (this == master)
-        random_mt.init(5489 * (rank+1) + 257);
-}
-
-void MultiIface::startPeriodicSync()
-{
-    DPRINTF(MultiEthernet, "MultiIface:::initPeriodicSync started\n");
-    // Do a global sync here to ensure that peer gem5 processes are around
-    // (actually this may not be needed...)
-    sync->run(SyncTrigger::atomic, curTick());
-
-    // Start the periodic sync if it is a fresh simulation from scratch
-    if (curTick() == 0) {
-        if (this == master) {
-        syncEvent->start(syncStart, syncRepeat);
-        inform("Multi synchronisation activated: start at %lld, "
-               "repeat at every %lld ticks.\n",
-               syncStart, syncRepeat);
-        } else {
-            // In case another multiIface object requires different schedule
-            // for periodic sync than the master does.
-            syncEvent->adjust(syncStart, syncRepeat);
-        }
-    } else {
-        // Schedule the next periodic sync if resuming from a checkpoint
-        if (this == master)
-            syncEvent->resume();
-    }
-    DPRINTF(MultiEthernet, "MultiIface::initPeriodicSync done\n");
-}
diff --git a/src/dev/multi_iface.hh b/src/dev/multi_iface.hh
deleted file mode 100644 (file)
index 5c7834d..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * The interface class for multi gem5 simulations.
- *
- * Multi gem5 is an extension to gem5 to enable parallel simulation of a
- * distributed system (e.g. simulation of a pool of machines
- * connected by Ethernet links). A multi gem5 run consists of seperate gem5
- * processes running in parallel. Each gem5 process executes
- * the simulation of a component of the simulated distributed system.
- * (An example component can be a multi-core board with an Ethernet NIC.)
- * The MultiIface class below provides services to transfer data and
- * control messages among the gem5 processes. The main such services are
- * as follows.
- *
- * 1. Send a data packet coming from a simulated Ethernet link. The packet
- * will be transferred to (all) the target(s) gem5 processes. The send
- * operation is always performed by the simulation thread, i.e. the gem5
- * thread that is processing the event queue associated with the simulated
- * Ethernet link.
- *
- * 2. Spawn a receiver thread to process messages coming in from the
- * from other gem5 processes. Each simulated Ethernet link has its own
- * associated receiver thread. The receiver thread saves the incoming packet
- * and schedule an appropriate receive event in the event queue.
- *
- * 3. Schedule a global barrier event periodically to keep the gem5
- * processes in sync.
- * Periodic barrier event to keep peer gem5 processes in sync. The basic idea
- * is that no gem5 process can go ahead further than the simulated link
- * transmission delay to ensure that a corresponding receive event can always
- * be scheduled for any message coming in from a peer gem5 process.
- *
- *
- *
- * This interface is an abstract class (sendRaw() and recvRaw()
- * methods are pure virtual). It can work with various low level
- * send/receive service implementations (e.g. TCP/IP, MPI,...). A TCP
- * stream socket version is implemented in dev/src/tcp_iface.[hh,cc].
- */
-#ifndef __DEV_MULTI_IFACE_HH__
-#define __DEV_MULTI_IFACE_HH__
-
-#include <array>
-#include <mutex>
-#include <queue>
-#include <thread>
-#include <utility>
-
-#include "dev/etherpkt.hh"
-#include "dev/multi_packet.hh"
-#include "sim/core.hh"
-#include "sim/drain.hh"
-#include "sim/global_event.hh"
-
-class EventManager;
-
-/**
- * The interface class to talk to peer gem5 processes.
- */
-class MultiIface : public Drainable
-{
-  public:
-    /*!
-     * The possible reasons a multi sync among gem5 peers is needed for.
-     */
-    enum
-    class SyncTrigger {
-        periodic, /*!< Regular periodic sync. This can be interrupted by a
-                   checkpoint sync request */
-        ckpt,     /*!< sync before taking a checkpoint */
-        atomic    /*!< sync that cannot be interrupted (e.g. sync at startup) */
-    };
-
-  private:
-    typedef MultiHeaderPkt::MsgType MsgType;
-
-    /** Sync State-Machine
-     \dot
-     digraph Sync {
-     node [shape=box, fontsize=10];
-     idle -> busy
-     [ label="new trigger\n by run()" fontsize=8 ];
-     busy -> busy
-     [ label="new message by progress():\n(msg == SyncAck &&\nwaitNum > 1) || \n(msg==CkptSyncReq &&\ntrigger == ckpt)" fontsize=8 ];
-     busy -> idle
-     [ label="new message by progress():\n(msg == SyncAck &&\nwaitNum == 1)" fontsize=8 ];
-     busy -> interrupted
-     [ label="new message by progress():\n(msg == CkptSyncReq &&\ntrigger == periodic)" fontsize=8 ];
-     idle -> asyncCkpt
-     [ label="new message by progress():\nmsg == CkptSyncReq" fontsize=8 ];
-     asyncCkpt -> asyncCkpt
-     [ label="new message by progress():\nmsg == CkptSyncReq" fontsize=8 ];
-     asyncCkpt -> busy
-     [ label="new trigger by run():\ntrigger == ckpt" fontsize=8 ];
-     asyncCkpt -> idle
-     [ label="new trigger by run():\n(trigger == periodic &&\nwaitNum == 0) " fontsize=8 ];
-     asyncCkpt -> interrupted
-     [ label="new trigger by run():\n(trigger == periodic &&\nwaitNum > 0) " fontsize=8 ];
-     interrupted -> interrupted
-     [ label="new message by progress():\n(msg == CkptSyncReq &&\nwaitNum > 1)" fontsize=8 ];
-     interrupted -> idle
-     [ label="new message by progress():\n(msg == CkptSyncReq &&\nwaitNum == 1)" fontsize=8 ];
-     }
-     \enddot
-     */
-    /** @class Sync
-     * This class implements global sync operations among gem5 peer processes.
-     *
-     * @note This class is used as a singleton object (shared by all MultiIface
-     * objects).
-     */
-    class Sync
-    {
-      private:
-        /*!
-         * Internal state of the sync singleton object.
-         */
-        enum class SyncState {
-            busy,        /*!< There is an on-going sync. */
-            interrupted, /*!< An on-going periodic sync was interrupted. */
-            asyncCkpt,   /*!< A checkpoint (sim_exit) is already scheduled */
-            idle         /*!< There is no active sync. */
-        };
-        /**
-         * The lock to protect access to the MultiSync object.
-         */
-        std::mutex lock;
-        /**
-         * Condition variable for the simulation thread to wait on
-         * until all receiver threads completes the current global
-         * synchronisation.
-         */
-        std::condition_variable cv;
-        /**
-         * Number of receiver threads that not yet completed the current global
-         * synchronisation.
-         */
-        unsigned waitNum;
-        /**
-         * The trigger for the most recent sync.
-         */
-        SyncTrigger trigger;
-        /**
-         * Map sync triggers to request messages.
-         */
-        std::array<MsgType, 3> triggerToMsg = {{
-                MsgType::cmdPeriodicSyncReq,
-                MsgType::cmdCkptSyncReq,
-                MsgType::cmdAtomicSyncReq
-            }};
-
-        /**
-         * Current sync state.
-         */
-        SyncState state;
-
-      public:
-        /**
-         *  Core method to perform a full multi sync.
-         *
-         * @param t Sync trigger.
-         * @param sync_tick The tick the sync was expected to happen at.
-         * @return true if the sync completed, false if it was interrupted.
-         *
-         * @note In case of an interrupted periodic sync, sync_tick can be less
-         * than curTick() when we resume (i.e. re-run) it
-         */
-        bool run(SyncTrigger t, Tick sync_tick);
-        /**
-         * Callback when the receiver thread gets a sync message.
-         */
-        void progress(MsgType m);
-
-        Sync() : waitNum(0), state(SyncState::idle) {}
-        ~Sync() {}
-    };
-
-
-    /**
-     * The global event to schedule peridic multi sync. It is used as a
-     * singleton object.
-     *
-     * The periodic synchronisation works as follows.
-     * 1. A MultisyncEvent is scheduled as a global event when startup() is
-     * called.
-     * 2. The progress() method of the MultisyncEvent initiates a new barrier
-     * for each simulated Ethernet links.
-     * 3. Simulation thread(s) then waits until all receiver threads
-     * completes the ongoing barrier. The global sync event is done.
-     */
-    class SyncEvent : public GlobalSyncEvent
-    {
-      public:
-        /**
-         * Flag to indicate that the most recent periodic sync was interrupted
-         * (by a checkpoint request).
-         */
-        bool interrupted;
-        /**
-         * The tick when the most recent periodic synchronisation was scheduled
-         * at.
-         */
-        Tick scheduledAt;
-        /**
-         * Flag to indicate an on-going drain cycle.
-         */
-         bool isDraining;
-
-      public:
-        /**
-         * Only the firstly instanstiated MultiIface object will
-         * call this constructor.
-         */
-        SyncEvent() : GlobalSyncEvent(Default_Pri, 0), interrupted(false),
-                      scheduledAt(0), isDraining(false) {}
-
-        ~SyncEvent() { assert (scheduled() == false); }
-        /**
-         * Schedule the first periodic sync event.
-         *
-         * @param start Start tick for multi synchronisation
-         * @param repeat Frequency of multi synchronisation
-         *
-         */
-        void start(Tick start, Tick repeat);
-        /**
-         * Reschedule (if necessary) the periodic sync event.
-         *
-         * @param start Start tick for multi synchronisation
-         * @param repeat Frequency of multi synchronisation
-         *
-         * @note Useful if we have multiple MultiIface objects with
-         * different 'start' and 'repeat' values for global sync.
-         */
-        void adjust(Tick start, Tick repeat);
-        /**
-         * This is a global event so process() will be called by each
-         * simulation threads. (See further comments in the .cc file.)
-         */
-        void process() override;
-        /**
-         * Schedule periodic sync when resuming from a checkpoint.
-         */
-        void resume();
-
-        void serialize(const std::string &base, CheckpointOut &cp) const;
-        void unserialize(const std::string &base, CheckpointIn &cp);
-    };
-
-    /**
-     * The receive thread needs to store the packet pointer and the computed
-     * receive tick for each incoming data packet. This information is used
-     * by the simulation thread when it processes the corresponding receive
-     * event. (See more comments at the implemetation of the recvThreadFunc()
-     * and RecvPacketIn() methods.)
-     */
-    typedef std::pair<EthPacketPtr, Tick> RecvInfo;
-
-    /**
-     * Comparison predicate for RecvInfo, needed by the recvQueue.
-     */
-    struct RecvInfoCompare {
-        bool operator()(const RecvInfo &lhs, const RecvInfo &rhs)
-        {
-            return lhs.second > rhs.second;
-        }
-    };
-
-    /**
-     * Customized priority queue used to store incoming data packets info by
-     * the receiver thread. We need to expose the underlying container to
-     * enable iterator access for serializing.
-     */
-    class RecvQueue : public std::priority_queue<RecvInfo,
-                                                 std::vector<RecvInfo>,
-                                                 RecvInfoCompare>
-    {
-      public:
-        std::vector<RecvInfo> &impl() { return c; }
-        const std::vector<RecvInfo> &impl() const { return c; }
-    };
-
-    /*
-     * The priority queue to store RecvInfo items ordered by receive ticks.
-     */
-    RecvQueue recvQueue;
-    /**
-     * The singleton Sync object to perform multi synchronisation.
-     */
-    static Sync *sync;
-    /**
-     * The singleton SyncEvent object to schedule periodic multi sync.
-     */
-    static SyncEvent *syncEvent;
-    /**
-     * Tick to schedule the first multi sync event.
-     * This is just as optimization : we do not need any multi sync
-     * event until the simulated NIC is brought up by the OS.
-     */
-    Tick syncStart;
-    /**
-     * Frequency of multi sync events in ticks.
-     */
-    Tick syncRepeat;
-    /**
-     * Receiver thread pointer.
-     * Each MultiIface object must have exactly one receiver thread.
-     */
-    std::thread *recvThread;
-    /**
-     * The event manager associated with the MultiIface object.
-     */
-    EventManager *eventManager;
-
-    /**
-     * The receive done event for the simulated Ethernet link.
-     * It is scheduled by the receiver thread for each incoming data
-     * packet.
-     */
-    Event *recvDone;
-
-    /**
-     * The packet that belongs to the currently scheduled recvDone event.
-     */
-    EthPacketPtr scheduledRecvPacket;
-
-    /**
-     * The link delay in ticks for the simulated Ethernet link.
-     */
-    Tick linkDelay;
-
-    /**
-     * The rank of this process among the gem5 peers.
-     */
-    unsigned rank;
-    /**
-     * Total number of receiver threads (in this gem5 process).
-     * During the simulation it should be constant and equal to the
-     * number of MultiIface objects (i.e. simulated Ethernet
-     * links).
-     */
-    static unsigned recvThreadsNum;
-    /**
-     * The very first MultiIface object created becomes the master. We need
-     * a master to co-ordinate the global synchronisation.
-     */
-    static MultiIface *master;
-
-  protected:
-    /**
-     * Low level generic send routine.
-     * @param buf buffer that holds the data to send out
-     * @param length number of bytes to send
-     * @param dest_addr address of the target (simulated NIC). This may be
-     * used by a subclass for optimization (e.g. optimize broadcast)
-     */
-    virtual void sendRaw(void *buf,
-                         unsigned length,
-                         const MultiHeaderPkt::AddressType dest_addr) = 0;
-    /**
-     * Low level generic receive routine.
-     * @param buf the buffer to store the incoming message
-     * @param length buffer size (in bytes)
-     */
-    virtual bool recvRaw(void *buf, unsigned length) = 0;
-    /**
-     * Low level request for synchronisation among gem5 processes. Only one
-     * MultiIface object needs to call this (in each gem5 process) to trigger
-     * a multi sync.
-     *
-     * @param sync_req Sync request command.
-     * @param sync_tick The tick when sync is expected to happen in the sender.
-     */
-    virtual void syncRaw(MsgType sync_req, Tick sync_tick) = 0;
-    /**
-     * The function executed by a receiver thread.
-     */
-    void recvThreadFunc();
-    /**
-     * Receive a multi header packet. Called by the receiver thread.
-     * @param header the structure to store the incoming header packet.
-     * @return false if any error occured during the receive, true otherwise
-     *
-     * A header packet can carry a control command (e.g. 'barrier leave') or
-     * information about a data packet that is following the header packet
-     * back to back.
-     */
-    bool recvHeader(MultiHeaderPkt::Header &header);
-    /**
-     * Receive a data packet. Called by the receiver thread.
-     * @param data_header The packet descriptor for the expected incoming data
-     * packet.
-     */
-    void recvData(const MultiHeaderPkt::Header &data_header);
-
-  public:
-
-    /**
-     * ctor
-     * @param multi_rank Rank of this gem5 process within the multi run
-     * @param sync_start Start tick for multi synchronisation
-     * @param sync_repeat Frequency for multi synchronisation
-     * @param em The event manager associated with the simulated Ethernet link
-     */
-    MultiIface(unsigned multi_rank,
-               Tick sync_start,
-               Tick sync_repeat,
-               EventManager *em);
-
-    virtual ~MultiIface();
-    /**
-     * Send out an Ethernet packet.
-     * @param pkt The Ethernet packet to send.
-     * @param send_delay The delay in ticks for the send completion event.
-     */
-    void packetOut(EthPacketPtr pkt, Tick send_delay);
-    /**
-     * Fetch the next packet from the receive queue.
-     */
-    EthPacketPtr packetIn();
-
-    /**
-     * spawn the receiver thread.
-     * @param recv_done The receive done event associated with the simulated
-     * Ethernet link.
-     * @param link_delay The link delay for the simulated Ethernet link.
-     */
-    void spawnRecvThread(Event *recv_done,
-                         Tick link_delay);
-    /**
-     * Initialize the random number generator with a different seed in each
-     * peer gem5 process.
-     */
-    void initRandom();
-
-    DrainState drain() override;
-
-    /**
-     * Callback when draining is complete.
-     */
-    void drainDone();
-
-    /**
-     * Initialize the periodic synchronisation among peer gem5 processes.
-     */
-    void startPeriodicSync();
-
-    void serialize(const std::string &base, CheckpointOut &cp) const;
-    void unserialize(const std::string &base, CheckpointIn &cp);
-
-};
-
-
-#endif
diff --git a/src/dev/multi_packet.cc b/src/dev/multi_packet.cc
deleted file mode 100644 (file)
index 1fd0c0e..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * MultiHeaderPkt class to encapsulate multi-gem5 header packets
- *
- */
-
-#include "dev/multi_packet.hh"
-
-#include <cstdint>
-#include <cstring>
-
-#include "base/inet.hh"
-
-unsigned
-MultiHeaderPkt::maxAddressLength()
-{
-    return sizeof(AddressType);
-}
-
-void
-MultiHeaderPkt::clearAddress(AddressType &addr)
-{
-    std::memset(addr, 0, sizeof(addr));
-}
-
-bool
-MultiHeaderPkt::isAddressEqual(const AddressType &addr1,
-                               const AddressType &addr2)
-{
-    return (std::memcmp(addr1, addr2, sizeof(addr1)) == 0);
-}
-
-bool
-MultiHeaderPkt::isAddressLess(const AddressType &addr1,
-                              const AddressType &addr2)
-{
-    return (std::memcmp(addr1, addr2, sizeof(addr1)) < 0);
-}
-
-void
-MultiHeaderPkt::copyAddress(AddressType &dest, const AddressType &src)
-{
-    std::memcpy(dest, src, sizeof(dest));
-}
-
-bool
-MultiHeaderPkt::isBroadcastAddress(const AddressType &addr)
-{
-    return ((Net::EthAddr *)&addr)->broadcast();
-}
-
-bool
-MultiHeaderPkt::isMulticastAddress(const AddressType &addr)
-{
-    return ((Net::EthAddr *)&addr)->multicast();
-}
-
-bool
-MultiHeaderPkt::isUnicastAddress(const AddressType &addr)
-{
-    return ((Net::EthAddr *)&addr)->unicast();
-}
diff --git a/src/dev/multi_packet.hh b/src/dev/multi_packet.hh
deleted file mode 100644 (file)
index 4b27064..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * Header packet class for multi gem5 runs.
- *
- * For a high level description about multi gem5 see comments in
- * header file multi_iface.hh.
- *
- * The MultiHeaderPkt class defines the format of message headers
- * sent among gem5 processes during a multi gem5 simulation. A header packet
- * can either carry the description of data packet (i.e. a simulated Ethernet
- * packet) or a synchronisation related control command. In case of
- * data packet description, the corresponding data packet always follows
- * the header packet back-to-back.
- */
-#ifndef __DEV_MULTI_PACKET_HH__
-#define __DEV_MULTI_PACKET_HH__
-
-#include <cstring>
-
-#include "base/types.hh"
-
-class MultiHeaderPkt
-{
-  private:
-    MultiHeaderPkt() {}
-    ~MultiHeaderPkt() {}
-
-  public:
-    /**
-     * Simply type to help with calculating space requirements for
-     * the corresponding header field.
-     */
-    typedef uint8_t AddressType[6];
-
-    /**
-     *  The msg type defines what informarion a multi header packet carries.
-     */
-    enum class MsgType
-    {
-        dataDescriptor,
-        cmdPeriodicSyncReq,
-        cmdPeriodicSyncAck,
-        cmdCkptSyncReq,
-        cmdCkptSyncAck,
-        cmdAtomicSyncReq,
-        cmdAtomicSyncAck,
-        unknown
-    };
-
-    struct Header
-    {
-        /**
-         * The msg type field is valid for all header packets. In case of
-         * a synchronisation control command this is the only valid field.
-         */
-        MsgType msgType;
-        Tick sendTick;
-        Tick sendDelay;
-        /**
-         * Actual length of the simulated Ethernet packet.
-         */
-        unsigned dataPacketLength;
-        /**
-         * Source MAC address.
-         */
-        AddressType srcAddress;
-        /**
-         * Destination MAC address.
-         */
-        AddressType dstAddress;
-    };
-
-    static unsigned maxAddressLength();
-
-    /**
-     * Static functions for manipulating and comparing MAC addresses.
-     */
-    static void clearAddress(AddressType &addr);
-    static bool isAddressEqual(const AddressType &addr1,
-                               const AddressType &addr2);
-    static bool isAddressLess(const AddressType &addr1,
-                              const AddressType &addr2);
-
-    static void copyAddress(AddressType &dest,
-                            const AddressType &src);
-
-    static bool isUnicastAddress(const AddressType &addr);
-    static bool isMulticastAddress(const AddressType &addr);
-    static bool isBroadcastAddress(const AddressType &addr);
-};
-
-#endif
diff --git a/src/dev/net/Ethernet.py b/src/dev/net/Ethernet.py
new file mode 100644 (file)
index 0000000..9859857
--- /dev/null
@@ -0,0 +1,245 @@
+# Copyright (c) 2015 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Copyright (c) 2005-2007 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+
+from m5.SimObject import SimObject
+from m5.params import *
+from m5.proxy import *
+from PciDevice import PciDevice
+
+class EtherObject(SimObject):
+    type = 'EtherObject'
+    abstract = True
+    cxx_header = "dev/net/etherobject.hh"
+
+class EtherLink(EtherObject):
+    type = 'EtherLink'
+    cxx_header = "dev/net/etherlink.hh"
+    int0 = SlavePort("interface 0")
+    int1 = SlavePort("interface 1")
+    delay = Param.Latency('0us', "packet transmit delay")
+    delay_var = Param.Latency('0ns', "packet transmit delay variability")
+    speed = Param.NetworkBandwidth('1Gbps', "link speed")
+    dump = Param.EtherDump(NULL, "dump object")
+
+class MultiEtherLink(EtherObject):
+    type = 'MultiEtherLink'
+    cxx_header = "dev/net/multi_etherlink.hh"
+    int0 = SlavePort("interface 0")
+    delay = Param.Latency('0us', "packet transmit delay")
+    delay_var = Param.Latency('0ns', "packet transmit delay variability")
+    speed = Param.NetworkBandwidth('1Gbps', "link speed")
+    dump = Param.EtherDump(NULL, "dump object")
+    multi_rank  =  Param.UInt32('0', "Rank of the this gem5 process (multi run)")
+    sync_start  = Param.Latency('5200000000000t', "first multi sync barrier")
+    sync_repeat = Param.Latency('10us', "multi sync barrier repeat")
+    server_name = Param.String('localhost', "Message server name")
+    server_port = Param.UInt32('2200', "Message server port")
+
+class EtherBus(EtherObject):
+    type = 'EtherBus'
+    cxx_header = "dev/net/etherbus.hh"
+    loopback = Param.Bool(True, "send packet back to the sending interface")
+    dump = Param.EtherDump(NULL, "dump object")
+    speed = Param.NetworkBandwidth('100Mbps', "bus speed in bits per second")
+
+class EtherTap(EtherObject):
+    type = 'EtherTap'
+    cxx_header = "dev/net/ethertap.hh"
+    bufsz = Param.Int(10000, "tap buffer size")
+    dump = Param.EtherDump(NULL, "dump object")
+    port = Param.UInt16(3500, "tap port")
+
+class EtherDump(SimObject):
+    type = 'EtherDump'
+    cxx_header = "dev/net/etherdump.hh"
+    file = Param.String("dump file")
+    maxlen = Param.Int(96, "max portion of packet data to dump")
+
+class EtherDevice(PciDevice):
+    type = 'EtherDevice'
+    abstract = True
+    cxx_header = "dev/net/etherdevice.hh"
+    interface = MasterPort("Ethernet Interface")
+
+class IGbE(EtherDevice):
+    # Base class for two IGbE adapters listed above
+    type = 'IGbE'
+    cxx_header = "dev/net/i8254xGBe.hh"
+    hardware_address = Param.EthernetAddr(NextEthernetAddr,
+        "Ethernet Hardware Address")
+    rx_fifo_size = Param.MemorySize('384kB', "Size of the rx FIFO")
+    tx_fifo_size = Param.MemorySize('384kB', "Size of the tx FIFO")
+    rx_desc_cache_size = Param.Int(64,
+        "Number of enteries in the rx descriptor cache")
+    tx_desc_cache_size = Param.Int(64,
+        "Number of enteries in the rx descriptor cache")
+    VendorID = 0x8086
+    SubsystemID = 0x1008
+    SubsystemVendorID = 0x8086
+    Status = 0x0000
+    SubClassCode = 0x00
+    ClassCode = 0x02
+    ProgIF = 0x00
+    BAR0 = 0x00000000
+    BAR1 = 0x00000000
+    BAR2 = 0x00000000
+    BAR3 = 0x00000000
+    BAR4 = 0x00000000
+    BAR5 = 0x00000000
+    MaximumLatency = 0x00
+    MinimumGrant = 0xff
+    InterruptLine = 0x1e
+    InterruptPin = 0x01
+    BAR0Size = '128kB'
+    wb_delay = Param.Latency('10ns', "delay before desc writeback occurs")
+    fetch_delay = Param.Latency('10ns', "delay before desc fetch occurs")
+    fetch_comp_delay = Param.Latency('10ns', "delay after desc fetch occurs")
+    wb_comp_delay = Param.Latency('10ns', "delay after desc wb occurs")
+    tx_read_delay = Param.Latency('0ns', "delay after tx dma read")
+    rx_write_delay = Param.Latency('0ns', "delay after rx dma read")
+    phy_pid = Param.UInt16("Phy PID that corresponds to device ID")
+    phy_epid = Param.UInt16("Phy EPID that corresponds to device ID")
+
+class IGbE_e1000(IGbE):
+    # Older Intel 8254x based gigabit ethernet adapter
+    # Uses Intel e1000 driver
+    DeviceID = 0x1075
+    phy_pid = 0x02A8
+    phy_epid = 0x0380
+
+class IGbE_igb(IGbE):
+    # Newer Intel 8257x based gigabit ethernet adapter
+    # Uses Intel igb driver and in theory supports packet splitting and LRO
+    DeviceID = 0x10C9
+    phy_pid = 0x0141
+    phy_epid = 0x0CC0
+
+class EtherDevBase(EtherDevice):
+    type = 'EtherDevBase'
+    abstract = True
+    cxx_header = "dev/net/etherdevice.hh"
+
+    hardware_address = Param.EthernetAddr(NextEthernetAddr,
+        "Ethernet Hardware Address")
+
+    dma_read_delay = Param.Latency('0us', "fixed delay for dma reads")
+    dma_read_factor = Param.Latency('0us', "multiplier for dma reads")
+    dma_write_delay = Param.Latency('0us', "fixed delay for dma writes")
+    dma_write_factor = Param.Latency('0us', "multiplier for dma writes")
+
+    rx_delay = Param.Latency('1us', "Receive Delay")
+    tx_delay = Param.Latency('1us', "Transmit Delay")
+    rx_fifo_size = Param.MemorySize('512kB', "max size of rx fifo")
+    tx_fifo_size = Param.MemorySize('512kB', "max size of tx fifo")
+
+    rx_filter = Param.Bool(True, "Enable Receive Filter")
+    intr_delay = Param.Latency('10us', "Interrupt propagation delay")
+    rx_thread = Param.Bool(False, "dedicated kernel thread for transmit")
+    tx_thread = Param.Bool(False, "dedicated kernel threads for receive")
+    rss = Param.Bool(False, "Receive Side Scaling")
+
+class NSGigE(EtherDevBase):
+    type = 'NSGigE'
+    cxx_header = "dev/net/ns_gige.hh"
+
+    dma_data_free = Param.Bool(False, "DMA of Data is free")
+    dma_desc_free = Param.Bool(False, "DMA of Descriptors is free")
+    dma_no_allocate = Param.Bool(True, "Should we allocate cache on read")
+
+    VendorID = 0x100B
+    DeviceID = 0x0022
+    Status = 0x0290
+    SubClassCode = 0x00
+    ClassCode = 0x02
+    ProgIF = 0x00
+    BAR0 = 0x00000001
+    BAR1 = 0x00000000
+    BAR2 = 0x00000000
+    BAR3 = 0x00000000
+    BAR4 = 0x00000000
+    BAR5 = 0x00000000
+    MaximumLatency = 0x34
+    MinimumGrant = 0xb0
+    InterruptLine = 0x1e
+    InterruptPin = 0x01
+    BAR0Size = '256B'
+    BAR1Size = '4kB'
+
+
+
+class Sinic(EtherDevBase):
+    type = 'Sinic'
+    cxx_class = 'Sinic::Device'
+    cxx_header = "dev/net/sinic.hh"
+
+    rx_max_copy = Param.MemorySize('1514B', "rx max copy")
+    tx_max_copy = Param.MemorySize('16kB', "tx max copy")
+    rx_max_intr = Param.UInt32(10, "max rx packets per interrupt")
+    rx_fifo_threshold = Param.MemorySize('384kB', "rx fifo high threshold")
+    rx_fifo_low_mark = Param.MemorySize('128kB', "rx fifo low threshold")
+    tx_fifo_high_mark = Param.MemorySize('384kB', "tx fifo high threshold")
+    tx_fifo_threshold = Param.MemorySize('128kB', "tx fifo low threshold")
+    virtual_count = Param.UInt32(1, "Virtualized SINIC")
+    zero_copy_size = Param.UInt32(64, "Bytes to copy if below threshold")
+    zero_copy_threshold = Param.UInt32(256,
+        "Only zero copy above this threshold")
+    zero_copy = Param.Bool(False, "Zero copy receive")
+    delay_copy = Param.Bool(False, "Delayed copy transmit")
+    virtual_addr = Param.Bool(False, "Virtual addressing")
+
+    VendorID = 0x1291
+    DeviceID = 0x1293
+    Status = 0x0290
+    SubClassCode = 0x00
+    ClassCode = 0x02
+    ProgIF = 0x00
+    BAR0 = 0x00000000
+    BAR1 = 0x00000000
+    BAR2 = 0x00000000
+    BAR3 = 0x00000000
+    BAR4 = 0x00000000
+    BAR5 = 0x00000000
+    MaximumLatency = 0x34
+    MinimumGrant = 0xb0
+    InterruptLine = 0x1e
+    InterruptPin = 0x01
+    BAR0Size = '64kB'
+
+
diff --git a/src/dev/net/SConscript b/src/dev/net/SConscript
new file mode 100644 (file)
index 0000000..f529a1b
--- /dev/null
@@ -0,0 +1,94 @@
+# -*- mode:python -*-
+
+# Copyright (c) 2015 ARM Limited
+# All rights reserved.
+#
+# The license below extends only to copyright in the software and shall
+# not be construed as granting a license to any other intellectual
+# property including but not limited to intellectual property relating
+# to a hardware implementation of the functionality of the software
+# licensed hereunder.  You may use the software subject to the license
+# terms below provided that you ensure that this notice is replicated
+# unmodified and in its entirety in all distributions of the software,
+# modified or unmodified, in source code or in binary form.
+#
+# Copyright (c) 2006 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Steve Reinhardt
+#          Gabe Black
+#          Andreas Sandberg
+
+Import('*')
+
+if env['TARGET_ISA'] == 'null':
+    Return()
+
+SimObject('Ethernet.py')
+
+# Basic Ethernet infrastructure
+Source('etherbus.cc')
+Source('etherdevice.cc')
+Source('etherdump.cc')
+Source('etherint.cc')
+Source('etherlink.cc')
+Source('etherpkt.cc')
+Source('ethertap.cc')
+
+Source('pktfifo.cc')
+
+DebugFlag('Ethernet')
+DebugFlag('EthernetCksum')
+DebugFlag('EthernetDMA')
+DebugFlag('EthernetData')
+DebugFlag('EthernetDesc')
+DebugFlag('EthernetEEPROM')
+DebugFlag('EthernetIntr')
+DebugFlag('EthernetPIO')
+DebugFlag('EthernetSM')
+
+# Multi gem5
+Source('multi_packet.cc')
+Source('multi_iface.cc')
+Source('multi_etherlink.cc')
+Source('tcp_iface.cc')
+
+DebugFlag('MultiEthernet')
+DebugFlag('MultiEthernetPkt')
+
+# Ethernet controllers
+Source('i8254xGBe.cc')
+Source('ns_gige.cc')
+Source('sinic.cc')
+
+
+
+CompoundFlag('EthernetAll', [ 'Ethernet', 'EthernetPIO', 'EthernetDMA',
+    'EthernetData' , 'EthernetDesc', 'EthernetIntr', 'EthernetSM',
+    'EthernetCksum', 'EthernetEEPROM' ])
+
+CompoundFlag('EthernetNoData', [ 'Ethernet', 'EthernetPIO', 'EthernetDesc',
+    'EthernetIntr', 'EthernetSM', 'EthernetCksum' ])
diff --git a/src/dev/net/etherbus.cc b/src/dev/net/etherbus.cc
new file mode 100644 (file)
index 0000000..ba5beab
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+#include "dev/net/etherbus.hh"
+
+#include <cmath>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/trace.hh"
+#include "debug/Ethernet.hh"
+#include "debug/EthernetData.hh"
+#include "dev/net/etherdump.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+#include "params/EtherBus.hh"
+#include "sim/core.hh"
+
+using namespace std;
+
+EtherBus::EtherBus(const Params *p)
+    : EtherObject(p), ticksPerByte(p->speed), loopback(p->loopback),
+      event(this), sender(0), dump(p->dump)
+{
+}
+
+void
+EtherBus::txDone()
+{
+    devlist_t::iterator i = devlist.begin();
+    devlist_t::iterator end = devlist.end();
+
+    DPRINTF(Ethernet, "ethernet packet received: length=%d\n", packet->length);
+    DDUMP(EthernetData, packet->data, packet->length);
+
+    while (i != end) {
+        if (loopback || *i != sender)
+            (*i)->sendPacket(packet);
+        ++i;
+    }
+
+    sender->sendDone();
+
+    if (dump)
+        dump->dump(packet);
+
+    sender = 0;
+    packet = 0;
+}
+
+EtherInt*
+EtherBus::getEthPort(const std::string &if_name, int idx)
+{
+    panic("Etherbus doesn't work\n");
+}
+
+bool
+EtherBus::send(EtherInt *sndr, EthPacketPtr &pkt)
+{
+    if (busy()) {
+        DPRINTF(Ethernet, "ethernet packet not sent, bus busy\n", curTick());
+        return false;
+    }
+
+    DPRINTF(Ethernet, "ethernet packet sent: length=%d\n", pkt->length);
+    DDUMP(EthernetData, pkt->data, pkt->length);
+
+    packet = pkt;
+    sender = sndr;
+    int delay = (int)ceil(((double)pkt->length * ticksPerByte) + 1.0);
+    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+            delay, ticksPerByte);
+    schedule(event, curTick() + delay);
+
+    return true;
+}
+
+EtherBus *
+EtherBusParams::create()
+{
+    return new EtherBus(this);
+}
diff --git a/src/dev/net/etherbus.hh b/src/dev/net/etherbus.hh
new file mode 100644 (file)
index 0000000..7395c28
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Device module for modelling an ethernet hub
+ */
+
+#ifndef __DEV_NET_ETHERBUS_HH__
+#define __DEV_NET_ETHERBUS_HH__
+
+#include "dev/net/etherobject.hh"
+#include "dev/net/etherpkt.hh"
+#include "params/EtherBus.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class EtherDump;
+class EtherInt;
+class EtherBus : public EtherObject
+{
+  protected:
+    typedef std::list<EtherInt *> devlist_t;
+    devlist_t devlist;
+    double ticksPerByte;
+    bool loopback;
+
+  protected:
+    class DoneEvent : public Event
+    {
+      protected:
+        EtherBus *bus;
+
+      public:
+        DoneEvent(EtherBus *b) : bus(b) {}
+        virtual void process() { bus->txDone(); }
+        virtual const char *description() const
+            { return "ethernet bus completion"; }
+    };
+
+    DoneEvent event;
+    EthPacketPtr packet;
+    EtherInt *sender;
+    EtherDump *dump;
+
+  public:
+    typedef EtherBusParams Params;
+    EtherBus(const Params *p);
+    virtual ~EtherBus() {}
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    void txDone();
+    void reg(EtherInt *dev);
+    bool busy() const { return (bool)packet; }
+    bool send(EtherInt *sender, EthPacketPtr &packet);
+    virtual EtherInt *getEthPort(const std::string &if_name, int idx);
+};
+
+#endif // __DEV_NET_ETHERBUS_HH__
diff --git a/src/dev/net/etherdevice.cc b/src/dev/net/etherdevice.cc
new file mode 100644 (file)
index 0000000..5984950
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Lisa Hsu
+ */
+
+#include "dev/net/etherdevice.hh"
+
+#include "sim/stats.hh"
+
+void
+EtherDevice::regStats()
+{
+    txBytes
+        .name(name() + ".txBytes")
+        .desc("Bytes Transmitted")
+        .prereq(txBytes)
+        ;
+
+    rxBytes
+        .name(name() + ".rxBytes")
+        .desc("Bytes Received")
+        .prereq(rxBytes)
+        ;
+
+    txPackets
+        .name(name() + ".txPackets")
+        .desc("Number of Packets Transmitted")
+        .prereq(txBytes)
+        ;
+
+    rxPackets
+        .name(name() + ".rxPackets")
+        .desc("Number of Packets Received")
+        .prereq(rxBytes)
+        ;
+
+    txIpChecksums
+        .name(name() + ".txIpChecksums")
+        .desc("Number of tx IP Checksums done by device")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxIpChecksums
+        .name(name() + ".rxIpChecksums")
+        .desc("Number of rx IP Checksums done by device")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    txTcpChecksums
+        .name(name() + ".txTcpChecksums")
+        .desc("Number of tx TCP Checksums done by device")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxTcpChecksums
+        .name(name() + ".rxTcpChecksums")
+        .desc("Number of rx TCP Checksums done by device")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    txUdpChecksums
+        .name(name() + ".txUdpChecksums")
+        .desc("Number of tx UDP Checksums done by device")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxUdpChecksums
+        .name(name() + ".rxUdpChecksums")
+        .desc("Number of rx UDP Checksums done by device")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    descDmaReads
+        .name(name() + ".descDMAReads")
+        .desc("Number of descriptors the device read w/ DMA")
+        .precision(0)
+        ;
+
+    descDmaWrites
+        .name(name() + ".descDMAWrites")
+        .desc("Number of descriptors the device wrote w/ DMA")
+        .precision(0)
+        ;
+
+    descDmaRdBytes
+        .name(name() + ".descDmaReadBytes")
+        .desc("number of descriptor bytes read w/ DMA")
+        .precision(0)
+        ;
+
+    descDmaWrBytes
+        .name(name() + ".descDmaWriteBytes")
+        .desc("number of descriptor bytes write w/ DMA")
+        .precision(0)
+        ;
+
+    txBandwidth
+        .name(name() + ".txBandwidth")
+        .desc("Transmit Bandwidth (bits/s)")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxBandwidth
+        .name(name() + ".rxBandwidth")
+        .desc("Receive Bandwidth (bits/s)")
+        .precision(0)
+        .prereq(rxBytes)
+        ;
+
+    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)")
+        .precision(0)
+        .prereq(txBytes)
+        ;
+
+    rxPacketRate
+        .name(name() + ".rxPPS")
+        .desc("Packet Reception Rate (packets/s)")
+        .precision(0)
+        .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;
+    totPacketRate = totPackets / simSeconds;
+}
diff --git a/src/dev/net/etherdevice.hh b/src/dev/net/etherdevice.hh
new file mode 100644 (file)
index 0000000..d13a1c3
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2007 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/**
+ * @file
+ * Base Ethernet Device declaration.
+ */
+
+#ifndef __DEV_NET_ETHERDEVICE_HH__
+#define __DEV_NET_ETHERDEVICE_HH__
+
+#include "base/statistics.hh"
+#include "dev/pci/device.hh"
+#include "params/EtherDevBase.hh"
+#include "params/EtherDevice.hh"
+#include "sim/sim_object.hh"
+
+class EtherInt;
+
+/**
+ * The base EtherObject class, allows for an accesor function to a
+ * simobj that returns the Port.
+ */
+class EtherDevice : public PciDevice
+{
+  public:
+    typedef EtherDeviceParams Params;
+    EtherDevice(const Params *params)
+        : PciDevice(params)
+    {}
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+  public:
+    /** Additional function to return the Port of a memory object. */
+    virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
+
+  public:
+    void regStats();
+
+  protected:
+    Stats::Scalar txBytes;
+    Stats::Scalar rxBytes;
+    Stats::Scalar txPackets;
+    Stats::Scalar rxPackets;
+    Stats::Scalar txIpChecksums;
+    Stats::Scalar rxIpChecksums;
+    Stats::Scalar txTcpChecksums;
+    Stats::Scalar rxTcpChecksums;
+    Stats::Scalar txUdpChecksums;
+    Stats::Scalar rxUdpChecksums;
+    Stats::Scalar descDmaReads;
+    Stats::Scalar descDmaWrites;
+    Stats::Scalar descDmaRdBytes;
+    Stats::Scalar descDmaWrBytes;
+    Stats::Formula totBandwidth;
+    Stats::Formula totPackets;
+    Stats::Formula totBytes;
+    Stats::Formula totPacketRate;
+    Stats::Formula txBandwidth;
+    Stats::Formula rxBandwidth;
+    Stats::Formula txPacketRate;
+    Stats::Formula rxPacketRate;
+    Stats::Scalar postedSwi;
+    Stats::Formula coalescedSwi;
+    Stats::Scalar totalSwi;
+    Stats::Scalar postedRxIdle;
+    Stats::Formula coalescedRxIdle;
+    Stats::Scalar totalRxIdle;
+    Stats::Scalar postedRxOk;
+    Stats::Formula coalescedRxOk;
+    Stats::Scalar totalRxOk;
+    Stats::Scalar postedRxDesc;
+    Stats::Formula coalescedRxDesc;
+    Stats::Scalar totalRxDesc;
+    Stats::Scalar postedTxOk;
+    Stats::Formula coalescedTxOk;
+    Stats::Scalar totalTxOk;
+    Stats::Scalar postedTxIdle;
+    Stats::Formula coalescedTxIdle;
+    Stats::Scalar totalTxIdle;
+    Stats::Scalar postedTxDesc;
+    Stats::Formula coalescedTxDesc;
+    Stats::Scalar totalTxDesc;
+    Stats::Scalar postedRxOrn;
+    Stats::Formula coalescedRxOrn;
+    Stats::Scalar totalRxOrn;
+    Stats::Formula coalescedTotal;
+    Stats::Scalar postedInterrupts;
+    Stats::Scalar droppedPackets;
+};
+
+/**
+ * Dummy class to keep the Python class hierarchy in sync with the C++
+ * object hierarchy.
+ *
+ * The Python object hierarchy includes the EtherDevBase class which
+ * is used by some ethernet devices as a way to share common
+ * configuration information in the generated param structs. Since the
+ * Python hierarchy is used to generate a SWIG interface for all C++
+ * SimObjects, we need to reflect this in the C++ object hierarchy. If
+ * we don't, SWIG might end up doing 'bad things' when it down casts
+ * ethernet objects to their base class(es).
+ */
+class EtherDevBase : public EtherDevice
+{
+  public:
+    EtherDevBase(const EtherDevBaseParams *params)
+        : EtherDevice(params)
+    {}
+
+    const EtherDevBaseParams *
+    params() const
+    {
+        return dynamic_cast<const EtherDevBaseParams *>(_params);
+    }
+
+};
+
+#endif // __DEV_NET_ETHERDEVICE_HH__
+
diff --git a/src/dev/net/etherdump.cc b/src/dev/net/etherdump.cc
new file mode 100644 (file)
index 0000000..c537fbf
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+#include "dev/net/etherdump.hh"
+
+#include <sys/time.h>
+
+#include <algorithm>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+#include "sim/core.hh"
+
+using std::string;
+
+EtherDump::EtherDump(const Params *p)
+    : SimObject(p), stream(simout.create(p->file, true)),
+      maxlen(p->maxlen)
+{
+}
+
+#define DLT_EN10MB              1               // Ethernet (10Mb)
+#define TCPDUMP_MAGIC           0xa1b2c3d4
+#define PCAP_VERSION_MAJOR      2
+#define PCAP_VERSION_MINOR      4
+
+struct pcap_file_header {
+    uint32_t magic;
+    uint16_t version_major;
+    uint16_t version_minor;
+    int32_t thiszone;           // gmt to local correction
+    uint32_t sigfigs;           // accuracy of timestamps
+    uint32_t snaplen;           // max length saved portion of each pkt
+    uint32_t linktype;          // data link type (DLT_*)
+};
+
+struct pcap_pkthdr {
+    uint32_t seconds;
+    uint32_t microseconds;
+    uint32_t caplen;            // length of portion present
+    uint32_t len;               // length this packet (off wire)
+};
+
+void
+EtherDump::init()
+{
+    struct pcap_file_header hdr;
+    hdr.magic = TCPDUMP_MAGIC;
+    hdr.version_major = PCAP_VERSION_MAJOR;
+    hdr.version_minor = PCAP_VERSION_MINOR;
+
+    hdr.thiszone = 0;
+    hdr.snaplen = 1500;
+    hdr.sigfigs = 0;
+    hdr.linktype = DLT_EN10MB;
+
+    stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
+
+    stream->flush();
+}
+
+void
+EtherDump::dumpPacket(EthPacketPtr &packet)
+{
+    pcap_pkthdr pkthdr;
+    pkthdr.seconds = curTick() / SimClock::Int::s;
+    pkthdr.microseconds = (curTick() / SimClock::Int::us) % ULL(1000000);
+    pkthdr.caplen = std::min(packet->length, maxlen);
+    pkthdr.len = packet->length;
+    stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+    stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
+    stream->flush();
+}
+
+EtherDump *
+EtherDumpParams::create()
+{
+    return new EtherDump(this);
+}
diff --git a/src/dev/net/etherdump.hh b/src/dev/net/etherdump.hh
new file mode 100644 (file)
index 0000000..8e651ba
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Simple object for creating a simple pcap style packet trace
+ */
+
+#ifndef __DEV_NET_ETHERDUMP_HH__
+#define __DEV_NET_ETHERDUMP_HH__
+
+#include <fstream>
+
+#include "dev/net/etherpkt.hh"
+#include "params/EtherDump.hh"
+#include "sim/sim_object.hh"
+
+/*
+ * Simple object for creating a simple pcap style packet trace
+ */
+class EtherDump : public SimObject
+{
+  private:
+    std::ostream *stream;
+    const unsigned maxlen;
+    void dumpPacket(EthPacketPtr &packet);
+    void init();
+
+  public:
+    typedef EtherDumpParams Params;
+    EtherDump(const Params *p);
+
+    inline void dump(EthPacketPtr &pkt) { dumpPacket(pkt); }
+};
+
+#endif // __DEV_NET_ETHERDUMP_HH__
diff --git a/src/dev/net/etherint.cc b/src/dev/net/etherint.cc
new file mode 100644 (file)
index 0000000..b5990c7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include "dev/net/etherint.hh"
+
+#include "base/misc.hh"
+#include "sim/sim_object.hh"
+
+void
+EtherInt::setPeer(EtherInt *p)
+{
+    if (peer && peer != p)
+        panic("You cannot change the peer once it is set.\n"
+              "Current peer=%s Desired peer=%s", peer->name(), p->name());
+
+    peer = p;
+}
diff --git a/src/dev/net/etherint.hh b/src/dev/net/etherint.hh
new file mode 100644 (file)
index 0000000..a11d026
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Class representing the actual interface between two ethernet
+ * components.
+ */
+
+#ifndef __DEV_NET_ETHERINT_HH__
+#define __DEV_NET_ETHERINT_HH__
+
+#include <string>
+
+#include "dev/net/etherpkt.hh"
+
+/*
+ * Class representing the actual interface between two ethernet
+ * components.  These components are intended to attach to another
+ * ethernet interface on one side and whatever device on the other.
+ */
+class EtherInt
+{
+  protected:
+    mutable std::string portName;
+    EtherInt *peer;
+
+  public:
+    EtherInt(const std::string &name)
+        : portName(name), peer(NULL) {}
+    virtual ~EtherInt() {}
+
+    /** Return port name (for DPRINTF). */
+    const std::string &name() const { return portName; }
+
+    void setPeer(EtherInt *p);
+    EtherInt* getPeer() { return peer; }
+
+    void recvDone() { peer->sendDone(); }
+    virtual void sendDone() = 0;
+
+    bool sendPacket(EthPacketPtr packet)
+    { return peer ? peer->recvPacket(packet) : true; }
+    virtual bool recvPacket(EthPacketPtr packet) = 0;
+
+    bool askBusy() {return peer->isBusy(); }
+    virtual bool isBusy() { return false; }
+};
+
+#endif // __DEV_NET_ETHERINT_HH__
diff --git a/src/dev/net/etherlink.cc b/src/dev/net/etherlink.cc
new file mode 100644 (file)
index 0000000..c327a01
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Ron Dreslinski
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#include "dev/net/etherlink.hh"
+
+#include <cmath>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/random.hh"
+#include "base/trace.hh"
+#include "debug/Ethernet.hh"
+#include "debug/EthernetData.hh"
+#include "dev/net/etherdump.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+#include "params/EtherLink.hh"
+#include "sim/core.hh"
+#include "sim/serialize.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+EtherLink::EtherLink(const Params *p)
+    : EtherObject(p)
+{
+    link[0] = new Link(name() + ".link0", this, 0, p->speed,
+                       p->delay, p->delay_var, p->dump);
+    link[1] = new Link(name() + ".link1", this, 1, p->speed,
+                       p->delay, p->delay_var, p->dump);
+
+    interface[0] = new Interface(name() + ".int0", link[0], link[1]);
+    interface[1] = new Interface(name() + ".int1", link[1], link[0]);
+}
+
+
+EtherLink::~EtherLink()
+{
+    delete link[0];
+    delete link[1];
+
+    delete interface[0];
+    delete interface[1];
+}
+
+EtherInt*
+EtherLink::getEthPort(const std::string &if_name, int idx)
+{
+    Interface *i;
+    if (if_name == "int0")
+        i = interface[0];
+    else if (if_name == "int1")
+        i = interface[1];
+    else
+        return NULL;
+    if (i->getPeer())
+        panic("interface already connected to\n");
+
+    return i;
+}
+
+
+EtherLink::Interface::Interface(const string &name, Link *tx, Link *rx)
+    : EtherInt(name), txlink(tx)
+{
+    tx->setTxInt(this);
+    rx->setRxInt(this);
+}
+
+EtherLink::Link::Link(const string &name, EtherLink *p, int num,
+                      double rate, Tick delay, Tick delay_var, EtherDump *d)
+    : objName(name), parent(p), number(num), txint(NULL), rxint(NULL),
+      ticksPerByte(rate), linkDelay(delay), delayVar(delay_var), dump(d),
+      doneEvent(this), txQueueEvent(this)
+{ }
+
+void
+EtherLink::serialize(CheckpointOut &cp) const
+{
+    link[0]->serialize("link0", cp);
+    link[1]->serialize("link1", cp);
+}
+
+void
+EtherLink::unserialize(CheckpointIn &cp)
+{
+    link[0]->unserialize("link0", cp);
+    link[1]->unserialize("link1", cp);
+}
+
+void
+EtherLink::Link::txComplete(EthPacketPtr packet)
+{
+    DPRINTF(Ethernet, "packet received: len=%d\n", packet->length);
+    DDUMP(EthernetData, packet->data, packet->length);
+    rxint->sendPacket(packet);
+}
+
+void
+EtherLink::Link::txDone()
+{
+    if (dump)
+        dump->dump(packet);
+
+    if (linkDelay > 0) {
+        DPRINTF(Ethernet, "packet delayed: delay=%d\n", linkDelay);
+        txQueue.emplace_back(std::make_pair(curTick() + linkDelay, packet));
+        if (!txQueueEvent.scheduled())
+            parent->schedule(txQueueEvent, txQueue.front().first);
+    } else {
+        assert(txQueue.empty());
+        txComplete(packet);
+    }
+
+    packet = 0;
+    assert(!busy());
+
+    txint->sendDone();
+}
+
+void
+EtherLink::Link::processTxQueue()
+{
+    auto cur(txQueue.front());
+    txQueue.pop_front();
+
+    // Schedule a new event to process the next packet in the queue.
+    if (!txQueue.empty()) {
+        auto next(txQueue.front());
+        assert(next.first > curTick());
+        parent->schedule(txQueueEvent, next.first);
+    }
+
+    assert(cur.first == curTick());
+    txComplete(cur.second);
+}
+
+bool
+EtherLink::Link::transmit(EthPacketPtr pkt)
+{
+    if (busy()) {
+        DPRINTF(Ethernet, "packet not sent, link busy\n");
+        return false;
+    }
+
+    DPRINTF(Ethernet, "packet sent: len=%d\n", pkt->length);
+    DDUMP(EthernetData, pkt->data, pkt->length);
+
+    packet = pkt;
+    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
+    if (delayVar != 0)
+        delay += random_mt.random<Tick>(0, delayVar);
+
+    DPRINTF(Ethernet, "scheduling packet: delay=%d, (rate=%f)\n",
+            delay, ticksPerByte);
+    parent->schedule(doneEvent, curTick() + delay);
+
+    return true;
+}
+
+void
+EtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
+{
+    bool packet_exists = packet != nullptr;
+    paramOut(cp, base + ".packet_exists", packet_exists);
+    if (packet_exists)
+        packet->serialize(base + ".packet", cp);
+
+    bool event_scheduled = doneEvent.scheduled();
+    paramOut(cp, base + ".event_scheduled", event_scheduled);
+    if (event_scheduled) {
+        Tick event_time = doneEvent.when();
+        paramOut(cp, base + ".event_time", event_time);
+    }
+
+    const size_t tx_queue_size(txQueue.size());
+    paramOut(cp, base + ".tx_queue_size", tx_queue_size);
+    unsigned idx(0);
+    for (const auto &pe : txQueue) {
+        paramOut(cp, csprintf("%s.txQueue[%i].tick", base, idx), pe.first);
+        pe.second->serialize(csprintf("%s.txQueue[%i].packet", base, idx), cp);
+
+        ++idx;
+    }
+}
+
+void
+EtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
+{
+    bool packet_exists;
+    paramIn(cp, base + ".packet_exists", packet_exists);
+    if (packet_exists) {
+        packet = make_shared<EthPacketData>(16384);
+        packet->unserialize(base + ".packet", cp);
+    }
+
+    bool event_scheduled;
+    paramIn(cp, base + ".event_scheduled", event_scheduled);
+    if (event_scheduled) {
+        Tick event_time;
+        paramIn(cp, base + ".event_time", event_time);
+        parent->schedule(doneEvent, event_time);
+    }
+
+    size_t tx_queue_size;
+    if (optParamIn(cp, base + ".tx_queue_size", tx_queue_size)) {
+        for (size_t idx = 0; idx < tx_queue_size; ++idx) {
+            Tick tick;
+            EthPacketPtr delayed_packet = make_shared<EthPacketData>(16384);
+
+            paramIn(cp, csprintf("%s.txQueue[%i].tick", base, idx), tick);
+            delayed_packet->unserialize(
+                csprintf("%s.txQueue[%i].packet", base, idx), cp);
+
+            fatal_if(!txQueue.empty() && txQueue.back().first > tick,
+                     "Invalid txQueue packet order in EtherLink!\n");
+            txQueue.emplace_back(std::make_pair(tick, delayed_packet));
+        }
+
+        if (!txQueue.empty())
+            parent->schedule(txQueueEvent, txQueue.front().first);
+    } else {
+        // We can't reliably convert in-flight packets from old
+        // checkpoints. In fact, gem5 hasn't been able to load these
+        // packets for at least two years before the format change.
+        warn("Old-style EtherLink serialization format detected, "
+             "in-flight packets may have been dropped.\n");
+    }
+}
+
+EtherLink *
+EtherLinkParams::create()
+{
+    return new EtherLink(this);
+}
diff --git a/src/dev/net/etherlink.hh b/src/dev/net/etherlink.hh
new file mode 100644 (file)
index 0000000..1d02dec
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Device module for modelling a fixed bandwidth full duplex ethernet link
+ */
+
+#ifndef __DEV_NET_ETHERLINK_HH__
+#define __DEV_NET_ETHERLINK_HH__
+
+#include <queue>
+
+#include "base/types.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherobject.hh"
+#include "dev/net/etherpkt.hh"
+#include "params/EtherLink.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class EtherDump;
+class Checkpoint;
+/*
+ * Model for a fixed bandwidth full duplex ethernet link
+ */
+class EtherLink : public EtherObject
+{
+  protected:
+    class Interface;
+
+    /*
+     * Model for a single uni-directional link
+     */
+    class Link
+    {
+      protected:
+        const std::string objName;
+
+        EtherLink *const parent;
+        const int number;
+
+        Interface *txint;
+        Interface *rxint;
+
+        const double ticksPerByte;
+        const Tick linkDelay;
+        const Tick delayVar;
+        EtherDump *const dump;
+
+      protected:
+        /*
+         * Transfer is complete
+         */
+        EthPacketPtr packet;
+        void txDone();
+        typedef EventWrapper<Link, &Link::txDone> DoneEvent;
+        friend void DoneEvent::process();
+        DoneEvent doneEvent;
+
+        /**
+         * Maintain a queue of in-flight packets. Assume that the
+         * delay is non-zero and constant (i.e., at most one packet
+         * per tick).
+         */
+        std::deque<std::pair<Tick, EthPacketPtr>> txQueue;
+
+        void processTxQueue();
+        typedef EventWrapper<Link, &Link::processTxQueue> TxQueueEvent;
+        friend void TxQueueEvent::process();
+        TxQueueEvent txQueueEvent;
+
+        void txComplete(EthPacketPtr packet);
+
+      public:
+        Link(const std::string &name, EtherLink *p, int num,
+             double rate, Tick delay, Tick delay_var, EtherDump *dump);
+        ~Link() {}
+
+        const std::string name() const { return objName; }
+
+        bool busy() const { return (bool)packet; }
+        bool transmit(EthPacketPtr packet);
+
+        void setTxInt(Interface *i) { assert(!txint); txint = i; }
+        void setRxInt(Interface *i) { assert(!rxint); rxint = i; }
+
+        void serialize(const std::string &base, CheckpointOut &cp) const;
+        void unserialize(const std::string &base, CheckpointIn &cp);
+    };
+
+    /*
+     * Interface at each end of the link
+     */
+    class Interface : public EtherInt
+    {
+      private:
+        Link *txlink;
+
+      public:
+        Interface(const std::string &name, Link *txlink, Link *rxlink);
+        bool recvPacket(EthPacketPtr packet) { return txlink->transmit(packet); }
+        void sendDone() { peer->sendDone(); }
+        bool isBusy() { return txlink->busy(); }
+    };
+
+    Link *link[2];
+    Interface *interface[2];
+
+  public:
+    typedef EtherLinkParams Params;
+    EtherLink(const Params *p);
+    virtual ~EtherLink();
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    EtherInt *getEthPort(const std::string &if_name, int idx) override;
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+};
+
+#endif // __DEV_NET_ETHERLINK_HH__
diff --git a/src/dev/net/etherobject.hh b/src/dev/net/etherobject.hh
new file mode 100644 (file)
index 0000000..55cfa97
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2007 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/**
+ * @file
+ * Base Ethernet Object declaration.
+ */
+
+#ifndef __DEV_NET_ETHEROBJECT_HH__
+#define __DEV_NET_ETHEROBJECT_HH__
+
+#include "params/EtherObject.hh"
+#include "sim/sim_object.hh"
+
+class EtherInt;
+
+/**
+ * The base EtherObject class, allows for an accesor function to a
+ * simobj that returns the Port.
+ */
+class EtherObject : public SimObject
+{
+  public:
+    typedef EtherObjectParams Params;
+    EtherObject(const Params *params)
+        : SimObject(params) {}
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+  public:
+    /** Additional function to return the Port of a memory object. */
+    virtual EtherInt *getEthPort(const std::string &if_name, int idx = -1) = 0;
+
+};
+
+#endif // __DEV_NET_ETHEROBJECT_HH__
diff --git a/src/dev/net/etherpkt.cc b/src/dev/net/etherpkt.cc
new file mode 100644 (file)
index 0000000..a16f572
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include "dev/net/etherpkt.hh"
+
+#include <iostream>
+
+#include "base/inet.hh"
+#include "base/misc.hh"
+#include "sim/serialize.hh"
+
+using namespace std;
+
+void
+EthPacketData::serialize(const string &base, CheckpointOut &cp) const
+{
+    paramOut(cp, base + ".length", length);
+    arrayParamOut(cp, base + ".data", data, length);
+}
+
+void
+EthPacketData::unserialize(const string &base, CheckpointIn &cp)
+{
+    paramIn(cp, base + ".length", length);
+    if (length)
+        arrayParamIn(cp, base + ".data", data, length);
+}
+
+void
+EthPacketData::packAddress(uint8_t *src_addr,
+                           uint8_t *dst_addr,
+                           unsigned &nbytes)
+{
+    Net::EthHdr *hdr = (Net::EthHdr *)data;
+    assert(hdr->src().size() == hdr->dst().size());
+    if (nbytes < hdr->src().size())
+        panic("EthPacketData::packAddress() Buffer overflow");
+
+    memcpy(dst_addr, hdr->dst().bytes(), hdr->dst().size());
+    memcpy(src_addr, hdr->src().bytes(), hdr->src().size());
+
+    nbytes = hdr->src().size();
+}
+
diff --git a/src/dev/net/etherpkt.hh b/src/dev/net/etherpkt.hh
new file mode 100644 (file)
index 0000000..4119578
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2002-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Lisa Hsu
+ */
+
+/* @file
+ * Reference counted class containing ethernet packet data
+ */
+
+#ifndef __DEV_NET_ETHERPKT_HH__
+#define __DEV_NET_ETHERPKT_HH__
+
+#include <cassert>
+#include <iosfwd>
+#include <memory>
+
+#include "base/types.hh"
+#include "sim/serialize.hh"
+
+/*
+ * Reference counted class containing ethernet packet data
+ */
+class EthPacketData
+{
+  public:
+    /*
+     * Pointer to packet data will be deleted
+     */
+    uint8_t *data;
+
+    /*
+     * Length of the current packet
+     */
+    unsigned length;
+
+  public:
+    EthPacketData()
+        : data(NULL), length(0)
+    { }
+
+    explicit EthPacketData(unsigned size)
+        : data(new uint8_t[size]), length(0)
+    { }
+
+    ~EthPacketData() { if (data) delete [] data; }
+
+  public:
+    /**
+     * This function pulls out the MAC source and destination addresses from
+     * the packet data and stores them in the caller specified buffers.
+     *
+     * @param src_addr The buffer to store the source MAC address.
+     * @param dst_addr The buffer to store the destination MAC address.
+     * @param length This is an inout parameter. The caller stores in this
+     * the size of the address buffers. On return, this will contain the
+     * actual address size stored in the buffers. (We assume that source
+     * address size is equal to that of the destination address.)
+     */
+    void packAddress(uint8_t *src_addr, uint8_t *dst_addr, unsigned &length);
+
+    void serialize(const std::string &base, CheckpointOut &cp) const;
+    void unserialize(const std::string &base, CheckpointIn &cp);
+
+    unsigned size() const { return length; }
+};
+
+typedef std::shared_ptr<EthPacketData> EthPacketPtr;
+
+#endif // __DEV_NET_ETHERPKT_HH__
diff --git a/src/dev/net/ethertap.cc b/src/dev/net/ethertap.cc
new file mode 100644 (file)
index 0000000..e8d6a36
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#include "dev/net/ethertap.hh"
+
+#if defined(__OpenBSD__) || defined(__APPLE__)
+#include <sys/param.h>
+
+#endif
+#include <netinet/in.h>
+#include <unistd.h>
+
+#include <deque>
+#include <string>
+
+#include "base/misc.hh"
+#include "base/pollevent.hh"
+#include "base/socket.hh"
+#include "base/trace.hh"
+#include "debug/Ethernet.hh"
+#include "debug/EthernetData.hh"
+#include "dev/net/etherdump.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+
+using namespace std;
+
+/**
+ */
+class TapListener
+{
+  protected:
+    /**
+     */
+    class Event : public PollEvent
+    {
+      protected:
+        TapListener *listener;
+
+      public:
+        Event(TapListener *l, int fd, int e)
+            : PollEvent(fd, e), listener(l) {}
+
+        virtual void process(int revent) { listener->accept(); }
+    };
+
+    friend class Event;
+    Event *event;
+
+  protected:
+    ListenSocket listener;
+    EtherTap *tap;
+    int port;
+
+  public:
+    TapListener(EtherTap *t, int p)
+        : event(NULL), tap(t), port(p) {}
+    ~TapListener() { if (event) delete event; }
+
+    void accept();
+    void listen();
+};
+
+void
+TapListener::listen()
+{
+    while (!listener.listen(port, true)) {
+        DPRINTF(Ethernet, "TapListener(listen): Can't bind port %d\n", port);
+        port++;
+    }
+
+    ccprintf(cerr, "Listening for tap connection on port %d\n", port);
+    event = new Event(this, listener.getfd(), POLLIN|POLLERR);
+    pollQueue.schedule(event);
+}
+
+void
+TapListener::accept()
+{
+    // As a consequence of being called from the PollQueue, we might
+    // have been called from a different thread. Migrate to "our"
+    // thread.
+    EventQueue::ScopedMigration migrate(tap->eventQueue());
+
+    if (!listener.islistening())
+        panic("TapListener(accept): cannot accept if we're not listening!");
+
+    int sfd = listener.accept(true);
+    if (sfd != -1)
+        tap->attach(sfd);
+}
+
+/**
+ */
+class TapEvent : public PollEvent
+{
+  protected:
+    EtherTap *tap;
+
+  public:
+    TapEvent(EtherTap *_tap, int fd, int e)
+        : PollEvent(fd, e), tap(_tap) {}
+    virtual void process(int revent) { tap->process(revent); }
+};
+
+EtherTap::EtherTap(const Params *p)
+    : EtherObject(p), event(NULL), socket(-1), buflen(p->bufsz), dump(p->dump),
+      interface(NULL), txEvent(this)
+{
+    if (ListenSocket::allDisabled())
+        fatal("All listeners are disabled! EtherTap can't work!");
+
+    buffer = new char[buflen];
+    listener = new TapListener(this, p->port);
+    listener->listen();
+    interface = new EtherTapInt(name() + ".interface", this);
+}
+
+EtherTap::~EtherTap()
+{
+    if (event)
+        delete event;
+    if (buffer)
+        delete [] buffer;
+
+    delete interface;
+    delete listener;
+}
+
+void
+EtherTap::attach(int fd)
+{
+    if (socket != -1)
+        close(fd);
+
+    buffer_offset = 0;
+    data_len = 0;
+    socket = fd;
+    DPRINTF(Ethernet, "EtherTap attached\n");
+    event = new TapEvent(this, socket, POLLIN|POLLERR);
+    pollQueue.schedule(event);
+}
+
+void
+EtherTap::detach()
+{
+    DPRINTF(Ethernet, "EtherTap detached\n");
+    delete event;
+    event = 0;
+    close(socket);
+    socket = -1;
+}
+
+bool
+EtherTap::recvPacket(EthPacketPtr packet)
+{
+    if (dump)
+        dump->dump(packet);
+
+    DPRINTF(Ethernet, "EtherTap output len=%d\n", packet->length);
+    DDUMP(EthernetData, packet->data, packet->length);
+    uint32_t len = htonl(packet->length);
+    ssize_t ret = write(socket, &len, sizeof(len));
+    if (ret != sizeof(len))
+        return false;
+    ret = write(socket, packet->data, packet->length);
+    if (ret != packet->length)
+        return false;
+
+    interface->recvDone();
+
+    return true;
+}
+
+void
+EtherTap::sendDone()
+{}
+
+void
+EtherTap::process(int revent)
+{
+    if (revent & POLLERR) {
+        detach();
+        return;
+    }
+
+    char *data = buffer + sizeof(uint32_t);
+    if (!(revent & POLLIN))
+        return;
+
+    if (buffer_offset < data_len + sizeof(uint32_t)) {
+        int len = read(socket, buffer + buffer_offset, buflen - buffer_offset);
+        if (len == 0) {
+            detach();
+            return;
+        }
+
+        buffer_offset += len;
+
+        if (data_len == 0)
+            data_len = ntohl(*(uint32_t *)buffer);
+
+        DPRINTF(Ethernet, "Received data from peer: len=%d buffer_offset=%d "
+                "data_len=%d\n", len, buffer_offset, data_len);
+    }
+
+    while (data_len != 0 && buffer_offset >= data_len + sizeof(uint32_t)) {
+        EthPacketPtr packet;
+        packet = make_shared<EthPacketData>(data_len);
+        packet->length = data_len;
+        memcpy(packet->data, data, data_len);
+
+        buffer_offset -= data_len + sizeof(uint32_t);
+        assert(buffer_offset >= 0);
+        if (buffer_offset > 0) {
+            memmove(buffer, data + data_len, buffer_offset);
+            data_len = ntohl(*(uint32_t *)buffer);
+        } else
+            data_len = 0;
+
+        DPRINTF(Ethernet, "EtherTap input len=%d\n", packet->length);
+        DDUMP(EthernetData, packet->data, packet->length);
+        if (!interface->sendPacket(packet)) {
+            DPRINTF(Ethernet, "bus busy...buffer for retransmission\n");
+            packetBuffer.push(packet);
+            if (!txEvent.scheduled())
+                schedule(txEvent, curTick() + retryTime);
+        } else if (dump) {
+            dump->dump(packet);
+        }
+    }
+}
+
+void
+EtherTap::retransmit()
+{
+    if (packetBuffer.empty())
+        return;
+
+    EthPacketPtr packet = packetBuffer.front();
+    if (interface->sendPacket(packet)) {
+        if (dump)
+            dump->dump(packet);
+        DPRINTF(Ethernet, "EtherTap retransmit\n");
+        packetBuffer.front() = NULL;
+        packetBuffer.pop();
+    }
+
+    if (!packetBuffer.empty() && !txEvent.scheduled())
+        schedule(txEvent, curTick() + retryTime);
+}
+
+EtherInt*
+EtherTap::getEthPort(const std::string &if_name, int idx)
+{
+    if (if_name == "tap") {
+        if (interface->getPeer())
+            panic("Interface already connected to\n");
+        return interface;
+    }
+    return NULL;
+}
+
+
+//=====================================================================
+
+void
+EtherTap::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(socket);
+    SERIALIZE_SCALAR(buflen);
+    uint8_t *buffer = (uint8_t *)this->buffer;
+    SERIALIZE_ARRAY(buffer, buflen);
+    SERIALIZE_SCALAR(buffer_offset);
+    SERIALIZE_SCALAR(data_len);
+
+    bool tapevent_present = false;
+    if (event) {
+        tapevent_present = true;
+        SERIALIZE_SCALAR(tapevent_present);
+        event->serialize(cp);
+    }
+    else {
+        SERIALIZE_SCALAR(tapevent_present);
+    }
+}
+
+void
+EtherTap::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(socket);
+    UNSERIALIZE_SCALAR(buflen);
+    uint8_t *buffer = (uint8_t *)this->buffer;
+    UNSERIALIZE_ARRAY(buffer, buflen);
+    UNSERIALIZE_SCALAR(buffer_offset);
+    UNSERIALIZE_SCALAR(data_len);
+
+    bool tapevent_present;
+    UNSERIALIZE_SCALAR(tapevent_present);
+    if (tapevent_present) {
+        event = new TapEvent(this, socket, POLLIN|POLLERR);
+
+        event->unserialize(cp);
+
+        if (event->queued()) {
+            pollQueue.schedule(event);
+        }
+    }
+}
+
+//=====================================================================
+
+EtherTap *
+EtherTapParams::create()
+{
+    return new EtherTap(this);
+}
diff --git a/src/dev/net/ethertap.hh b/src/dev/net/ethertap.hh
new file mode 100644 (file)
index 0000000..b27b80f
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2003-2005 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+/* @file
+ * Interface to connect a simulated ethernet device to the real world
+ */
+
+#ifndef __DEV_NET_ETHERTAP_HH__
+#define __DEV_NET_ETHERTAP_HH__
+
+#include <queue>
+#include <string>
+
+#include "base/pollevent.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherobject.hh"
+#include "dev/net/etherpkt.hh"
+#include "params/EtherTap.hh"
+#include "sim/eventq.hh"
+#include "sim/sim_object.hh"
+
+class TapEvent;
+class TapListener;
+class EtherTapInt;
+
+/*
+ * Interface to connect a simulated ethernet device to the real world
+ */
+class EtherTap : public EtherObject
+{
+  protected:
+    friend class TapEvent;
+    TapEvent *event;
+
+  protected:
+    friend class TapListener;
+    TapListener *listener;
+    int socket;
+    char *buffer;
+    int buflen;
+    uint32_t buffer_offset;
+    uint32_t data_len;
+
+    EtherDump *dump;
+
+    void attach(int fd);
+    void detach();
+
+  protected:
+    std::string device;
+    std::queue<EthPacketPtr> packetBuffer;
+    EtherTapInt *interface;
+
+    void process(int revent);
+    void enqueue(EthPacketData *packet);
+    void retransmit();
+
+    /*
+     */
+    class TxEvent : public Event
+    {
+      protected:
+        EtherTap *tap;
+
+      public:
+        TxEvent(EtherTap *_tap) : tap(_tap) {}
+        void process() { tap->retransmit(); }
+        virtual const char *description() const
+            { return "EtherTap retransmit"; }
+    };
+
+    friend class TxEvent;
+    TxEvent txEvent;
+
+  public:
+    typedef EtherTapParams Params;
+    EtherTap(const Params *p);
+    virtual ~EtherTap();
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    EtherInt *getEthPort(const std::string &if_name, int idx) override;
+
+    virtual bool recvPacket(EthPacketPtr packet);
+    virtual void sendDone();
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+};
+
+class EtherTapInt : public EtherInt
+{
+  private:
+    EtherTap *tap;
+  public:
+    EtherTapInt(const std::string &name, EtherTap *t)
+            : EtherInt(name), tap(t)
+    { }
+
+    virtual bool recvPacket(EthPacketPtr pkt) { return tap->recvPacket(pkt); }
+    virtual void sendDone() { tap->sendDone(); }
+};
+
+
+#endif // __DEV_NET_ETHERTAP_HH__
diff --git a/src/dev/net/i8254xGBe.cc b/src/dev/net/i8254xGBe.cc
new file mode 100644 (file)
index 0000000..cba773f
--- /dev/null
@@ -0,0 +1,2562 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Device model for Intel's 8254x line of gigabit ethernet controllers.
+ * In particular an 82547 revision 2 (82547GI) MAC because it seems to have the
+ * fewest workarounds in the driver. It will probably work with most of the
+ * other MACs with slight modifications.
+ */
+
+#include "dev/net/i8254xGBe.hh"
+
+/*
+ * @todo really there are multiple dma engines.. we should implement them.
+ */
+
+#include <algorithm>
+#include <memory>
+
+#include "base/inet.hh"
+#include "base/trace.hh"
+#include "debug/Drain.hh"
+#include "debug/EthernetAll.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/IGbE.hh"
+#include "sim/stats.hh"
+#include "sim/system.hh"
+
+using namespace iGbReg;
+using namespace Net;
+
+IGbE::IGbE(const Params *p)
+    : EtherDevice(p), etherInt(NULL), cpa(NULL),
+      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), rxTick(false),
+      txTick(false), txFifoTick(false), rxDmaPacket(false), pktOffset(0),
+      fetchDelay(p->fetch_delay), wbDelay(p->wb_delay), 
+      fetchCompDelay(p->fetch_comp_delay), wbCompDelay(p->wb_comp_delay), 
+      rxWriteDelay(p->rx_write_delay), txReadDelay(p->tx_read_delay),  
+      rdtrEvent(this), radvEvent(this),
+      tadvEvent(this), tidvEvent(this), tickEvent(this), interEvent(this),
+      rxDescCache(this, name()+".RxDesc", p->rx_desc_cache_size),
+      txDescCache(this, name()+".TxDesc", p->tx_desc_cache_size),
+      lastInterrupt(0)
+{
+    etherInt = new IGbEInt(name() + ".int", this);
+
+    // Initialized internal registers per Intel documentation
+    // All registers intialized to 0 by per register constructor
+    regs.ctrl.fd(1);
+    regs.ctrl.lrst(1);
+    regs.ctrl.speed(2);
+    regs.ctrl.frcspd(1);
+    regs.sts.speed(3); // Say we're 1000Mbps
+    regs.sts.fd(1); // full duplex
+    regs.sts.lu(1); // link up
+    regs.eecd.fwe(1);
+    regs.eecd.ee_type(1);
+    regs.imr = 0;
+    regs.iam = 0;
+    regs.rxdctl.gran(1);
+    regs.rxdctl.wthresh(1);
+    regs.fcrth(1);
+    regs.tdwba = 0;
+    regs.rlpml = 0;
+    regs.sw_fw_sync = 0;
+
+    regs.pba.rxa(0x30);
+    regs.pba.txa(0x10);
+
+    eeOpBits            = 0;
+    eeAddrBits          = 0;
+    eeDataBits          = 0;
+    eeOpcode            = 0;
+
+    // clear all 64 16 bit words of the eeprom
+    memset(&flash, 0, EEPROM_SIZE*2);
+
+    // Set the MAC address
+    memcpy(flash, p->hardware_address.bytes(), ETH_ADDR_LEN);
+    for (int x = 0; x < ETH_ADDR_LEN/2; x++)
+        flash[x] = htobe(flash[x]);
+
+    uint16_t csum = 0;
+    for (int x = 0; x < EEPROM_SIZE; x++)
+        csum += htobe(flash[x]);
+
+
+    // Magic happy checksum value
+    flash[EEPROM_SIZE-1] = htobe((uint16_t)(EEPROM_CSUM - csum));
+
+    // Store the MAC address as queue ID
+    macAddr = p->hardware_address;
+
+    rxFifo.clear();
+    txFifo.clear();
+}
+
+IGbE::~IGbE()
+{
+    delete etherInt;
+}
+
+void
+IGbE::init()
+{
+    cpa = CPA::cpa();
+    PciDevice::init();
+}
+
+EtherInt*
+IGbE::getEthPort(const std::string &if_name, int idx)
+{
+
+    if (if_name == "interface") {
+        if (etherInt->getPeer())
+            panic("Port already connected to\n");
+        return etherInt;
+    }
+    return NULL;
+}
+
+Tick
+IGbE::writeConfig(PacketPtr pkt)
+{
+    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+    if (offset < PCI_DEVICE_SPECIFIC)
+        PciDevice::writeConfig(pkt);
+    else
+        panic("Device specific PCI config space not implemented.\n");
+
+    //
+    // Some work may need to be done here based for the pci COMMAND bits.
+    //
+
+    return configDelay;
+}
+
+// Handy macro for range-testing register access addresses
+#define IN_RANGE(val, base, len) (val >= base && val < (base + len))
+
+Tick
+IGbE::read(PacketPtr pkt)
+{
+    int bar;
+    Addr daddr;
+
+    if (!getBAR(pkt->getAddr(), bar, daddr))
+        panic("Invalid PCI memory access to unmapped memory.\n");
+
+    // Only Memory register BAR is allowed
+    assert(bar == 0);
+
+    // Only 32bit accesses allowed
+    assert(pkt->getSize() == 4);
+
+    DPRINTF(Ethernet, "Read device register %#X\n", daddr);
+
+    //
+    // Handle read of register here
+    //
+
+
+    switch (daddr) {
+      case REG_CTRL:
+        pkt->set<uint32_t>(regs.ctrl());
+        break;
+      case REG_STATUS:
+        pkt->set<uint32_t>(regs.sts());
+        break;
+      case REG_EECD:
+        pkt->set<uint32_t>(regs.eecd());
+        break;
+      case REG_EERD:
+        pkt->set<uint32_t>(regs.eerd());
+        break;
+      case REG_CTRL_EXT:
+        pkt->set<uint32_t>(regs.ctrl_ext());
+        break;
+      case REG_MDIC:
+        pkt->set<uint32_t>(regs.mdic());
+        break;
+      case REG_ICR:
+        DPRINTF(Ethernet, "Reading ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
+                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
+        pkt->set<uint32_t>(regs.icr());
+        if (regs.icr.int_assert() || regs.imr == 0) {
+            regs.icr = regs.icr() & ~mask(30);
+            DPRINTF(Ethernet, "Cleared ICR. ICR=%#x\n", regs.icr());
+        }
+        if (regs.ctrl_ext.iame() && regs.icr.int_assert())
+            regs.imr &= ~regs.iam;
+        chkInterrupt();
+        break;
+      case REG_EICR:
+        // This is only useful for MSI, but the driver reads it every time
+        // Just don't do anything
+        pkt->set<uint32_t>(0);
+        break;
+      case REG_ITR:
+        pkt->set<uint32_t>(regs.itr());
+        break;
+      case REG_RCTL:
+        pkt->set<uint32_t>(regs.rctl());
+        break;
+      case REG_FCTTV:
+        pkt->set<uint32_t>(regs.fcttv());
+        break;
+      case REG_TCTL:
+        pkt->set<uint32_t>(regs.tctl());
+        break;
+      case REG_PBA:
+        pkt->set<uint32_t>(regs.pba());
+        break;
+      case REG_WUC:
+      case REG_LEDCTL:
+        pkt->set<uint32_t>(0); // We don't care, so just return 0
+        break;
+      case REG_FCRTL:
+        pkt->set<uint32_t>(regs.fcrtl());
+        break;
+      case REG_FCRTH:
+        pkt->set<uint32_t>(regs.fcrth());
+        break;
+      case REG_RDBAL:
+        pkt->set<uint32_t>(regs.rdba.rdbal());
+        break;
+      case REG_RDBAH:
+        pkt->set<uint32_t>(regs.rdba.rdbah());
+        break;
+      case REG_RDLEN:
+        pkt->set<uint32_t>(regs.rdlen());
+        break;
+      case REG_SRRCTL:
+        pkt->set<uint32_t>(regs.srrctl());
+        break;
+      case REG_RDH:
+        pkt->set<uint32_t>(regs.rdh());
+        break;
+      case REG_RDT:
+        pkt->set<uint32_t>(regs.rdt());
+        break;
+      case REG_RDTR:
+        pkt->set<uint32_t>(regs.rdtr());
+        if (regs.rdtr.fpd()) {
+            rxDescCache.writeback(0);
+            DPRINTF(EthernetIntr,
+                    "Posting interrupt because of RDTR.FPD write\n");
+            postInterrupt(IT_RXT);
+            regs.rdtr.fpd(0);
+        }
+        break;
+      case REG_RXDCTL:
+        pkt->set<uint32_t>(regs.rxdctl());
+        break;
+      case REG_RADV:
+        pkt->set<uint32_t>(regs.radv());
+        break;
+      case REG_TDBAL:
+        pkt->set<uint32_t>(regs.tdba.tdbal());
+        break;
+      case REG_TDBAH:
+        pkt->set<uint32_t>(regs.tdba.tdbah());
+        break;
+      case REG_TDLEN:
+        pkt->set<uint32_t>(regs.tdlen());
+        break;
+      case REG_TDH:
+        pkt->set<uint32_t>(regs.tdh());
+        break;
+      case REG_TXDCA_CTL:
+        pkt->set<uint32_t>(regs.txdca_ctl());
+        break;
+      case REG_TDT:
+        pkt->set<uint32_t>(regs.tdt());
+        break;
+      case REG_TIDV:
+        pkt->set<uint32_t>(regs.tidv());
+        break;
+      case REG_TXDCTL:
+        pkt->set<uint32_t>(regs.txdctl());
+        break;
+      case REG_TADV:
+        pkt->set<uint32_t>(regs.tadv());
+        break;
+      case REG_TDWBAL:
+        pkt->set<uint32_t>(regs.tdwba & mask(32));
+        break;
+      case REG_TDWBAH:
+        pkt->set<uint32_t>(regs.tdwba >> 32);
+        break;
+      case REG_RXCSUM:
+        pkt->set<uint32_t>(regs.rxcsum());
+        break;
+      case REG_RLPML:
+        pkt->set<uint32_t>(regs.rlpml);
+        break;
+      case REG_RFCTL:
+        pkt->set<uint32_t>(regs.rfctl());
+        break;
+      case REG_MANC:
+        pkt->set<uint32_t>(regs.manc());
+        break;
+      case REG_SWSM:
+        pkt->set<uint32_t>(regs.swsm());
+        regs.swsm.smbi(1);
+        break;
+      case REG_FWSM:
+        pkt->set<uint32_t>(regs.fwsm());
+        break;
+      case REG_SWFWSYNC:
+        pkt->set<uint32_t>(regs.sw_fw_sync);
+        break;
+      default:
+        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
+            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
+            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4) &&
+            !IN_RANGE(daddr, REG_CRCERRS, STATS_REGS_SIZE))
+            panic("Read request to unknown register number: %#x\n", daddr);
+        else
+            pkt->set<uint32_t>(0);
+    };
+
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+Tick
+IGbE::write(PacketPtr pkt)
+{
+    int bar;
+    Addr daddr;
+
+
+    if (!getBAR(pkt->getAddr(), bar, daddr))
+        panic("Invalid PCI memory access to unmapped memory.\n");
+
+    // Only Memory register BAR is allowed
+    assert(bar == 0);
+
+    // Only 32bit accesses allowed
+    assert(pkt->getSize() == sizeof(uint32_t));
+
+    DPRINTF(Ethernet, "Wrote device register %#X value %#X\n",
+            daddr, pkt->get<uint32_t>());
+
+    //
+    // Handle write of register here
+    //
+    uint32_t val = pkt->get<uint32_t>();
+
+    Regs::RCTL oldrctl;
+    Regs::TCTL oldtctl;
+
+    switch (daddr) {
+      case REG_CTRL:
+        regs.ctrl = val;
+        if (regs.ctrl.tfce())
+            warn("TX Flow control enabled, should implement\n");
+        if (regs.ctrl.rfce())
+            warn("RX Flow control enabled, should implement\n");
+        break;
+      case REG_CTRL_EXT:
+        regs.ctrl_ext = val;
+        break;
+      case REG_STATUS:
+        regs.sts = val;
+        break;
+      case REG_EECD:
+        int oldClk;
+        oldClk = regs.eecd.sk();
+        regs.eecd = val;
+        // See if this is a eeprom access and emulate accordingly
+        if (!oldClk && regs.eecd.sk()) {
+            if (eeOpBits < 8) {
+                eeOpcode = eeOpcode << 1 | regs.eecd.din();
+                eeOpBits++;
+            } else if (eeAddrBits < 8 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
+                eeAddr = eeAddr << 1 | regs.eecd.din();
+                eeAddrBits++;
+            } else if (eeDataBits < 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) {
+                assert(eeAddr>>1 < EEPROM_SIZE);
+                DPRINTF(EthernetEEPROM, "EEPROM bit read: %d word: %#X\n",
+                        flash[eeAddr>>1] >> eeDataBits & 0x1,
+                        flash[eeAddr>>1]);
+                regs.eecd.dout((flash[eeAddr>>1] >> (15-eeDataBits)) & 0x1);
+                eeDataBits++;
+            } else if (eeDataBits < 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI) {
+                regs.eecd.dout(0);
+                eeDataBits++;
+            } else
+                panic("What's going on with eeprom interface? opcode:"
+                      " %#x:%d addr: %#x:%d, data: %d\n", (uint32_t)eeOpcode,
+                      (uint32_t)eeOpBits, (uint32_t)eeAddr,
+                      (uint32_t)eeAddrBits, (uint32_t)eeDataBits);
+
+            // Reset everything for the next command
+            if ((eeDataBits == 16 && eeOpcode == EEPROM_READ_OPCODE_SPI) ||
+                (eeDataBits == 8 && eeOpcode == EEPROM_RDSR_OPCODE_SPI)) {
+                eeOpBits = 0;
+                eeAddrBits = 0;
+                eeDataBits = 0;
+                eeOpcode = 0;
+                eeAddr = 0;
+            }
+
+            DPRINTF(EthernetEEPROM, "EEPROM: opcode: %#X:%d addr: %#X:%d\n",
+                    (uint32_t)eeOpcode, (uint32_t) eeOpBits,
+                    (uint32_t)eeAddr>>1, (uint32_t)eeAddrBits);
+            if (eeOpBits == 8 && !(eeOpcode == EEPROM_READ_OPCODE_SPI ||
+                                   eeOpcode == EEPROM_RDSR_OPCODE_SPI ))
+                panic("Unknown eeprom opcode: %#X:%d\n", (uint32_t)eeOpcode,
+                      (uint32_t)eeOpBits);
+
+
+        }
+        // If driver requests eeprom access, immediately give it to it
+        regs.eecd.ee_gnt(regs.eecd.ee_req());
+        break;
+      case REG_EERD:
+        regs.eerd = val;
+        if (regs.eerd.start()) {
+            regs.eerd.done(1);
+            assert(regs.eerd.addr() < EEPROM_SIZE);
+            regs.eerd.data(flash[regs.eerd.addr()]);
+            regs.eerd.start(0);
+            DPRINTF(EthernetEEPROM, "EEPROM: read addr: %#X data %#x\n",
+                    regs.eerd.addr(), regs.eerd.data());
+        }
+        break;
+      case REG_MDIC:
+        regs.mdic = val;
+        if (regs.mdic.i())
+            panic("No support for interrupt on mdic complete\n");
+        if (regs.mdic.phyadd() != 1)
+            panic("No support for reading anything but phy\n");
+        DPRINTF(Ethernet, "%s phy address %x\n",
+                regs.mdic.op() == 1 ? "Writing" : "Reading",
+                regs.mdic.regadd());
+        switch (regs.mdic.regadd()) {
+          case PHY_PSTATUS:
+            regs.mdic.data(0x796D); // link up
+            break;
+          case PHY_PID:
+            regs.mdic.data(params()->phy_pid);
+            break;
+          case PHY_EPID:
+            regs.mdic.data(params()->phy_epid);
+            break;
+          case PHY_GSTATUS:
+            regs.mdic.data(0x7C00);
+            break;
+          case PHY_EPSTATUS:
+            regs.mdic.data(0x3000);
+            break;
+          case PHY_AGC:
+            regs.mdic.data(0x180); // some random length
+            break;
+          default:
+            regs.mdic.data(0);
+        }
+        regs.mdic.r(1);
+        break;
+      case REG_ICR:
+        DPRINTF(Ethernet, "Writing ICR. ICR=%#x IMR=%#x IAM=%#x IAME=%d\n",
+                regs.icr(), regs.imr, regs.iam, regs.ctrl_ext.iame());
+        if (regs.ctrl_ext.iame())
+            regs.imr &= ~regs.iam;
+        regs.icr = ~bits(val,30,0) & regs.icr();
+        chkInterrupt();
+        break;
+      case REG_ITR:
+        regs.itr = val;
+        break;
+      case REG_ICS:
+        DPRINTF(EthernetIntr, "Posting interrupt because of ICS write\n");
+        postInterrupt((IntTypes)val);
+        break;
+      case REG_IMS:
+        regs.imr |= val;
+        chkInterrupt();
+        break;
+      case REG_IMC:
+        regs.imr &= ~val;
+        chkInterrupt();
+        break;
+      case REG_IAM:
+        regs.iam = val;
+        break;
+      case REG_RCTL:
+        oldrctl = regs.rctl;
+        regs.rctl = val;
+        if (regs.rctl.rst()) {
+            rxDescCache.reset();
+            DPRINTF(EthernetSM, "RXS: Got RESET!\n");
+            rxFifo.clear();
+            regs.rctl.rst(0);
+        }
+        if (regs.rctl.en())
+            rxTick = true;
+        restartClock();
+        break;
+      case REG_FCTTV:
+        regs.fcttv = val;
+        break;
+      case REG_TCTL:
+        regs.tctl = val;
+        oldtctl = regs.tctl;
+        regs.tctl = val;
+        if (regs.tctl.en())
+            txTick = true;
+        restartClock();
+        if (regs.tctl.en() && !oldtctl.en()) {
+            txDescCache.reset();
+        }
+        break;
+      case REG_PBA:
+        regs.pba.rxa(val);
+        regs.pba.txa(64 - regs.pba.rxa());
+        break;
+      case REG_WUC:
+      case REG_LEDCTL:
+      case REG_FCAL:
+      case REG_FCAH:
+      case REG_FCT:
+      case REG_VET:
+      case REG_AIFS:
+      case REG_TIPG:
+        ; // We don't care, so don't store anything
+        break;
+      case REG_IVAR0:
+        warn("Writing to IVAR0, ignoring...\n");
+        break;
+      case REG_FCRTL:
+        regs.fcrtl = val;
+        break;
+      case REG_FCRTH:
+        regs.fcrth = val;
+        break;
+      case REG_RDBAL:
+        regs.rdba.rdbal( val & ~mask(4));
+        rxDescCache.areaChanged();
+        break;
+      case REG_RDBAH:
+        regs.rdba.rdbah(val);
+        rxDescCache.areaChanged();
+        break;
+      case REG_RDLEN:
+        regs.rdlen = val & ~mask(7);
+        rxDescCache.areaChanged();
+        break;
+      case REG_SRRCTL:
+        regs.srrctl = val;
+        break;
+      case REG_RDH:
+        regs.rdh = val;
+        rxDescCache.areaChanged();
+        break;
+      case REG_RDT:
+        regs.rdt = val;
+        DPRINTF(EthernetSM, "RXS: RDT Updated.\n");
+        if (drainState() == DrainState::Running) {
+            DPRINTF(EthernetSM, "RXS: RDT Fetching Descriptors!\n");
+            rxDescCache.fetchDescriptors();
+        } else {
+            DPRINTF(EthernetSM, "RXS: RDT NOT Fetching Desc b/c draining!\n");
+        }
+        break;
+      case REG_RDTR:
+        regs.rdtr = val;
+        break;
+      case REG_RADV:
+        regs.radv = val;
+        break;
+      case REG_RXDCTL:
+        regs.rxdctl = val;
+        break;
+      case REG_TDBAL:
+        regs.tdba.tdbal( val & ~mask(4));
+        txDescCache.areaChanged();
+        break;
+      case REG_TDBAH:
+        regs.tdba.tdbah(val);
+        txDescCache.areaChanged();
+        break;
+      case REG_TDLEN:
+        regs.tdlen = val & ~mask(7);
+        txDescCache.areaChanged();
+        break;
+      case REG_TDH:
+        regs.tdh = val;
+        txDescCache.areaChanged();
+        break;
+      case REG_TXDCA_CTL:
+        regs.txdca_ctl = val;
+        if (regs.txdca_ctl.enabled())
+            panic("No support for DCA\n");
+        break;
+      case REG_TDT:
+        regs.tdt = val;
+        DPRINTF(EthernetSM, "TXS: TX Tail pointer updated\n");
+        if (drainState() == DrainState::Running) {
+            DPRINTF(EthernetSM, "TXS: TDT Fetching Descriptors!\n");
+            txDescCache.fetchDescriptors();
+        } else {
+            DPRINTF(EthernetSM, "TXS: TDT NOT Fetching Desc b/c draining!\n");
+        }
+        break;
+      case REG_TIDV:
+        regs.tidv = val;
+        break;
+      case REG_TXDCTL:
+        regs.txdctl = val;
+        break;
+      case REG_TADV:
+        regs.tadv = val;
+        break;
+      case REG_TDWBAL:
+        regs.tdwba &= ~mask(32);
+        regs.tdwba |= val;
+        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
+                                        regs.tdwba & mask(1));
+        break;
+      case REG_TDWBAH:
+        regs.tdwba &= mask(32);
+        regs.tdwba |= (uint64_t)val << 32;
+        txDescCache.completionWriteback(regs.tdwba & ~mask(1),
+                                        regs.tdwba & mask(1));
+        break;
+      case REG_RXCSUM:
+        regs.rxcsum = val;
+        break;
+      case REG_RLPML:
+        regs.rlpml = val;
+        break;
+      case REG_RFCTL:
+        regs.rfctl = val;
+        if (regs.rfctl.exsten())
+            panic("Extended RX descriptors not implemented\n");
+        break;
+      case REG_MANC:
+        regs.manc = val;
+        break;
+      case REG_SWSM:
+        regs.swsm = val;
+        if (regs.fwsm.eep_fw_semaphore())
+            regs.swsm.swesmbi(0);
+        break;
+      case REG_SWFWSYNC:
+        regs.sw_fw_sync = val;
+        break;
+      default:
+        if (!IN_RANGE(daddr, REG_VFTA, VLAN_FILTER_TABLE_SIZE*4) &&
+            !IN_RANGE(daddr, REG_RAL, RCV_ADDRESS_TABLE_SIZE*8) &&
+            !IN_RANGE(daddr, REG_MTA, MULTICAST_TABLE_SIZE*4))
+            panic("Write request to unknown register number: %#x\n", daddr);
+    };
+
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+void
+IGbE::postInterrupt(IntTypes t, bool now)
+{
+    assert(t);
+
+    // Interrupt is already pending
+    if (t & regs.icr() && !now)
+        return;
+
+    regs.icr = regs.icr() | t;
+
+    Tick itr_interval = SimClock::Int::ns * 256 * regs.itr.interval();
+    DPRINTF(EthernetIntr,
+            "EINT: postInterrupt() curTick(): %d itr: %d interval: %d\n",
+            curTick(), regs.itr.interval(), itr_interval);
+
+    if (regs.itr.interval() == 0 || now ||
+        lastInterrupt + itr_interval <= curTick()) {
+        if (interEvent.scheduled()) {
+            deschedule(interEvent);
+        }
+        cpuPostInt();
+    } else {
+        Tick int_time = lastInterrupt + itr_interval;
+        assert(int_time > 0);
+        DPRINTF(EthernetIntr, "EINT: Scheduling timer interrupt for tick %d\n",
+                int_time);
+        if (!interEvent.scheduled()) {
+            schedule(interEvent, int_time);
+        }
+    }
+}
+
+void
+IGbE::delayIntEvent()
+{
+    cpuPostInt();
+}
+
+
+void
+IGbE::cpuPostInt()
+{
+
+    postedInterrupts++;
+
+    if (!(regs.icr() & regs.imr)) {
+        DPRINTF(Ethernet, "Interrupt Masked. Not Posting\n");
+        return;
+    }
+
+    DPRINTF(Ethernet, "Posting Interrupt\n");
+
+
+    if (interEvent.scheduled()) {
+        deschedule(interEvent);
+    }
+
+    if (rdtrEvent.scheduled()) {
+        regs.icr.rxt0(1);
+        deschedule(rdtrEvent);
+    }
+    if (radvEvent.scheduled()) {
+        regs.icr.rxt0(1);
+        deschedule(radvEvent);
+    }
+    if (tadvEvent.scheduled()) {
+        regs.icr.txdw(1);
+        deschedule(tadvEvent);
+    }
+    if (tidvEvent.scheduled()) {
+        regs.icr.txdw(1);
+        deschedule(tidvEvent);
+    }
+
+    regs.icr.int_assert(1);
+    DPRINTF(EthernetIntr, "EINT: Posting interrupt to CPU now. Vector %#x\n",
+            regs.icr());
+
+    intrPost();
+
+    lastInterrupt = curTick();
+}
+
+void
+IGbE::cpuClearInt()
+{
+    if (regs.icr.int_assert()) {
+        regs.icr.int_assert(0);
+        DPRINTF(EthernetIntr,
+                "EINT: Clearing interrupt to CPU now. Vector %#x\n",
+                regs.icr());
+        intrClear();
+    }
+}
+
+void
+IGbE::chkInterrupt()
+{
+    DPRINTF(Ethernet, "Checking interrupts icr: %#x imr: %#x\n", regs.icr(),
+            regs.imr);
+    // Check if we need to clear the cpu interrupt
+    if (!(regs.icr() & regs.imr)) {
+        DPRINTF(Ethernet, "Mask cleaned all interrupts\n");
+        if (interEvent.scheduled())
+            deschedule(interEvent);
+        if (regs.icr.int_assert())
+            cpuClearInt();
+    }
+    DPRINTF(Ethernet, "ITR = %#X itr.interval = %#X\n",
+            regs.itr(), regs.itr.interval());
+
+    if (regs.icr() & regs.imr) {
+        if (regs.itr.interval() == 0)  {
+            cpuPostInt();
+        } else {
+            DPRINTF(Ethernet,
+                    "Possibly scheduling interrupt because of imr write\n");
+            if (!interEvent.scheduled()) {
+                Tick t = curTick() + SimClock::Int::ns * 256 * regs.itr.interval();
+                DPRINTF(Ethernet, "Scheduling for %d\n", t);
+                schedule(interEvent, t);
+            }
+        }
+    }
+}
+
+
+///////////////////////////// IGbE::DescCache //////////////////////////////
+
+template<class T>
+IGbE::DescCache<T>::DescCache(IGbE *i, const std::string n, int s)
+    : igbe(i), _name(n), cachePnt(0), size(s), curFetching(0),
+      wbOut(0), moreToWb(false), wbAlignment(0), pktPtr(NULL),
+      wbDelayEvent(this), fetchDelayEvent(this), fetchEvent(this),
+      wbEvent(this)
+{
+    fetchBuf = new T[size];
+    wbBuf = new T[size];
+}
+
+template<class T>
+IGbE::DescCache<T>::~DescCache()
+{
+    reset();
+    delete[] fetchBuf;
+    delete[] wbBuf;
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::areaChanged()
+{
+    if (usedCache.size() > 0 || curFetching || wbOut)
+        panic("Descriptor Address, Length or Head changed. Bad\n");
+    reset();
+
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::writeback(Addr aMask)
+{
+    int curHead = descHead();
+    int max_to_wb = usedCache.size();
+
+    // Check if this writeback is less restrictive that the previous
+    // and if so setup another one immediately following it
+    if (wbOut) {
+        if (aMask < wbAlignment) {
+            moreToWb = true;
+            wbAlignment = aMask;
+        }
+        DPRINTF(EthernetDesc,
+                "Writing back already in process, returning\n");
+        return;
+    }
+
+    moreToWb = false;
+    wbAlignment = aMask;
+   
+
+    DPRINTF(EthernetDesc, "Writing back descriptors head: %d tail: "
+            "%d len: %d cachePnt: %d max_to_wb: %d descleft: %d\n",
+            curHead, descTail(), descLen(), cachePnt, max_to_wb,
+            descLeft());
+
+    if (max_to_wb + curHead >= descLen()) {
+        max_to_wb = descLen() - curHead;
+        moreToWb = true;
+        // this is by definition aligned correctly
+    } else if (wbAlignment != 0) {
+        // align the wb point to the mask
+        max_to_wb = max_to_wb & ~wbAlignment;
+    }
+
+    DPRINTF(EthernetDesc, "Writing back %d descriptors\n", max_to_wb);
+
+    if (max_to_wb <= 0) {
+        if (usedCache.size())
+            igbe->anBegin(annSmWb, "Wait Alignment", CPA::FL_WAIT);
+        else
+            igbe->anWe(annSmWb, annUsedCacheQ);
+        return;
+    }
+
+    wbOut = max_to_wb;
+
+    assert(!wbDelayEvent.scheduled()); 
+    igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
+    igbe->anBegin(annSmWb, "Prepare Writeback Desc");
+}
+            
+template<class T>
+void
+IGbE::DescCache<T>::writeback1()
+{
+    // If we're draining delay issuing this DMA
+    if (igbe->drainState() != DrainState::Running) {
+        igbe->schedule(wbDelayEvent, curTick() + igbe->wbDelay);
+        return;
+    }
+
+    DPRINTF(EthernetDesc, "Begining DMA of %d descriptors\n", wbOut);
+            
+    for (int x = 0; x < wbOut; x++) {
+        assert(usedCache.size());
+        memcpy(&wbBuf[x], usedCache[x], sizeof(T));
+        igbe->anPq(annSmWb, annUsedCacheQ);
+        igbe->anPq(annSmWb, annDescQ);
+        igbe->anQ(annSmWb, annUsedDescQ);
+    }
+
+    
+    igbe->anBegin(annSmWb, "Writeback Desc DMA");
+
+    assert(wbOut);
+    igbe->dmaWrite(pciToDma(descBase() + descHead() * sizeof(T)),
+                   wbOut * sizeof(T), &wbEvent, (uint8_t*)wbBuf,
+                   igbe->wbCompDelay);
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::fetchDescriptors()
+{
+    size_t max_to_fetch;
+
+    if (curFetching) {
+        DPRINTF(EthernetDesc,
+                "Currently fetching %d descriptors, returning\n",
+                curFetching);
+        return;
+    }
+
+    if (descTail() >= cachePnt)
+        max_to_fetch = descTail() - cachePnt;
+    else
+        max_to_fetch = descLen() - cachePnt;
+
+    size_t free_cache = size - usedCache.size() - unusedCache.size();
+
+    if (!max_to_fetch)
+        igbe->anWe(annSmFetch, annUnusedDescQ);
+    else
+        igbe->anPq(annSmFetch, annUnusedDescQ, max_to_fetch);
+
+    if (max_to_fetch) {
+        if (!free_cache)
+            igbe->anWf(annSmFetch, annDescQ);
+        else
+            igbe->anRq(annSmFetch, annDescQ, free_cache);
+    }
+
+    max_to_fetch = std::min(max_to_fetch, free_cache);
+            
+
+    DPRINTF(EthernetDesc, "Fetching descriptors head: %d tail: "
+            "%d len: %d cachePnt: %d max_to_fetch: %d descleft: %d\n",
+            descHead(), descTail(), descLen(), cachePnt,
+            max_to_fetch, descLeft());
+
+    // Nothing to do
+    if (max_to_fetch == 0)
+        return;
+            
+    // So we don't have two descriptor fetches going on at once
+    curFetching = max_to_fetch;
+
+    assert(!fetchDelayEvent.scheduled());
+    igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
+    igbe->anBegin(annSmFetch, "Prepare Fetch Desc");
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::fetchDescriptors1()
+{
+    // If we're draining delay issuing this DMA
+    if (igbe->drainState() != DrainState::Running) {
+        igbe->schedule(fetchDelayEvent, curTick() + igbe->fetchDelay);
+        return;
+    }
+
+    igbe->anBegin(annSmFetch, "Fetch Desc");
+
+    DPRINTF(EthernetDesc, "Fetching descriptors at %#x (%#x), size: %#x\n",
+            descBase() + cachePnt * sizeof(T),
+            pciToDma(descBase() + cachePnt * sizeof(T)),
+            curFetching * sizeof(T));
+    assert(curFetching);
+    igbe->dmaRead(pciToDma(descBase() + cachePnt * sizeof(T)),
+                  curFetching * sizeof(T), &fetchEvent, (uint8_t*)fetchBuf,
+                  igbe->fetchCompDelay);
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::fetchComplete()
+{
+    T *newDesc;
+    igbe->anBegin(annSmFetch, "Fetch Complete");
+    for (int x = 0; x < curFetching; x++) {
+        newDesc = new T;
+        memcpy(newDesc, &fetchBuf[x], sizeof(T));
+        unusedCache.push_back(newDesc);
+        igbe->anDq(annSmFetch, annUnusedDescQ);
+        igbe->anQ(annSmFetch, annUnusedCacheQ);
+        igbe->anQ(annSmFetch, annDescQ);
+    }
+
+
+#ifndef NDEBUG
+    int oldCp = cachePnt;
+#endif
+
+    cachePnt += curFetching;
+    assert(cachePnt <= descLen());
+    if (cachePnt == descLen())
+        cachePnt = 0;
+
+    curFetching = 0;
+
+    DPRINTF(EthernetDesc, "Fetching complete cachePnt %d -> %d\n",
+            oldCp, cachePnt);
+
+    if ((descTail() >= cachePnt ? (descTail() - cachePnt) : (descLen() -
+                                                             cachePnt)) == 0)
+    {
+        igbe->anWe(annSmFetch, annUnusedDescQ);
+    } else if (!(size - usedCache.size() - unusedCache.size())) {
+        igbe->anWf(annSmFetch, annDescQ);
+    } else {
+        igbe->anBegin(annSmFetch, "Wait", CPA::FL_WAIT);
+    }
+
+    enableSm();
+    igbe->checkDrain();
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::wbComplete()
+{
+
+    igbe->anBegin(annSmWb, "Finish Writeback");
+
+    long  curHead = descHead();
+#ifndef NDEBUG
+    long oldHead = curHead;
+#endif
+            
+    for (int x = 0; x < wbOut; x++) {
+        assert(usedCache.size());
+        delete usedCache[0];
+        usedCache.pop_front();
+
+        igbe->anDq(annSmWb, annUsedCacheQ);
+        igbe->anDq(annSmWb, annDescQ);
+    }
+
+    curHead += wbOut;
+    wbOut = 0;
+
+    if (curHead >= descLen())
+        curHead -= descLen();
+
+    // Update the head
+    updateHead(curHead);
+
+    DPRINTF(EthernetDesc, "Writeback complete curHead %d -> %d\n",
+            oldHead, curHead);
+
+    // If we still have more to wb, call wb now
+    actionAfterWb();
+    if (moreToWb) {
+        moreToWb = false;
+        DPRINTF(EthernetDesc, "Writeback has more todo\n");
+        writeback(wbAlignment);
+    }
+
+    if (!wbOut) {
+        igbe->checkDrain();
+        if (usedCache.size())
+            igbe->anBegin(annSmWb, "Wait", CPA::FL_WAIT);
+        else
+            igbe->anWe(annSmWb, annUsedCacheQ);
+    }
+    fetchAfterWb();
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::reset()
+{
+    DPRINTF(EthernetDesc, "Reseting descriptor cache\n");
+    for (typename CacheType::size_type x = 0; x < usedCache.size(); x++)
+        delete usedCache[x];
+    for (typename CacheType::size_type x = 0; x < unusedCache.size(); x++)
+        delete unusedCache[x];
+
+    usedCache.clear();
+    unusedCache.clear();
+
+    cachePnt = 0;
+
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::serialize(CheckpointOut &cp) const
+{
+    SERIALIZE_SCALAR(cachePnt);
+    SERIALIZE_SCALAR(curFetching);
+    SERIALIZE_SCALAR(wbOut);
+    SERIALIZE_SCALAR(moreToWb);
+    SERIALIZE_SCALAR(wbAlignment);
+
+    typename CacheType::size_type usedCacheSize = usedCache.size();
+    SERIALIZE_SCALAR(usedCacheSize);
+    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
+        arrayParamOut(cp, csprintf("usedCache_%d", x),
+                      (uint8_t*)usedCache[x],sizeof(T));
+    }
+
+    typename CacheType::size_type unusedCacheSize = unusedCache.size();
+    SERIALIZE_SCALAR(unusedCacheSize);
+    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
+        arrayParamOut(cp, csprintf("unusedCache_%d", x),
+                      (uint8_t*)unusedCache[x],sizeof(T));
+    }
+
+    Tick fetch_delay = 0, wb_delay = 0;
+    if (fetchDelayEvent.scheduled())
+        fetch_delay = fetchDelayEvent.when();
+    SERIALIZE_SCALAR(fetch_delay);
+    if (wbDelayEvent.scheduled())
+        wb_delay = wbDelayEvent.when();
+    SERIALIZE_SCALAR(wb_delay);
+
+
+}
+
+template<class T>
+void
+IGbE::DescCache<T>::unserialize(CheckpointIn &cp)
+{
+    UNSERIALIZE_SCALAR(cachePnt);
+    UNSERIALIZE_SCALAR(curFetching);
+    UNSERIALIZE_SCALAR(wbOut);
+    UNSERIALIZE_SCALAR(moreToWb);
+    UNSERIALIZE_SCALAR(wbAlignment);
+
+    typename CacheType::size_type usedCacheSize;
+    UNSERIALIZE_SCALAR(usedCacheSize);
+    T *temp;
+    for (typename CacheType::size_type x = 0; x < usedCacheSize; x++) {
+        temp = new T;
+        arrayParamIn(cp, csprintf("usedCache_%d", x),
+                     (uint8_t*)temp,sizeof(T));
+        usedCache.push_back(temp);
+    }
+
+    typename CacheType::size_type unusedCacheSize;
+    UNSERIALIZE_SCALAR(unusedCacheSize);
+    for (typename CacheType::size_type x = 0; x < unusedCacheSize; x++) {
+        temp = new T;
+        arrayParamIn(cp, csprintf("unusedCache_%d", x),
+                     (uint8_t*)temp,sizeof(T));
+        unusedCache.push_back(temp);
+    }
+    Tick fetch_delay = 0, wb_delay = 0;
+    UNSERIALIZE_SCALAR(fetch_delay);
+    UNSERIALIZE_SCALAR(wb_delay);
+    if (fetch_delay)
+        igbe->schedule(fetchDelayEvent, fetch_delay);
+    if (wb_delay)
+        igbe->schedule(wbDelayEvent, wb_delay);
+
+
+}
+
+///////////////////////////// IGbE::RxDescCache //////////////////////////////
+
+IGbE::RxDescCache::RxDescCache(IGbE *i, const std::string n, int s)
+    : DescCache<RxDesc>(i, n, s), pktDone(false), splitCount(0), 
+      pktEvent(this), pktHdrEvent(this), pktDataEvent(this)
+
+{
+    annSmFetch = "RX Desc Fetch";
+    annSmWb = "RX Desc Writeback";
+    annUnusedDescQ = "RX Unused Descriptors";
+    annUnusedCacheQ = "RX Unused Descriptor Cache";
+    annUsedCacheQ = "RX Used Descriptor Cache";
+    annUsedDescQ = "RX Used Descriptors";
+    annDescQ = "RX Descriptors";
+}
+
+void
+IGbE::RxDescCache::pktSplitDone()
+{
+    splitCount++;
+    DPRINTF(EthernetDesc,
+            "Part of split packet done: splitcount now %d\n", splitCount);
+    assert(splitCount <= 2);
+    if (splitCount != 2)
+        return;
+    splitCount = 0;
+    DPRINTF(EthernetDesc,
+            "Part of split packet done: calling pktComplete()\n");
+    pktComplete();
+}
+
+int
+IGbE::RxDescCache::writePacket(EthPacketPtr packet, int pkt_offset)
+{
+    assert(unusedCache.size());
+    //if (!unusedCache.size())
+    //    return false;
+
+    pktPtr = packet;
+    pktDone = false;
+    unsigned buf_len, hdr_len;
+
+    RxDesc *desc = unusedCache.front();
+    switch (igbe->regs.srrctl.desctype()) {
+      case RXDT_LEGACY:
+        assert(pkt_offset == 0);
+        bytesCopied = packet->length;
+        DPRINTF(EthernetDesc, "Packet Length: %d Desc Size: %d\n",
+                packet->length, igbe->regs.rctl.descSize());
+        assert(packet->length < igbe->regs.rctl.descSize());
+        igbe->dmaWrite(pciToDma(desc->legacy.buf),
+                       packet->length, &pktEvent, packet->data,
+                       igbe->rxWriteDelay);
+        break;
+      case RXDT_ADV_ONEBUF:
+        assert(pkt_offset == 0);
+        bytesCopied = packet->length;
+        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+            igbe->regs.rctl.descSize();
+        DPRINTF(EthernetDesc, "Packet Length: %d srrctl: %#x Desc Size: %d\n",
+                packet->length, igbe->regs.srrctl(), buf_len);
+        assert(packet->length < buf_len);
+        igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
+                       packet->length, &pktEvent, packet->data,
+                       igbe->rxWriteDelay);
+        desc->adv_wb.header_len = htole(0);
+        desc->adv_wb.sph = htole(0);
+        desc->adv_wb.pkt_len = htole((uint16_t)(pktPtr->length));
+        break;
+      case RXDT_ADV_SPLIT_A:
+        int split_point;
+        
+        buf_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.bufLen() :
+            igbe->regs.rctl.descSize();
+        hdr_len = igbe->regs.rctl.lpe() ? igbe->regs.srrctl.hdrLen() : 0; 
+        DPRINTF(EthernetDesc,
+                "lpe: %d Packet Length: %d offset: %d srrctl: %#x "
+                "hdr addr: %#x Hdr Size: %d desc addr: %#x Desc Size: %d\n",
+                igbe->regs.rctl.lpe(), packet->length, pkt_offset,
+                igbe->regs.srrctl(), desc->adv_read.hdr, hdr_len,
+                desc->adv_read.pkt, buf_len);
+
+        split_point = hsplit(pktPtr);
+
+        if (packet->length <= hdr_len) {
+            bytesCopied = packet->length;
+            assert(pkt_offset == 0);
+            DPRINTF(EthernetDesc, "Hdr split: Entire packet in header\n");
+            igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
+                           packet->length, &pktEvent, packet->data,
+                           igbe->rxWriteDelay);
+            desc->adv_wb.header_len = htole((uint16_t)packet->length);
+            desc->adv_wb.sph = htole(0);
+            desc->adv_wb.pkt_len = htole(0);
+        } else if (split_point) {
+            if (pkt_offset) {
+                // we are only copying some data, header/data has already been
+                // copied
+                int max_to_copy =
+                    std::min(packet->length - pkt_offset, buf_len);
+                bytesCopied += max_to_copy;
+                DPRINTF(EthernetDesc,
+                        "Hdr split: Continuing data buffer copy\n");
+                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
+                               max_to_copy, &pktEvent,
+                               packet->data + pkt_offset, igbe->rxWriteDelay);
+                desc->adv_wb.header_len = htole(0);
+                desc->adv_wb.pkt_len = htole((uint16_t)max_to_copy);
+                desc->adv_wb.sph = htole(0);
+            } else {
+                int max_to_copy =
+                    std::min(packet->length - split_point, buf_len);
+                bytesCopied += max_to_copy + split_point;
+                
+                DPRINTF(EthernetDesc, "Hdr split: splitting at %d\n",
+                        split_point);
+                igbe->dmaWrite(pciToDma(desc->adv_read.hdr),
+                               split_point, &pktHdrEvent,
+                               packet->data, igbe->rxWriteDelay);
+                igbe->dmaWrite(pciToDma(desc->adv_read.pkt),
+                               max_to_copy, &pktDataEvent,
+                               packet->data + split_point, igbe->rxWriteDelay);
+                desc->adv_wb.header_len = htole(split_point);
+                desc->adv_wb.sph = 1;
+                desc->adv_wb.pkt_len = htole((uint16_t)(max_to_copy));
+            }
+        } else {
+            panic("Header split not fitting within header buffer or "
+                  "undecodable packet not fitting in header unsupported\n");
+        }
+        break;
+      default:
+        panic("Unimplemnted RX receive buffer type: %d\n",
+              igbe->regs.srrctl.desctype());
+    }
+    return bytesCopied;
+
+}
+
+void
+IGbE::RxDescCache::pktComplete()
+{
+    assert(unusedCache.size());
+    RxDesc *desc;
+    desc = unusedCache.front();
+
+    igbe->anBegin("RXS", "Update Desc");
+
+    uint16_t crcfixup = igbe->regs.rctl.secrc() ? 0 : 4 ;
+    DPRINTF(EthernetDesc, "pktPtr->length: %d bytesCopied: %d "
+            "stripcrc offset: %d value written: %d %d\n",
+            pktPtr->length, bytesCopied, crcfixup,
+            htole((uint16_t)(pktPtr->length + crcfixup)),
+            (uint16_t)(pktPtr->length + crcfixup));
+
+    // no support for anything but starting at 0
+    assert(igbe->regs.rxcsum.pcss() == 0);
+
+    DPRINTF(EthernetDesc, "Packet written to memory updating Descriptor\n");
+
+    uint16_t status = RXDS_DD;
+    uint8_t err = 0;
+    uint16_t ext_err = 0;
+    uint16_t csum = 0;
+    uint16_t ptype = 0;
+    uint16_t ip_id = 0;
+
+    assert(bytesCopied <= pktPtr->length);
+    if (bytesCopied == pktPtr->length)
+        status |= RXDS_EOP;
+
+    IpPtr ip(pktPtr);
+
+    if (ip) {
+        DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n", ip->id());
+        ptype |= RXDP_IPV4;
+        ip_id = ip->id();
+
+        if (igbe->regs.rxcsum.ipofld()) {
+            DPRINTF(EthernetDesc, "Checking IP checksum\n");
+            status |= RXDS_IPCS;
+            csum = htole(cksum(ip));
+            igbe->rxIpChecksums++;
+            if (cksum(ip) != 0) {
+                err |= RXDE_IPE;
+                ext_err |= RXDEE_IPE;
+                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+            }
+        }
+        TcpPtr tcp(ip);
+        if (tcp && igbe->regs.rxcsum.tuofld()) {
+            DPRINTF(EthernetDesc, "Checking TCP checksum\n");
+            status |= RXDS_TCPCS;
+            ptype |= RXDP_TCP;
+            csum = htole(cksum(tcp));
+            igbe->rxTcpChecksums++;
+            if (cksum(tcp) != 0) {
+                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+                err |= RXDE_TCPE;
+                ext_err |= RXDEE_TCPE;
+            }
+        }
+
+        UdpPtr udp(ip);
+        if (udp && igbe->regs.rxcsum.tuofld()) {
+            DPRINTF(EthernetDesc, "Checking UDP checksum\n");
+            status |= RXDS_UDPCS;
+            ptype |= RXDP_UDP;
+            csum = htole(cksum(udp));
+            igbe->rxUdpChecksums++;
+            if (cksum(udp) != 0) {
+                DPRINTF(EthernetDesc, "Checksum is bad!!\n");
+                ext_err |= RXDEE_TCPE;
+                err |= RXDE_TCPE;
+            }
+        }
+    } else { // if ip
+        DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
+    }
+
+    switch (igbe->regs.srrctl.desctype()) {
+      case RXDT_LEGACY:
+        desc->legacy.len = htole((uint16_t)(pktPtr->length + crcfixup));
+        desc->legacy.status = htole(status);
+        desc->legacy.errors = htole(err);
+        // No vlan support at this point... just set it to 0
+        desc->legacy.vlan = 0;
+        break;
+      case RXDT_ADV_SPLIT_A:
+      case RXDT_ADV_ONEBUF:
+        desc->adv_wb.rss_type = htole(0);
+        desc->adv_wb.pkt_type = htole(ptype);
+        if (igbe->regs.rxcsum.pcsd()) {
+            // no rss support right now
+            desc->adv_wb.rss_hash = htole(0);
+        } else {
+            desc->adv_wb.id = htole(ip_id);
+            desc->adv_wb.csum = htole(csum);
+        }
+        desc->adv_wb.status = htole(status);
+        desc->adv_wb.errors = htole(ext_err);
+        // no vlan support
+        desc->adv_wb.vlan_tag = htole(0); 
+        break;
+      default:
+        panic("Unimplemnted RX receive buffer type %d\n",
+              igbe->regs.srrctl.desctype());
+    }
+
+    DPRINTF(EthernetDesc, "Descriptor complete w0: %#x w1: %#x\n",
+            desc->adv_read.pkt, desc->adv_read.hdr);
+
+    if (bytesCopied == pktPtr->length) {
+        DPRINTF(EthernetDesc,
+                "Packet completely written to descriptor buffers\n");
+        // Deal with the rx timer interrupts
+        if (igbe->regs.rdtr.delay()) {
+            Tick delay = igbe->regs.rdtr.delay() * igbe->intClock();
+            DPRINTF(EthernetSM, "RXS: Scheduling DTR for %d\n", delay);
+            igbe->reschedule(igbe->rdtrEvent, curTick() + delay);
+        }
+
+        if (igbe->regs.radv.idv()) {
+            Tick delay = igbe->regs.radv.idv() * igbe->intClock();
+            DPRINTF(EthernetSM, "RXS: Scheduling ADV for %d\n", delay);
+            if (!igbe->radvEvent.scheduled()) {
+                igbe->schedule(igbe->radvEvent, curTick() + delay);
+            }
+        }
+
+        // if neither radv or rdtr, maybe itr is set...
+        if (!igbe->regs.rdtr.delay() && !igbe->regs.radv.idv()) {
+            DPRINTF(EthernetSM,
+                    "RXS: Receive interrupt delay disabled, posting IT_RXT\n");
+            igbe->postInterrupt(IT_RXT);
+        }
+
+        // If the packet is small enough, interrupt appropriately
+        // I wonder if this is delayed or not?!
+        if (pktPtr->length <= igbe->regs.rsrpd.idv()) {
+            DPRINTF(EthernetSM,
+                    "RXS: Posting IT_SRPD beacuse small packet received\n");
+            igbe->postInterrupt(IT_SRPD);
+        }
+        bytesCopied = 0;
+    }
+
+    pktPtr = NULL;
+    igbe->checkDrain();
+    enableSm();
+    pktDone = true;
+
+    igbe->anBegin("RXS", "Done Updating Desc");
+    DPRINTF(EthernetDesc, "Processing of this descriptor complete\n");
+    igbe->anDq("RXS", annUnusedCacheQ);
+    unusedCache.pop_front();
+    igbe->anQ("RXS", annUsedCacheQ);
+    usedCache.push_back(desc);
+}
+
+void
+IGbE::RxDescCache::enableSm()
+{
+    if (igbe->drainState() != DrainState::Draining) {
+        igbe->rxTick = true;
+        igbe->restartClock();
+    }
+}
+
+bool
+IGbE::RxDescCache::packetDone()
+{
+    if (pktDone) {
+        pktDone = false;
+        return true;
+    }
+    return false;
+}
+
+bool
+IGbE::RxDescCache::hasOutstandingEvents()
+{
+    return pktEvent.scheduled() || wbEvent.scheduled() ||
+        fetchEvent.scheduled() || pktHdrEvent.scheduled() ||
+        pktDataEvent.scheduled();
+         
+}
+
+void
+IGbE::RxDescCache::serialize(CheckpointOut &cp) const
+{
+    DescCache<RxDesc>::serialize(cp);
+    SERIALIZE_SCALAR(pktDone);
+    SERIALIZE_SCALAR(splitCount);
+    SERIALIZE_SCALAR(bytesCopied);
+}
+
+void
+IGbE::RxDescCache::unserialize(CheckpointIn &cp)
+{
+    DescCache<RxDesc>::unserialize(cp);
+    UNSERIALIZE_SCALAR(pktDone);
+    UNSERIALIZE_SCALAR(splitCount);
+    UNSERIALIZE_SCALAR(bytesCopied);
+}
+
+
+///////////////////////////// IGbE::TxDescCache //////////////////////////////
+
+IGbE::TxDescCache::TxDescCache(IGbE *i, const std::string n, int s)
+    : DescCache<TxDesc>(i,n, s), pktDone(false), isTcp(false),
+      pktWaiting(false), pktMultiDesc(false),
+      completionAddress(0), completionEnabled(false),
+      useTso(false), tsoHeaderLen(0), tsoMss(0), tsoTotalLen(0), tsoUsedLen(0),
+      tsoPrevSeq(0), tsoPktPayloadBytes(0), tsoLoadedHeader(false),
+      tsoPktHasHeader(false), tsoDescBytesUsed(0), tsoCopyBytes(0), tsoPkts(0),
+      pktEvent(this), headerEvent(this), nullEvent(this)
+{
+    annSmFetch = "TX Desc Fetch";
+    annSmWb = "TX Desc Writeback";
+    annUnusedDescQ = "TX Unused Descriptors";
+    annUnusedCacheQ = "TX Unused Descriptor Cache";
+    annUsedCacheQ = "TX Used Descriptor Cache";
+    annUsedDescQ = "TX Used Descriptors";
+    annDescQ = "TX Descriptors";
+}
+
+void
+IGbE::TxDescCache::processContextDesc()
+{
+    assert(unusedCache.size());
+    TxDesc *desc;
+    
+    DPRINTF(EthernetDesc, "Checking and  processing context descriptors\n");
+
+    while (!useTso && unusedCache.size() &&
+           TxdOp::isContext(unusedCache.front())) {
+        DPRINTF(EthernetDesc, "Got context descriptor type...\n");
+
+        desc = unusedCache.front();
+        DPRINTF(EthernetDesc, "Descriptor upper: %#x lower: %#X\n", 
+                desc->d1, desc->d2);
+
+        
+        // is this going to be a tcp or udp packet?
+        isTcp = TxdOp::tcp(desc) ? true : false;
+
+        // setup all the TSO variables, they'll be ignored if we don't use 
+        // tso for this connection
+        tsoHeaderLen = TxdOp::hdrlen(desc);
+        tsoMss  = TxdOp::mss(desc);
+
+        if (TxdOp::isType(desc, TxdOp::TXD_CNXT) && TxdOp::tse(desc)) {
+            DPRINTF(EthernetDesc, "TCP offload enabled for packet hdrlen: "
+                    "%d mss: %d paylen %d\n", TxdOp::hdrlen(desc),
+                    TxdOp::mss(desc), TxdOp::getLen(desc));
+            useTso = true;
+            tsoTotalLen = TxdOp::getLen(desc);
+            tsoLoadedHeader = false;
+            tsoDescBytesUsed = 0;
+            tsoUsedLen = 0;
+            tsoPrevSeq = 0;
+            tsoPktHasHeader = false;
+            tsoPkts = 0;
+            tsoCopyBytes = 0;
+        }
+
+        TxdOp::setDd(desc);
+        unusedCache.pop_front();
+        igbe->anDq("TXS", annUnusedCacheQ);
+        usedCache.push_back(desc);
+        igbe->anQ("TXS", annUsedCacheQ);
+    }
+
+    if (!unusedCache.size())
+        return;
+
+    desc = unusedCache.front();
+    if (!useTso && TxdOp::isType(desc, TxdOp::TXD_ADVDATA) && 
+        TxdOp::tse(desc)) {
+        DPRINTF(EthernetDesc, "TCP offload(adv) enabled for packet "
+                "hdrlen: %d mss: %d paylen %d\n", 
+                tsoHeaderLen, tsoMss, TxdOp::getTsoLen(desc));
+        useTso = true;
+        tsoTotalLen = TxdOp::getTsoLen(desc);
+        tsoLoadedHeader = false;
+        tsoDescBytesUsed = 0;
+        tsoUsedLen = 0;
+        tsoPrevSeq = 0;
+        tsoPktHasHeader = false;
+        tsoPkts = 0;
+    }
+
+    if (useTso && !tsoLoadedHeader) {
+        // we need to fetch a header
+        DPRINTF(EthernetDesc, "Starting DMA of TSO header\n");
+        assert(TxdOp::isData(desc) && TxdOp::getLen(desc) >= tsoHeaderLen);
+        pktWaiting = true;
+        assert(tsoHeaderLen <= 256);
+        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
+                      tsoHeaderLen, &headerEvent, tsoHeader, 0);
+    }
+}
+
+void
+IGbE::TxDescCache::headerComplete()
+{
+    DPRINTF(EthernetDesc, "TSO: Fetching TSO header complete\n");
+    pktWaiting = false;
+
+    assert(unusedCache.size());
+    TxDesc *desc = unusedCache.front();
+    DPRINTF(EthernetDesc, "TSO: len: %d tsoHeaderLen: %d\n",
+            TxdOp::getLen(desc), tsoHeaderLen);
+
+    if (TxdOp::getLen(desc) == tsoHeaderLen) {
+        tsoDescBytesUsed = 0;
+        tsoLoadedHeader = true;
+        unusedCache.pop_front();
+        usedCache.push_back(desc);
+    } else {
+        DPRINTF(EthernetDesc, "TSO: header part of larger payload\n");
+        tsoDescBytesUsed = tsoHeaderLen;
+        tsoLoadedHeader = true;
+    }
+    enableSm();
+    igbe->checkDrain();
+}
+
+unsigned
+IGbE::TxDescCache::getPacketSize(EthPacketPtr p)
+{
+    if (!unusedCache.size())
+        return 0;
+    DPRINTF(EthernetDesc, "Starting processing of descriptor\n");
+
+    assert(!useTso || tsoLoadedHeader);
+    TxDesc *desc = unusedCache.front();
+
+    if (useTso) {
+        DPRINTF(EthernetDesc, "getPacket(): TxDescriptor data "
+                "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
+                "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
+                tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
+
+        if (tsoPktHasHeader) 
+            tsoCopyBytes =  std::min((tsoMss + tsoHeaderLen) - p->length,
+                                     TxdOp::getLen(desc) - tsoDescBytesUsed);
+        else
+            tsoCopyBytes =  std::min(tsoMss,
+                                     TxdOp::getLen(desc) - tsoDescBytesUsed); 
+        unsigned pkt_size =
+            tsoCopyBytes + (tsoPktHasHeader ? 0 : tsoHeaderLen); 
+
+        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d "
+                "this descLen: %d\n",
+                tsoDescBytesUsed, tsoCopyBytes, TxdOp::getLen(desc));
+        DPRINTF(EthernetDesc, "TSO: pktHasHeader: %d\n", tsoPktHasHeader);
+        DPRINTF(EthernetDesc, "TSO: Next packet is %d bytes\n", pkt_size);
+        return pkt_size;
+    }
+
+    DPRINTF(EthernetDesc, "Next TX packet is %d bytes\n",
+            TxdOp::getLen(unusedCache.front()));
+    return TxdOp::getLen(desc);
+}
+
+void
+IGbE::TxDescCache::getPacketData(EthPacketPtr p)
+{
+    assert(unusedCache.size());
+
+    TxDesc *desc;
+    desc = unusedCache.front();
+
+    DPRINTF(EthernetDesc, "getPacketData(): TxDescriptor data "
+            "d1: %#llx d2: %#llx\n", desc->d1, desc->d2);
+    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
+           TxdOp::getLen(desc));
+
+    pktPtr = p;
+
+    pktWaiting = true;
+
+    DPRINTF(EthernetDesc, "Starting DMA of packet at offset %d\n", p->length);
+    
+    if (useTso) {
+        assert(tsoLoadedHeader);
+        if (!tsoPktHasHeader) {
+            DPRINTF(EthernetDesc,
+                    "Loading TSO header (%d bytes) into start of packet\n",
+                    tsoHeaderLen);
+            memcpy(p->data, &tsoHeader,tsoHeaderLen);
+            p->length +=tsoHeaderLen;
+            tsoPktHasHeader = true;
+        }
+    }
+  
+    if (useTso) {
+        DPRINTF(EthernetDesc,
+                "Starting DMA of packet at offset %d length: %d\n",
+                p->length, tsoCopyBytes);
+        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc))
+                      + tsoDescBytesUsed,
+                      tsoCopyBytes, &pktEvent, p->data + p->length,
+                      igbe->txReadDelay);
+        tsoDescBytesUsed += tsoCopyBytes;
+        assert(tsoDescBytesUsed <= TxdOp::getLen(desc));
+    } else {
+        igbe->dmaRead(pciToDma(TxdOp::getBuf(desc)),
+                      TxdOp::getLen(desc), &pktEvent, p->data + p->length,
+                      igbe->txReadDelay);
+    }
+}
+
+void
+IGbE::TxDescCache::pktComplete()
+{
+
+    TxDesc *desc;
+    assert(unusedCache.size());
+    assert(pktPtr);
+
+    igbe->anBegin("TXS", "Update Desc");
+
+    DPRINTF(EthernetDesc, "DMA of packet complete\n");
+
+
+    desc = unusedCache.front();
+    assert((TxdOp::isLegacy(desc) || TxdOp::isData(desc)) &&
+           TxdOp::getLen(desc));
+
+    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
+            desc->d1, desc->d2);
+
+    // Set the length of the data in the EtherPacket
+    if (useTso) {
+        DPRINTF(EthernetDesc, "TSO: use: %d hdrlen: %d mss: %d total: %d "
+            "used: %d loaded hdr: %d\n", useTso, tsoHeaderLen, tsoMss,
+            tsoTotalLen, tsoUsedLen, tsoLoadedHeader);
+        pktPtr->length += tsoCopyBytes;
+        tsoUsedLen += tsoCopyBytes;
+        DPRINTF(EthernetDesc, "TSO: descBytesUsed: %d copyBytes: %d\n",
+            tsoDescBytesUsed, tsoCopyBytes);
+    } else
+        pktPtr->length += TxdOp::getLen(desc);
+    
+
+
+    if ((!TxdOp::eop(desc) && !useTso) || 
+        (pktPtr->length < ( tsoMss + tsoHeaderLen) &&
+         tsoTotalLen != tsoUsedLen && useTso)) {
+        assert(!useTso || (tsoDescBytesUsed == TxdOp::getLen(desc)));
+        igbe->anDq("TXS", annUnusedCacheQ);
+        unusedCache.pop_front();
+        igbe->anQ("TXS", annUsedCacheQ);
+        usedCache.push_back(desc);
+
+        tsoDescBytesUsed = 0;
+        pktDone = true;
+        pktWaiting = false;
+        pktMultiDesc = true;
+
+        DPRINTF(EthernetDesc, "Partial Packet Descriptor of %d bytes Done\n",
+                pktPtr->length);
+        pktPtr = NULL;
+
+        enableSm();
+        igbe->checkDrain();
+        return;
+    }
+
+
+    pktMultiDesc = false;
+    // no support for vlans
+    assert(!TxdOp::vle(desc));
+
+    // we only support single packet descriptors at this point
+    if (!useTso)
+        assert(TxdOp::eop(desc));
+
+    // set that this packet is done
+    if (TxdOp::rs(desc))
+        TxdOp::setDd(desc);
+
+    DPRINTF(EthernetDesc, "TxDescriptor data d1: %#llx d2: %#llx\n",
+            desc->d1, desc->d2);
+
+    if (useTso) {
+        IpPtr ip(pktPtr);
+        if (ip) {
+            DPRINTF(EthernetDesc, "TSO: Modifying IP header. Id + %d\n",
+                    tsoPkts);
+            ip->id(ip->id() + tsoPkts++);
+            ip->len(pktPtr->length - EthPtr(pktPtr)->size()); 
+        
+            TcpPtr tcp(ip);
+            if (tcp) {
+                DPRINTF(EthernetDesc,
+                        "TSO: Modifying TCP header. old seq %d + %d\n",
+                        tcp->seq(), tsoPrevSeq);
+                tcp->seq(tcp->seq() + tsoPrevSeq);
+                if (tsoUsedLen != tsoTotalLen)
+                    tcp->flags(tcp->flags() & ~9); // clear fin & psh
+            }
+            UdpPtr udp(ip);
+            if (udp) {
+                DPRINTF(EthernetDesc, "TSO: Modifying UDP header.\n");
+                udp->len(pktPtr->length - EthPtr(pktPtr)->size());
+            }
+        }
+        tsoPrevSeq = tsoUsedLen;
+    }
+
+    if (DTRACE(EthernetDesc)) {
+        IpPtr ip(pktPtr);
+        if (ip)
+            DPRINTF(EthernetDesc, "Proccesing Ip packet with Id=%d\n",
+                    ip->id());
+        else
+            DPRINTF(EthernetSM, "Proccesing Non-Ip packet\n");
+    }
+
+    // Checksums are only ofloaded for new descriptor types
+    if (TxdOp::isData(desc) && ( TxdOp::ixsm(desc) || TxdOp::txsm(desc)) ) {
+        DPRINTF(EthernetDesc, "Calculating checksums for packet\n");
+        IpPtr ip(pktPtr);
+        assert(ip);
+        if (TxdOp::ixsm(desc)) {
+            ip->sum(0);
+            ip->sum(cksum(ip));
+            igbe->txIpChecksums++;
+            DPRINTF(EthernetDesc, "Calculated IP checksum\n");
+        }
+        if (TxdOp::txsm(desc)) {
+            TcpPtr tcp(ip);
+            UdpPtr udp(ip);
+            if (tcp) {
+                tcp->sum(0);
+                tcp->sum(cksum(tcp));
+                igbe->txTcpChecksums++;
+                DPRINTF(EthernetDesc, "Calculated TCP checksum\n");
+            } else if (udp) {
+                assert(udp);
+                udp->sum(0);
+                udp->sum(cksum(udp));
+                igbe->txUdpChecksums++;
+                DPRINTF(EthernetDesc, "Calculated UDP checksum\n");
+            } else {
+                panic("Told to checksum, but don't know how\n");
+            }
+        }
+    }
+
+    if (TxdOp::ide(desc)) {
+        // Deal with the rx timer interrupts
+        DPRINTF(EthernetDesc, "Descriptor had IDE set\n");
+        if (igbe->regs.tidv.idv()) {
+            Tick delay = igbe->regs.tidv.idv() * igbe->intClock();
+            DPRINTF(EthernetDesc, "setting tidv\n");
+            igbe->reschedule(igbe->tidvEvent, curTick() + delay, true);
+        }
+
+        if (igbe->regs.tadv.idv() && igbe->regs.tidv.idv()) {
+            Tick delay = igbe->regs.tadv.idv() * igbe->intClock();
+            DPRINTF(EthernetDesc, "setting tadv\n");
+            if (!igbe->tadvEvent.scheduled()) {
+                igbe->schedule(igbe->tadvEvent, curTick() + delay);
+            }
+        }
+    }
+
+
+    if (!useTso ||  TxdOp::getLen(desc) == tsoDescBytesUsed) {
+        DPRINTF(EthernetDesc, "Descriptor Done\n");
+        igbe->anDq("TXS", annUnusedCacheQ);
+        unusedCache.pop_front();
+        igbe->anQ("TXS", annUsedCacheQ);
+        usedCache.push_back(desc);
+        tsoDescBytesUsed = 0;
+    }
+
+    if (useTso && tsoUsedLen == tsoTotalLen)
+        useTso = false;
+
+
+    DPRINTF(EthernetDesc,
+            "------Packet of %d bytes ready for transmission-------\n",
+            pktPtr->length);
+    pktDone = true;
+    pktWaiting = false;
+    pktPtr = NULL;
+    tsoPktHasHeader = false;
+
+    if (igbe->regs.txdctl.wthresh() == 0) {
+        igbe->anBegin("TXS", "Desc Writeback");
+        DPRINTF(EthernetDesc, "WTHRESH == 0, writing back descriptor\n");
+        writeback(0);
+    } else if (!igbe->regs.txdctl.gran() && igbe->regs.txdctl.wthresh() <=
+               descInBlock(usedCache.size())) {
+        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+        igbe->anBegin("TXS", "Desc Writeback");
+        writeback((igbe->cacheBlockSize()-1)>>4);
+    } else if (igbe->regs.txdctl.wthresh() <= usedCache.size()) {
+        DPRINTF(EthernetDesc, "used > WTHRESH, writing back descriptor\n");
+        igbe->anBegin("TXS", "Desc Writeback");
+        writeback((igbe->cacheBlockSize()-1)>>4);
+    }
+
+    enableSm();
+    igbe->checkDrain();
+}
+
+void
+IGbE::TxDescCache::actionAfterWb() 
+{
+    DPRINTF(EthernetDesc, "actionAfterWb() completionEnabled: %d\n",
+            completionEnabled);
+    igbe->postInterrupt(iGbReg::IT_TXDW);
+    if (completionEnabled) { 
+        descEnd = igbe->regs.tdh();
+        DPRINTF(EthernetDesc,
+                "Completion writing back value: %d to addr: %#x\n", descEnd,
+                completionAddress);
+        igbe->dmaWrite(pciToDma(mbits(completionAddress, 63, 2)),
+                       sizeof(descEnd), &nullEvent, (uint8_t*)&descEnd, 0);
+    }
+}
+
+void
+IGbE::TxDescCache::serialize(CheckpointOut &cp) const
+{
+    DescCache<TxDesc>::serialize(cp);
+
+    SERIALIZE_SCALAR(pktDone);
+    SERIALIZE_SCALAR(isTcp);
+    SERIALIZE_SCALAR(pktWaiting);
+    SERIALIZE_SCALAR(pktMultiDesc);
+
+    SERIALIZE_SCALAR(useTso);
+    SERIALIZE_SCALAR(tsoHeaderLen);
+    SERIALIZE_SCALAR(tsoMss);
+    SERIALIZE_SCALAR(tsoTotalLen);
+    SERIALIZE_SCALAR(tsoUsedLen);
+    SERIALIZE_SCALAR(tsoPrevSeq);;
+    SERIALIZE_SCALAR(tsoPktPayloadBytes);
+    SERIALIZE_SCALAR(tsoLoadedHeader);
+    SERIALIZE_SCALAR(tsoPktHasHeader);
+    SERIALIZE_ARRAY(tsoHeader, 256);
+    SERIALIZE_SCALAR(tsoDescBytesUsed);
+    SERIALIZE_SCALAR(tsoCopyBytes);
+    SERIALIZE_SCALAR(tsoPkts);
+
+    SERIALIZE_SCALAR(completionAddress);
+    SERIALIZE_SCALAR(completionEnabled);
+    SERIALIZE_SCALAR(descEnd);
+}
+
+void
+IGbE::TxDescCache::unserialize(CheckpointIn &cp)
+{
+    DescCache<TxDesc>::unserialize(cp);
+
+    UNSERIALIZE_SCALAR(pktDone);
+    UNSERIALIZE_SCALAR(isTcp);
+    UNSERIALIZE_SCALAR(pktWaiting);
+    UNSERIALIZE_SCALAR(pktMultiDesc);
+
+    UNSERIALIZE_SCALAR(useTso);
+    UNSERIALIZE_SCALAR(tsoHeaderLen);
+    UNSERIALIZE_SCALAR(tsoMss);
+    UNSERIALIZE_SCALAR(tsoTotalLen);
+    UNSERIALIZE_SCALAR(tsoUsedLen);
+    UNSERIALIZE_SCALAR(tsoPrevSeq);;
+    UNSERIALIZE_SCALAR(tsoPktPayloadBytes);
+    UNSERIALIZE_SCALAR(tsoLoadedHeader);
+    UNSERIALIZE_SCALAR(tsoPktHasHeader);
+    UNSERIALIZE_ARRAY(tsoHeader, 256);
+    UNSERIALIZE_SCALAR(tsoDescBytesUsed);
+    UNSERIALIZE_SCALAR(tsoCopyBytes);
+    UNSERIALIZE_SCALAR(tsoPkts);
+
+    UNSERIALIZE_SCALAR(completionAddress);
+    UNSERIALIZE_SCALAR(completionEnabled);
+    UNSERIALIZE_SCALAR(descEnd);
+}
+
+bool
+IGbE::TxDescCache::packetAvailable()
+{
+    if (pktDone) {
+        pktDone = false;
+        return true;
+    }
+    return false;
+}
+
+void
+IGbE::TxDescCache::enableSm()
+{
+    if (igbe->drainState() != DrainState::Draining) {
+        igbe->txTick = true;
+        igbe->restartClock();
+    }
+}
+
+bool
+IGbE::TxDescCache::hasOutstandingEvents()
+{
+    return pktEvent.scheduled() || wbEvent.scheduled() ||
+        fetchEvent.scheduled();
+}
+
+
+///////////////////////////////////// IGbE /////////////////////////////////
+
+void
+IGbE::restartClock()
+{
+    if (!tickEvent.scheduled() && (rxTick || txTick || txFifoTick) &&
+        drainState() == DrainState::Running)
+        schedule(tickEvent, clockEdge(Cycles(1)));
+}
+
+DrainState
+IGbE::drain()
+{
+    unsigned int count(0);
+    if (rxDescCache.hasOutstandingEvents() ||
+        txDescCache.hasOutstandingEvents()) {
+        count++;
+    }
+
+    txFifoTick = false;
+    txTick = false;
+    rxTick = false;
+
+    if (tickEvent.scheduled())
+        deschedule(tickEvent);
+
+    if (count) {
+        DPRINTF(Drain, "IGbE not drained\n");
+        return DrainState::Draining;
+    } else
+        return DrainState::Drained;
+}
+
+void
+IGbE::drainResume()
+{
+    Drainable::drainResume();
+
+    txFifoTick = true;
+    txTick = true;
+    rxTick = true;
+
+    restartClock();
+    DPRINTF(EthernetSM, "resuming from drain");
+}
+
+void
+IGbE::checkDrain()
+{
+    if (drainState() != DrainState::Draining)
+        return;
+
+    txFifoTick = false;
+    txTick = false;
+    rxTick = false;
+    if (!rxDescCache.hasOutstandingEvents() &&
+        !txDescCache.hasOutstandingEvents()) {
+        DPRINTF(Drain, "IGbE done draining, processing drain event\n");
+        signalDrainDone();
+    }
+}
+
+void
+IGbE::txStateMachine()
+{
+    if (!regs.tctl.en()) {
+        txTick = false;
+        DPRINTF(EthernetSM, "TXS: TX disabled, stopping ticking\n");
+        return;
+    }
+
+    // If we have a packet available and it's length is not 0 (meaning it's not
+    // a multidescriptor packet) put it in the fifo, otherwise an the next
+    // iteration we'll get the rest of the data
+    if (txPacket && txDescCache.packetAvailable()
+        && !txDescCache.packetMultiDesc() && txPacket->length) {
+        anQ("TXS", "TX FIFO Q");
+        DPRINTF(EthernetSM, "TXS: packet placed in TX FIFO\n");
+#ifndef NDEBUG
+        bool success =
+#endif
+            txFifo.push(txPacket);
+        txFifoTick = true && drainState() != DrainState::Draining;
+        assert(success);
+        txPacket = NULL;
+        anBegin("TXS", "Desc Writeback");
+        txDescCache.writeback((cacheBlockSize()-1)>>4);
+        return;
+    }
+
+    // Only support descriptor granularity
+    if (regs.txdctl.lwthresh() &&
+        txDescCache.descLeft() < (regs.txdctl.lwthresh() * 8)) {
+        DPRINTF(EthernetSM, "TXS: LWTHRESH caused posting of TXDLOW\n");
+        postInterrupt(IT_TXDLOW);
+    }
+
+    if (!txPacket) {
+        txPacket = std::make_shared<EthPacketData>(16384);
+    }
+
+    if (!txDescCache.packetWaiting()) {
+        if (txDescCache.descLeft() == 0) {
+            postInterrupt(IT_TXQE);
+            anBegin("TXS", "Desc Writeback");
+            txDescCache.writeback(0);
+            anBegin("TXS", "Desc Fetch");
+            anWe("TXS", txDescCache.annUnusedCacheQ);
+            txDescCache.fetchDescriptors();
+            DPRINTF(EthernetSM, "TXS: No descriptors left in ring, forcing "
+                    "writeback stopping ticking and posting TXQE\n");
+            txTick = false;
+            return;
+        }
+
+
+        if (!(txDescCache.descUnused())) {
+            anBegin("TXS", "Desc Fetch");
+            txDescCache.fetchDescriptors();
+            anWe("TXS", txDescCache.annUnusedCacheQ);
+            DPRINTF(EthernetSM, "TXS: No descriptors available in cache, "
+                    "fetching and stopping ticking\n");
+            txTick = false;
+            return;
+        }
+        anPq("TXS", txDescCache.annUnusedCacheQ);
+
+
+        txDescCache.processContextDesc();
+        if (txDescCache.packetWaiting()) {
+            DPRINTF(EthernetSM,
+                    "TXS: Fetching TSO header, stopping ticking\n");
+            txTick = false;
+            return;
+        }
+
+        unsigned size = txDescCache.getPacketSize(txPacket);
+        if (size > 0 && txFifo.avail() > size) {
+            anRq("TXS", "TX FIFO Q");
+            anBegin("TXS", "DMA Packet");
+            DPRINTF(EthernetSM, "TXS: Reserving %d bytes in FIFO and "
+                    "beginning DMA of next packet\n", size);
+            txFifo.reserve(size);
+            txDescCache.getPacketData(txPacket);
+        } else if (size == 0) {
+            DPRINTF(EthernetSM, "TXS: getPacketSize returned: %d\n", size);
+            DPRINTF(EthernetSM,
+                    "TXS: No packets to get, writing back used descriptors\n");
+            anBegin("TXS", "Desc Writeback");
+            txDescCache.writeback(0);
+        } else {
+            anWf("TXS", "TX FIFO Q");
+            DPRINTF(EthernetSM, "TXS: FIFO full, stopping ticking until space "
+                    "available in FIFO\n");
+            txTick = false;
+        }
+
+
+        return;
+    }
+    DPRINTF(EthernetSM, "TXS: Nothing to do, stopping ticking\n");
+    txTick = false;
+}
+
+bool
+IGbE::ethRxPkt(EthPacketPtr pkt)
+{
+    rxBytes += pkt->length;
+    rxPackets++;
+
+    DPRINTF(Ethernet, "RxFIFO: Receiving pcakte from wire\n");
+    anBegin("RXQ", "Wire Recv");
+
+
+    if (!regs.rctl.en()) {
+        DPRINTF(Ethernet, "RxFIFO: RX not enabled, dropping\n");
+        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
+        return true;
+    }
+
+    // restart the state machines if they are stopped
+    rxTick = true && drainState() != DrainState::Draining;
+    if ((rxTick || txTick) && !tickEvent.scheduled()) {
+        DPRINTF(EthernetSM,
+                "RXS: received packet into fifo, starting ticking\n");
+        restartClock();
+    }
+
+    if (!rxFifo.push(pkt)) {
+        DPRINTF(Ethernet, "RxFIFO: Packet won't fit in fifo... dropped\n");
+        postInterrupt(IT_RXO, true);
+        anBegin("RXQ", "FIFO Drop", CPA::FL_BAD);
+        return false;
+    }
+
+    if (CPA::available() && cpa->enabled()) {
+        assert(sys->numSystemsRunning <= 2);
+        System *other_sys;
+        if (sys->systemList[0] == sys)
+            other_sys = sys->systemList[1];
+        else
+            other_sys = sys->systemList[0];
+
+        cpa->hwDq(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+        anQ("RXQ", "RX FIFO Q");
+        cpa->hwWe(CPA::FL_NONE, sys, macAddr, "RXQ", "WireQ", 0, other_sys);
+    }
+
+    return true;
+}
+
+
+void
+IGbE::rxStateMachine()
+{
+    if (!regs.rctl.en()) {
+        rxTick = false;
+        DPRINTF(EthernetSM, "RXS: RX disabled, stopping ticking\n");
+        return;
+    }
+
+    // If the packet is done check for interrupts/descriptors/etc
+    if (rxDescCache.packetDone()) {
+        rxDmaPacket = false;
+        DPRINTF(EthernetSM, "RXS: Packet completed DMA to memory\n");
+        int descLeft = rxDescCache.descLeft();
+        DPRINTF(EthernetSM, "RXS: descLeft: %d rdmts: %d rdlen: %d\n",
+                descLeft, regs.rctl.rdmts(), regs.rdlen());
+        switch (regs.rctl.rdmts()) {
+          case 2: if (descLeft > .125 * regs.rdlen()) break;
+          case 1: if (descLeft > .250 * regs.rdlen()) break;
+          case 0: if (descLeft > .500 * regs.rdlen())  break;
+            DPRINTF(Ethernet, "RXS: Interrupting (RXDMT) "
+                    "because of descriptors left\n");
+            postInterrupt(IT_RXDMT);
+            break;
+        }
+
+        if (rxFifo.empty())
+            rxDescCache.writeback(0);
+
+        if (descLeft == 0) {
+            anBegin("RXS", "Writeback Descriptors");
+            rxDescCache.writeback(0);
+            DPRINTF(EthernetSM, "RXS: No descriptors left in ring, forcing"
+                    " writeback and stopping ticking\n");
+            rxTick = false;
+        }
+
+        // only support descriptor granulaties
+        assert(regs.rxdctl.gran());
+
+        if (regs.rxdctl.wthresh() >= rxDescCache.descUsed()) {
+            DPRINTF(EthernetSM,
+                    "RXS: Writing back because WTHRESH >= descUsed\n");
+            anBegin("RXS", "Writeback Descriptors");
+            if (regs.rxdctl.wthresh() < (cacheBlockSize()>>4))
+                rxDescCache.writeback(regs.rxdctl.wthresh()-1);
+            else
+                rxDescCache.writeback((cacheBlockSize()-1)>>4);
+        }
+
+        if ((rxDescCache.descUnused() < regs.rxdctl.pthresh()) &&
+            ((rxDescCache.descLeft() - rxDescCache.descUnused()) >
+             regs.rxdctl.hthresh())) {
+            DPRINTF(EthernetSM, "RXS: Fetching descriptors because "
+                    "descUnused < PTHRESH\n");
+            anBegin("RXS", "Fetch Descriptors");
+            rxDescCache.fetchDescriptors();
+        }
+
+        if (rxDescCache.descUnused() == 0) {
+            anBegin("RXS", "Fetch Descriptors");
+            rxDescCache.fetchDescriptors();
+            anWe("RXS", rxDescCache.annUnusedCacheQ);
+            DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
+                    "fetching descriptors and stopping ticking\n");
+            rxTick = false;
+        }
+        return;
+    }
+
+    if (rxDmaPacket) {
+        DPRINTF(EthernetSM,
+                "RXS: stopping ticking until packet DMA completes\n");
+        rxTick = false;
+        return;
+    }
+
+    if (!rxDescCache.descUnused()) {
+        anBegin("RXS", "Fetch Descriptors");
+        rxDescCache.fetchDescriptors();
+        anWe("RXS", rxDescCache.annUnusedCacheQ);
+        DPRINTF(EthernetSM, "RXS: No descriptors available in cache, "
+                "stopping ticking\n");
+        rxTick = false;
+        DPRINTF(EthernetSM, "RXS: No descriptors available, fetching\n");
+        return;
+    }
+    anPq("RXS", rxDescCache.annUnusedCacheQ);
+
+    if (rxFifo.empty()) {
+        anWe("RXS", "RX FIFO Q");
+        DPRINTF(EthernetSM, "RXS: RxFIFO empty, stopping ticking\n");
+        rxTick = false;
+        return;
+    }
+    anPq("RXS", "RX FIFO Q");
+    anBegin("RXS", "Get Desc");
+
+    EthPacketPtr pkt;
+    pkt = rxFifo.front();
+
+
+    pktOffset = rxDescCache.writePacket(pkt, pktOffset);
+    DPRINTF(EthernetSM, "RXS: Writing packet into memory\n");
+    if (pktOffset == pkt->length) {
+        anBegin( "RXS", "FIFO Dequeue");
+        DPRINTF(EthernetSM, "RXS: Removing packet from FIFO\n");
+        pktOffset = 0;
+        anDq("RXS", "RX FIFO Q");
+        rxFifo.pop();
+    }
+
+    DPRINTF(EthernetSM, "RXS: stopping ticking until packet DMA completes\n");
+    rxTick = false;
+    rxDmaPacket = true;
+    anBegin("RXS", "DMA Packet");
+}
+
+void
+IGbE::txWire()
+{
+    if (txFifo.empty()) {
+        anWe("TXQ", "TX FIFO Q");
+        txFifoTick = false;
+        return;
+    }
+
+
+    anPq("TXQ", "TX FIFO Q");
+    if (etherInt->sendPacket(txFifo.front())) {
+        anQ("TXQ", "WireQ");
+        if (DTRACE(EthernetSM)) {
+            IpPtr ip(txFifo.front());
+            if (ip)
+                DPRINTF(EthernetSM, "Transmitting Ip packet with Id=%d\n",
+                        ip->id());
+            else
+                DPRINTF(EthernetSM, "Transmitting Non-Ip packet\n");
+        }
+        anDq("TXQ", "TX FIFO Q");
+        anBegin("TXQ", "Wire Send");
+        DPRINTF(EthernetSM,
+                "TxFIFO: Successful transmit, bytes available in fifo: %d\n",
+                txFifo.avail());
+
+        txBytes += txFifo.front()->length;
+        txPackets++;
+        txFifoTick = false;
+
+        txFifo.pop();
+    } else {
+        // We'll get woken up when the packet ethTxDone() gets called
+        txFifoTick = false;
+    }
+}
+
+void
+IGbE::tick()
+{
+    DPRINTF(EthernetSM, "IGbE: -------------- Cycle --------------\n");
+
+    if (rxTick)
+        rxStateMachine();
+
+    if (txTick)
+        txStateMachine();
+
+    if (txFifoTick)
+        txWire();
+
+
+    if (rxTick || txTick || txFifoTick)
+        schedule(tickEvent, curTick() + clockPeriod());
+}
+
+void
+IGbE::ethTxDone()
+{
+    anBegin("TXQ", "Send Done");
+    // restart the tx state machines if they are stopped
+    // fifo to send another packet
+    // tx sm to put more data into the fifo
+    txFifoTick = true && drainState() != DrainState::Draining;
+    if (txDescCache.descLeft() != 0 && drainState() != DrainState::Draining)
+        txTick = true;
+
+    restartClock();
+    txWire();
+    DPRINTF(EthernetSM, "TxFIFO: Transmission complete\n");
+}
+
+void
+IGbE::serialize(CheckpointOut &cp) const
+{
+    PciDevice::serialize(cp);
+
+    regs.serialize(cp);
+    SERIALIZE_SCALAR(eeOpBits);
+    SERIALIZE_SCALAR(eeAddrBits);
+    SERIALIZE_SCALAR(eeDataBits);
+    SERIALIZE_SCALAR(eeOpcode);
+    SERIALIZE_SCALAR(eeAddr);
+    SERIALIZE_SCALAR(lastInterrupt);
+    SERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
+
+    rxFifo.serialize("rxfifo", cp);
+    txFifo.serialize("txfifo", cp);
+
+    bool txPktExists = txPacket != nullptr;
+    SERIALIZE_SCALAR(txPktExists);
+    if (txPktExists)
+        txPacket->serialize("txpacket", cp);
+
+    Tick rdtr_time = 0, radv_time = 0, tidv_time = 0, tadv_time = 0,
+        inter_time = 0;
+
+    if (rdtrEvent.scheduled())
+        rdtr_time = rdtrEvent.when();
+    SERIALIZE_SCALAR(rdtr_time);
+
+    if (radvEvent.scheduled())
+        radv_time = radvEvent.when();
+    SERIALIZE_SCALAR(radv_time);
+
+    if (tidvEvent.scheduled())
+        tidv_time = tidvEvent.when();
+    SERIALIZE_SCALAR(tidv_time);
+
+    if (tadvEvent.scheduled())
+        tadv_time = tadvEvent.when();
+    SERIALIZE_SCALAR(tadv_time);
+
+    if (interEvent.scheduled())
+        inter_time = interEvent.when();
+    SERIALIZE_SCALAR(inter_time);
+
+    SERIALIZE_SCALAR(pktOffset);
+
+    txDescCache.serializeSection(cp, "TxDescCache");
+    rxDescCache.serializeSection(cp, "RxDescCache");
+}
+
+void
+IGbE::unserialize(CheckpointIn &cp)
+{
+    PciDevice::unserialize(cp);
+
+    regs.unserialize(cp);
+    UNSERIALIZE_SCALAR(eeOpBits);
+    UNSERIALIZE_SCALAR(eeAddrBits);
+    UNSERIALIZE_SCALAR(eeDataBits);
+    UNSERIALIZE_SCALAR(eeOpcode);
+    UNSERIALIZE_SCALAR(eeAddr);
+    UNSERIALIZE_SCALAR(lastInterrupt);
+    UNSERIALIZE_ARRAY(flash,iGbReg::EEPROM_SIZE);
+
+    rxFifo.unserialize("rxfifo", cp);
+    txFifo.unserialize("txfifo", cp);
+
+    bool txPktExists;
+    UNSERIALIZE_SCALAR(txPktExists);
+    if (txPktExists) {
+        txPacket = std::make_shared<EthPacketData>(16384);
+        txPacket->unserialize("txpacket", cp);
+    }
+
+    rxTick = true;
+    txTick = true;
+    txFifoTick = true;
+
+    Tick rdtr_time, radv_time, tidv_time, tadv_time, inter_time;
+    UNSERIALIZE_SCALAR(rdtr_time);
+    UNSERIALIZE_SCALAR(radv_time);
+    UNSERIALIZE_SCALAR(tidv_time);
+    UNSERIALIZE_SCALAR(tadv_time);
+    UNSERIALIZE_SCALAR(inter_time);
+
+    if (rdtr_time)
+        schedule(rdtrEvent, rdtr_time);
+
+    if (radv_time)
+        schedule(radvEvent, radv_time);
+
+    if (tidv_time)
+        schedule(tidvEvent, tidv_time);
+
+    if (tadv_time)
+        schedule(tadvEvent, tadv_time);
+
+    if (inter_time)
+        schedule(interEvent, inter_time);
+
+    UNSERIALIZE_SCALAR(pktOffset);
+
+    txDescCache.unserializeSection(cp, "TxDescCache");
+    rxDescCache.unserializeSection(cp, "RxDescCache");
+}
+
+IGbE *
+IGbEParams::create()
+{
+    return new IGbE(this);
+}
diff --git a/src/dev/net/i8254xGBe.hh b/src/dev/net/i8254xGBe.hh
new file mode 100644 (file)
index 0000000..e357444
--- /dev/null
@@ -0,0 +1,560 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Device model for Intel's 8254x line of gigabit ethernet controllers.
+ */
+
+#ifndef __DEV_NET_I8254XGBE_HH__
+#define __DEV_NET_I8254XGBE_HH__
+
+#include <deque>
+#include <string>
+
+#include "base/cp_annotate.hh"
+#include "base/inet.hh"
+#include "debug/EthernetDesc.hh"
+#include "debug/EthernetIntr.hh"
+#include "dev/net/etherdevice.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+#include "dev/net/i8254xGBe_defs.hh"
+#include "dev/net/pktfifo.hh"
+#include "dev/pci/device.hh"
+#include "params/IGbE.hh"
+#include "sim/eventq.hh"
+
+class IGbEInt;
+
+class IGbE : public EtherDevice
+{
+  private:
+    IGbEInt *etherInt;
+    CPA *cpa;
+
+    // device registers
+    iGbReg::Regs regs;
+
+    // eeprom data, status and control bits
+    int eeOpBits, eeAddrBits, eeDataBits;
+    uint8_t eeOpcode, eeAddr;
+    uint16_t flash[iGbReg::EEPROM_SIZE];
+
+    // packet fifos
+    PacketFifo rxFifo;
+    PacketFifo txFifo;
+
+    // Packet that we are currently putting into the txFifo
+    EthPacketPtr txPacket;
+
+    // Should to Rx/Tx State machine tick?
+    bool rxTick;
+    bool txTick;
+    bool txFifoTick;
+
+    bool rxDmaPacket;
+
+    // Number of bytes copied from current RX packet
+    unsigned pktOffset;
+
+    // Delays in managaging descriptors
+    Tick fetchDelay, wbDelay;
+    Tick fetchCompDelay, wbCompDelay;
+    Tick rxWriteDelay, txReadDelay;
+
+    // Event and function to deal with RDTR timer expiring
+    void rdtrProcess() {
+        rxDescCache.writeback(0);
+        DPRINTF(EthernetIntr,
+                "Posting RXT interrupt because RDTR timer expired\n");
+        postInterrupt(iGbReg::IT_RXT);
+    }
+
+    //friend class EventWrapper<IGbE, &IGbE::rdtrProcess>;
+    EventWrapper<IGbE, &IGbE::rdtrProcess> rdtrEvent;
+
+    // Event and function to deal with RADV timer expiring
+    void radvProcess() {
+        rxDescCache.writeback(0);
+        DPRINTF(EthernetIntr,
+                "Posting RXT interrupt because RADV timer expired\n");
+        postInterrupt(iGbReg::IT_RXT);
+    }
+
+    //friend class EventWrapper<IGbE, &IGbE::radvProcess>;
+    EventWrapper<IGbE, &IGbE::radvProcess> radvEvent;
+
+    // Event and function to deal with TADV timer expiring
+    void tadvProcess() {
+        txDescCache.writeback(0);
+        DPRINTF(EthernetIntr,
+                "Posting TXDW interrupt because TADV timer expired\n");
+        postInterrupt(iGbReg::IT_TXDW);
+    }
+
+    //friend class EventWrapper<IGbE, &IGbE::tadvProcess>;
+    EventWrapper<IGbE, &IGbE::tadvProcess> tadvEvent;
+
+    // Event and function to deal with TIDV timer expiring
+    void tidvProcess() {
+        txDescCache.writeback(0);
+        DPRINTF(EthernetIntr,
+                "Posting TXDW interrupt because TIDV timer expired\n");
+        postInterrupt(iGbReg::IT_TXDW);
+    }
+    //friend class EventWrapper<IGbE, &IGbE::tidvProcess>;
+    EventWrapper<IGbE, &IGbE::tidvProcess> tidvEvent;
+
+    // Main event to tick the device
+    void tick();
+    //friend class EventWrapper<IGbE, &IGbE::tick>;
+    EventWrapper<IGbE, &IGbE::tick> tickEvent;
+
+
+    uint64_t macAddr;
+
+    void rxStateMachine();
+    void txStateMachine();
+    void txWire();
+
+    /** Write an interrupt into the interrupt pending register and check mask
+     * and interrupt limit timer before sending interrupt to CPU
+     * @param t the type of interrupt we are posting
+     * @param now should we ignore the interrupt limiting timer
+     */
+    void postInterrupt(iGbReg::IntTypes t, bool now = false);
+
+    /** Check and see if changes to the mask register have caused an interrupt
+     * to need to be sent or perhaps removed an interrupt cause.
+     */
+    void chkInterrupt();
+
+    /** Send an interrupt to the cpu
+     */
+    void delayIntEvent();
+    void cpuPostInt();
+    // Event to moderate interrupts
+    EventWrapper<IGbE, &IGbE::delayIntEvent> interEvent;
+
+    /** Clear the interupt line to the cpu
+     */
+    void cpuClearInt();
+
+    Tick intClock() { return SimClock::Int::ns * 1024; }
+
+    /** This function is used to restart the clock so it can handle things like
+     * draining and resume in one place. */
+    void restartClock();
+
+    /** Check if all the draining things that need to occur have occured and
+     * handle the drain event if so.
+     */
+    void checkDrain();
+
+    void anBegin(std::string sm, std::string st, int flags = CPA::FL_NONE) {
+        if (cpa)
+            cpa->hwBegin((CPA::flags)flags, sys, macAddr, sm, st);
+    }
+
+    void anQ(std::string sm, std::string q) {
+        if (cpa)
+            cpa->hwQ(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anDq(std::string sm, std::string q) {
+        if (cpa)
+            cpa->hwDq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anPq(std::string sm, std::string q, int num = 1) {
+        if (cpa)
+            cpa->hwPq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+    }
+
+    void anRq(std::string sm, std::string q, int num = 1) {
+        if (cpa)
+            cpa->hwRq(CPA::FL_NONE, sys, macAddr, sm, q, macAddr, NULL, num);
+    }
+
+    void anWe(std::string sm, std::string q) {
+        if (cpa)
+            cpa->hwWe(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+    void anWf(std::string sm, std::string q) {
+        if (cpa)
+            cpa->hwWf(CPA::FL_NONE, sys, macAddr, sm, q, macAddr);
+    }
+
+
+    template<class T>
+    class DescCache : public Serializable
+    {
+      protected:
+        virtual Addr descBase() const = 0;
+        virtual long descHead() const = 0;
+        virtual long descTail() const = 0;
+        virtual long descLen() const = 0;
+        virtual void updateHead(long h) = 0;
+        virtual void enableSm() = 0;
+        virtual void actionAfterWb() {}
+        virtual void fetchAfterWb() = 0;
+
+        typedef std::deque<T *> CacheType;
+        CacheType usedCache;
+        CacheType unusedCache;
+
+        T *fetchBuf;
+        T *wbBuf;
+
+        // Pointer to the device we cache for
+        IGbE *igbe;
+
+        // Name of this  descriptor cache
+        std::string _name;
+
+        // How far we've cached
+        int cachePnt;
+
+        // The size of the descriptor cache
+        int size;
+
+        // How many descriptors we are currently fetching
+        int curFetching;
+
+        // How many descriptors we are currently writing back
+        int wbOut;
+
+        // if the we wrote back to the end of the descriptor ring and are going
+        // to have to wrap and write more
+        bool moreToWb;
+
+        // What the alignment is of the next descriptor writeback
+        Addr wbAlignment;
+
+        /** The packet that is currently being dmad to memory if any */
+        EthPacketPtr pktPtr;
+
+        /** Shortcut for DMA address translation */
+        Addr pciToDma(Addr a) { return igbe->pciToDma(a); }
+
+      public:
+        /** Annotate sm*/
+        std::string annSmFetch, annSmWb, annUnusedDescQ, annUsedCacheQ,
+            annUsedDescQ, annUnusedCacheQ, annDescQ;
+
+        DescCache(IGbE *i, const std::string n, int s);
+        virtual ~DescCache();
+
+        std::string name() { return _name; }
+
+        /** If the address/len/head change when we've got descriptors that are
+         * dirty that is very bad. This function checks that we don't and if we
+         * do panics.
+         */
+        void areaChanged();
+
+        void writeback(Addr aMask);
+        void writeback1();
+        EventWrapper<DescCache, &DescCache::writeback1> wbDelayEvent;
+
+        /** Fetch a chunk of descriptors into the descriptor cache.
+         * Calls fetchComplete when the memory system returns the data
+         */
+        void fetchDescriptors();
+        void fetchDescriptors1();
+        EventWrapper<DescCache, &DescCache::fetchDescriptors1> fetchDelayEvent;
+
+        /** Called by event when dma to read descriptors is completed
+         */
+        void fetchComplete();
+        EventWrapper<DescCache, &DescCache::fetchComplete> fetchEvent;
+
+        /** Called by event when dma to writeback descriptors is completed
+         */
+        void wbComplete();
+        EventWrapper<DescCache, &DescCache::wbComplete> wbEvent;
+
+        /* Return the number of descriptors left in the ring, so the device has
+         * a way to figure out if it needs to interrupt.
+         */
+        unsigned
+        descLeft() const
+        {
+            unsigned left = unusedCache.size();
+            if (cachePnt > descTail())
+                left += (descLen() - cachePnt + descTail());
+            else
+                left += (descTail() - cachePnt);
+
+            return left;
+        }
+
+        /* Return the number of descriptors used and not written back.
+         */
+        unsigned descUsed() const { return usedCache.size(); }
+
+        /* Return the number of cache unused descriptors we have. */
+        unsigned descUnused() const { return unusedCache.size(); }
+
+        /* Get into a state where the descriptor address/head/etc colud be
+         * changed */
+        void reset();
+
+
+        void serialize(CheckpointOut &cp) const override;
+        void unserialize(CheckpointIn &cp) override;
+
+        virtual bool hasOutstandingEvents() {
+            return wbEvent.scheduled() || fetchEvent.scheduled();
+        }
+
+    };
+
+
+    class RxDescCache : public DescCache<iGbReg::RxDesc>
+    {
+      protected:
+        Addr descBase() const override { return igbe->regs.rdba(); }
+        long descHead() const override { return igbe->regs.rdh(); }
+        long descLen() const override { return igbe->regs.rdlen() >> 4; }
+        long descTail() const override { return igbe->regs.rdt(); }
+        void updateHead(long h) override { igbe->regs.rdh(h); }
+        void enableSm() override;
+        void fetchAfterWb() override {
+            if (!igbe->rxTick && igbe->drainState() == DrainState::Running)
+                fetchDescriptors();
+        }
+
+        bool pktDone;
+
+        /** Variable to head with header/data completion events */
+        int splitCount;
+
+        /** Bytes of packet that have been copied, so we know when to
+            set EOP */
+        unsigned bytesCopied;
+
+      public:
+        RxDescCache(IGbE *i, std::string n, int s);
+
+        /** Write the given packet into the buffer(s) pointed to by the
+         * descriptor and update the book keeping. Should only be called when
+         * there are no dma's pending.
+         * @param packet ethernet packet to write
+         * @param pkt_offset bytes already copied from the packet to memory
+         * @return pkt_offset + number of bytes copied during this call
+         */
+        int writePacket(EthPacketPtr packet, int pkt_offset);
+
+        /** Called by event when dma to write packet is completed
+         */
+        void pktComplete();
+
+        /** Check if the dma on the packet has completed and RX state machine
+         * can continue
+         */
+        bool packetDone();
+
+        EventWrapper<RxDescCache, &RxDescCache::pktComplete> pktEvent;
+
+        // Event to handle issuing header and data write at the same time
+        // and only callking pktComplete() when both are completed
+        void pktSplitDone();
+        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktHdrEvent;
+        EventWrapper<RxDescCache, &RxDescCache::pktSplitDone> pktDataEvent;
+
+        bool hasOutstandingEvents() override;
+
+        void serialize(CheckpointOut &cp) const override;
+        void unserialize(CheckpointIn &cp) override;
+    };
+    friend class RxDescCache;
+
+    RxDescCache rxDescCache;
+
+    class TxDescCache  : public DescCache<iGbReg::TxDesc>
+    {
+      protected:
+        Addr descBase() const override { return igbe->regs.tdba(); }
+        long descHead() const override { return igbe->regs.tdh(); }
+        long descTail() const override { return igbe->regs.tdt(); }
+        long descLen() const override { return igbe->regs.tdlen() >> 4; }
+        void updateHead(long h) override { igbe->regs.tdh(h); }
+        void enableSm() override;
+        void actionAfterWb() override;
+        void fetchAfterWb() override {
+            if (!igbe->txTick && igbe->drainState() == DrainState::Running)
+                fetchDescriptors();
+        }
+        
+
+
+        bool pktDone;
+        bool isTcp;
+        bool pktWaiting;
+        bool pktMultiDesc;
+        Addr completionAddress;
+        bool completionEnabled;
+        uint32_t descEnd;
+        
+
+        // tso variables
+        bool useTso;
+        Addr tsoHeaderLen;
+        Addr tsoMss;
+        Addr tsoTotalLen;
+        Addr tsoUsedLen;
+        Addr tsoPrevSeq;
+        Addr tsoPktPayloadBytes;
+        bool tsoLoadedHeader;
+        bool tsoPktHasHeader;
+        uint8_t tsoHeader[256];
+        Addr tsoDescBytesUsed;
+        Addr tsoCopyBytes;
+        int tsoPkts;
+
+      public:
+        TxDescCache(IGbE *i, std::string n, int s);
+
+        /** Tell the cache to DMA a packet from main memory into its buffer and
+         * return the size the of the packet to reserve space in tx fifo.
+         * @return size of the packet
+         */
+        unsigned getPacketSize(EthPacketPtr p);
+        void getPacketData(EthPacketPtr p);
+        void processContextDesc();
+
+        /** Return the number of dsecriptors in a cache block for threshold
+         * operations.
+         */
+        unsigned
+        descInBlock(unsigned num_desc)
+        {
+            return num_desc / igbe->cacheBlockSize() / sizeof(iGbReg::TxDesc);
+        }
+
+        /** Ask if the packet has been transfered so the state machine can give
+         * it to the fifo.
+         * @return packet available in descriptor cache
+         */
+        bool packetAvailable();
+
+        /** Ask if we are still waiting for the packet to be transfered.
+         * @return packet still in transit.
+         */
+        bool packetWaiting() { return pktWaiting; }
+
+        /** Ask if this packet is composed of multiple descriptors
+         * so even if we've got data, we need to wait for more before
+         * we can send it out.
+         * @return packet can't be sent out because it's a multi-descriptor
+         * packet
+         */
+        bool packetMultiDesc() { return pktMultiDesc;}
+
+        /** Called by event when dma to write packet is completed
+         */
+        void pktComplete();
+        EventWrapper<TxDescCache, &TxDescCache::pktComplete> pktEvent;
+
+        void headerComplete();
+        EventWrapper<TxDescCache, &TxDescCache::headerComplete> headerEvent;
+
+
+        void completionWriteback(Addr a, bool enabled) {
+            DPRINTF(EthernetDesc,
+                    "Completion writeback Addr: %#x enabled: %d\n", 
+                    a, enabled);
+            completionAddress = a;
+            completionEnabled = enabled;
+        }
+
+        bool hasOutstandingEvents() override;
+
+        void nullCallback() {
+            DPRINTF(EthernetDesc, "Completion writeback complete\n");
+        }
+        EventWrapper<TxDescCache, &TxDescCache::nullCallback> nullEvent;
+
+        void serialize(CheckpointOut &cp) const override;
+        void unserialize(CheckpointIn &cp) override;
+    };
+
+    friend class TxDescCache;
+
+    TxDescCache txDescCache;
+
+  public:
+    typedef IGbEParams Params;
+    const Params *
+    params() const {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    IGbE(const Params *params);
+    ~IGbE();
+    void init() override;
+
+    EtherInt *getEthPort(const std::string &if_name, int idx) override;
+
+    Tick lastInterrupt;
+
+    Tick read(PacketPtr pkt) override;
+    Tick write(PacketPtr pkt) override;
+
+    Tick writeConfig(PacketPtr pkt) override;
+
+    bool ethRxPkt(EthPacketPtr packet);
+    void ethTxDone();
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+    DrainState drain() override;
+    void drainResume() override;
+
+};
+
+class IGbEInt : public EtherInt
+{
+  private:
+    IGbE *dev;
+
+  public:
+    IGbEInt(const std::string &name, IGbE *d)
+        : EtherInt(name), dev(d)
+    { }
+
+    virtual bool recvPacket(EthPacketPtr pkt) { return dev->ethRxPkt(pkt); }
+    virtual void sendDone() { dev->ethTxDone(); }
+};
+
+#endif //__DEV_NET_I8254XGBE_HH__
diff --git a/src/dev/net/i8254xGBe_defs.hh b/src/dev/net/i8254xGBe_defs.hh
new file mode 100644 (file)
index 0000000..79a9413
--- /dev/null
@@ -0,0 +1,854 @@
+/*
+ * Copyright (c) 2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Ali Saidi
+ */
+
+/* @file
+ * Register and structure descriptions for Intel's 8254x line of gigabit ethernet controllers.
+ */
+#include "base/bitfield.hh"
+
+namespace iGbReg {
+
+
+// Registers used by the Intel GbE NIC
+const uint32_t REG_CTRL     = 0x00000;
+const uint32_t REG_STATUS   = 0x00008;
+const uint32_t REG_EECD     = 0x00010;
+const uint32_t REG_EERD     = 0x00014;
+const uint32_t REG_CTRL_EXT = 0x00018;
+const uint32_t REG_MDIC     = 0x00020;
+const uint32_t REG_FCAL     = 0x00028;
+const uint32_t REG_FCAH     = 0x0002C;
+const uint32_t REG_FCT      = 0x00030;
+const uint32_t REG_VET      = 0x00038;
+const uint32_t REG_PBA      = 0x01000;
+const uint32_t REG_ICR      = 0x000C0;
+const uint32_t REG_ITR      = 0x000C4;
+const uint32_t REG_ICS      = 0x000C8;
+const uint32_t REG_IMS      = 0x000D0;
+const uint32_t REG_IMC      = 0x000D8;
+const uint32_t REG_IAM      = 0x000E0;
+const uint32_t REG_RCTL     = 0x00100;
+const uint32_t REG_FCTTV    = 0x00170;
+const uint32_t REG_TIPG     = 0x00410;
+const uint32_t REG_AIFS     = 0x00458;
+const uint32_t REG_LEDCTL   = 0x00e00;
+const uint32_t REG_EICR     = 0x01580;
+const uint32_t REG_IVAR0    = 0x01700;
+const uint32_t REG_FCRTL    = 0x02160;
+const uint32_t REG_FCRTH    = 0x02168;
+const uint32_t REG_RDBAL    = 0x02800;
+const uint32_t REG_RDBAH    = 0x02804;
+const uint32_t REG_RDLEN    = 0x02808;
+const uint32_t REG_SRRCTL   = 0x0280C;
+const uint32_t REG_RDH      = 0x02810;
+const uint32_t REG_RDT      = 0x02818;
+const uint32_t REG_RDTR     = 0x02820;
+const uint32_t REG_RXDCTL   = 0x02828;
+const uint32_t REG_RADV     = 0x0282C;
+const uint32_t REG_TCTL     = 0x00400;
+const uint32_t REG_TDBAL    = 0x03800;
+const uint32_t REG_TDBAH    = 0x03804;
+const uint32_t REG_TDLEN    = 0x03808;
+const uint32_t REG_TDH      = 0x03810;
+const uint32_t REG_TXDCA_CTL = 0x03814;
+const uint32_t REG_TDT      = 0x03818;
+const uint32_t REG_TIDV     = 0x03820;
+const uint32_t REG_TXDCTL   = 0x03828;
+const uint32_t REG_TADV     = 0x0382C;
+const uint32_t REG_TDWBAL   = 0x03838;
+const uint32_t REG_TDWBAH   = 0x0383C;
+const uint32_t REG_CRCERRS  = 0x04000;
+const uint32_t REG_RXCSUM   = 0x05000;
+const uint32_t REG_RLPML    = 0x05004;
+const uint32_t REG_RFCTL    = 0x05008;
+const uint32_t REG_MTA      = 0x05200;
+const uint32_t REG_RAL      = 0x05400;
+const uint32_t REG_RAH      = 0x05404;
+const uint32_t REG_VFTA     = 0x05600;
+
+const uint32_t REG_WUC      = 0x05800;
+const uint32_t REG_MANC     = 0x05820;
+const uint32_t REG_SWSM     = 0x05B50;
+const uint32_t REG_FWSM     = 0x05B54;
+const uint32_t REG_SWFWSYNC = 0x05B5C;
+
+const uint8_t EEPROM_READ_OPCODE_SPI    = 0x03;
+const uint8_t EEPROM_RDSR_OPCODE_SPI    = 0x05;
+const uint8_t EEPROM_SIZE               = 64;
+const uint16_t EEPROM_CSUM              = 0xBABA;
+
+const uint8_t VLAN_FILTER_TABLE_SIZE    = 128;
+const uint8_t RCV_ADDRESS_TABLE_SIZE    = 24;
+const uint8_t MULTICAST_TABLE_SIZE      = 128;
+const uint32_t STATS_REGS_SIZE           = 0x228;
+
+
+// Registers in that are accessed in the PHY
+const uint8_t PHY_PSTATUS       = 0x1;
+const uint8_t PHY_PID           = 0x2;
+const uint8_t PHY_EPID          = 0x3;
+const uint8_t PHY_GSTATUS       = 10;
+const uint8_t PHY_EPSTATUS      = 15;
+const uint8_t PHY_AGC           = 18;
+
+// Receive Descriptor Status Flags
+const uint16_t RXDS_DYNINT      = 0x800;
+const uint16_t RXDS_UDPV        = 0x400;
+const uint16_t RXDS_CRCV        = 0x100;
+const uint16_t RXDS_PIF         = 0x080;
+const uint16_t RXDS_IPCS        = 0x040;
+const uint16_t RXDS_TCPCS       = 0x020;
+const uint16_t RXDS_UDPCS       = 0x010;
+const uint16_t RXDS_VP          = 0x008;
+const uint16_t RXDS_IXSM        = 0x004;
+const uint16_t RXDS_EOP         = 0x002;
+const uint16_t RXDS_DD          = 0x001;
+
+// Receive Descriptor Error Flags
+const uint8_t RXDE_RXE         = 0x80;
+const uint8_t RXDE_IPE         = 0x40;
+const uint8_t RXDE_TCPE        = 0x20;
+const uint8_t RXDE_SEQ         = 0x04;
+const uint8_t RXDE_SE          = 0x02;
+const uint8_t RXDE_CE          = 0x01;
+
+// Receive Descriptor Extended Error Flags
+const uint16_t RXDEE_HBO       = 0x008;
+const uint16_t RXDEE_CE        = 0x010;
+const uint16_t RXDEE_LE        = 0x020;
+const uint16_t RXDEE_PE        = 0x080;
+const uint16_t RXDEE_OSE       = 0x100;
+const uint16_t RXDEE_USE       = 0x200;
+const uint16_t RXDEE_TCPE      = 0x400;
+const uint16_t RXDEE_IPE       = 0x800;
+
+
+// Receive Descriptor Types
+const uint8_t RXDT_LEGACY      = 0x00;
+const uint8_t RXDT_ADV_ONEBUF  = 0x01;
+const uint8_t RXDT_ADV_SPLIT_A = 0x05;
+
+// Receive Descriptor Packet Types
+const uint16_t RXDP_IPV4       = 0x001;
+const uint16_t RXDP_IPV4E      = 0x002;
+const uint16_t RXDP_IPV6       = 0x004;
+const uint16_t RXDP_IPV6E      = 0x008;
+const uint16_t RXDP_TCP        = 0x010;
+const uint16_t RXDP_UDP        = 0x020;
+const uint16_t RXDP_SCTP       = 0x040;
+const uint16_t RXDP_NFS        = 0x080;
+
+// Interrupt types
+enum IntTypes
+{
+    IT_NONE    = 0x00000, //dummy value
+    IT_TXDW    = 0x00001,
+    IT_TXQE    = 0x00002,
+    IT_LSC     = 0x00004,
+    IT_RXSEQ   = 0x00008,
+    IT_RXDMT   = 0x00010,
+    IT_RXO     = 0x00040,
+    IT_RXT     = 0x00080,
+    IT_MADC    = 0x00200,
+    IT_RXCFG   = 0x00400,
+    IT_GPI0    = 0x02000,
+    IT_GPI1    = 0x04000,
+    IT_TXDLOW  = 0x08000,
+    IT_SRPD    = 0x10000,
+    IT_ACK     = 0x20000
+};
+
+// Receive Descriptor struct
+struct RxDesc {
+    union { 
+        struct {
+            Addr buf;
+            uint16_t len;
+            uint16_t csum;
+            uint8_t status;
+            uint8_t errors;
+            uint16_t vlan;
+        } legacy;
+        struct {
+            Addr pkt;
+            Addr hdr;
+        } adv_read;
+        struct {
+            uint16_t rss_type:4;
+            uint16_t pkt_type:12;
+            uint16_t __reserved1:5;
+            uint16_t header_len:10;
+            uint16_t sph:1;
+            union {
+                struct {
+                    uint16_t id;
+                    uint16_t csum;
+                };
+                uint32_t rss_hash;
+            };
+            uint32_t status:20;
+            uint32_t errors:12;
+            uint16_t pkt_len;
+            uint16_t vlan_tag;
+        } adv_wb ;
+    };
+};
+
+struct TxDesc {
+    uint64_t d1;
+    uint64_t d2;
+};
+
+namespace TxdOp {
+const uint8_t TXD_CNXT = 0x0;
+const uint8_t TXD_DATA = 0x1;
+const uint8_t TXD_ADVCNXT = 0x2;
+const uint8_t TXD_ADVDATA = 0x3;
+
+inline bool isLegacy(TxDesc *d) { return !bits(d->d2,29,29); }
+inline uint8_t getType(TxDesc *d) { return bits(d->d2, 23,20); }
+inline bool isType(TxDesc *d, uint8_t type) { return getType(d) == type; }
+inline bool isTypes(TxDesc *d, uint8_t t1, uint8_t t2) { return isType(d, t1) || isType(d, t2); }
+inline bool isAdvDesc(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_ADVDATA,TXD_ADVCNXT);  }
+inline bool isContext(TxDesc *d) { return !isLegacy(d) && isTypes(d,TXD_CNXT, TXD_ADVCNXT); }
+inline bool isData(TxDesc *d) { return !isLegacy(d) && isTypes(d, TXD_DATA, TXD_ADVDATA); }
+
+inline Addr getBuf(TxDesc *d) { assert(isLegacy(d) || isData(d)); return d->d1; }
+inline Addr getLen(TxDesc *d) { if (isLegacy(d)) return bits(d->d2,15,0); else return bits(d->d2, 19,0); }
+inline void setDd(TxDesc *d) { replaceBits(d->d2, 35, 32, ULL(1)); }
+
+inline bool ide(TxDesc *d)  { return bits(d->d2, 31,31) && (getType(d) == TXD_DATA || isLegacy(d)); }
+inline bool vle(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 30,30); }
+inline bool rs(TxDesc *d)   { return bits(d->d2, 27,27); }
+inline bool ic(TxDesc *d)   { assert(isLegacy(d) || isData(d)); return isLegacy(d) && bits(d->d2, 26,26); }
+inline bool tse(TxDesc *d)  {
+    if (isTypes(d, TXD_CNXT, TXD_DATA))
+        return bits(d->d2, 26,26); 
+    if (isType(d, TXD_ADVDATA))
+        return bits(d->d2, 31, 31);
+    return false;
+}
+
+inline bool ifcs(TxDesc *d) { assert(isLegacy(d) || isData(d)); return bits(d->d2, 25,25); }
+inline bool eop(TxDesc *d)  { assert(isLegacy(d) || isData(d)); return bits(d->d2, 24,24); }
+inline bool ip(TxDesc *d)   { assert(isContext(d)); return bits(d->d2, 25,25); }
+inline bool tcp(TxDesc *d)  { assert(isContext(d)); return bits(d->d2, 24,24); }
+
+inline uint8_t getCso(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 23,16); }
+inline uint8_t getCss(TxDesc *d) { assert(isLegacy(d)); return bits(d->d2, 47,40); }
+
+inline bool ixsm(TxDesc *d)  { return isData(d) && bits(d->d2, 40,40); }
+inline bool txsm(TxDesc *d)  { return isData(d) && bits(d->d2, 41,41); }
+
+inline int tucse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,63,48); }
+inline int tucso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,47,40); }
+inline int tucss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,39,32); }
+inline int ipcse(TxDesc *d) { assert(isContext(d)); return bits(d->d1,31,16); }
+inline int ipcso(TxDesc *d) { assert(isContext(d)); return bits(d->d1,15,8); }
+inline int ipcss(TxDesc *d) { assert(isContext(d)); return bits(d->d1,7,0); }
+inline int mss(TxDesc *d) { assert(isContext(d)); return bits(d->d2,63,48); }
+inline int hdrlen(TxDesc *d) {
+    assert(isContext(d)); 
+    if (!isAdvDesc(d))
+        return bits(d->d2,47,40);
+    return bits(d->d2, 47,40) + bits(d->d1, 8,0) + bits(d->d1, 15, 9); 
+}
+
+inline int getTsoLen(TxDesc *d) { assert(isType(d, TXD_ADVDATA)); return bits(d->d2, 63,46); }
+inline int utcmd(TxDesc *d) { assert(isContext(d)); return bits(d->d2,24,31); }
+} // namespace TxdOp
+
+
+#define ADD_FIELD32(NAME, OFFSET, BITS) \
+    inline uint32_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint32_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+#define ADD_FIELD64(NAME, OFFSET, BITS) \
+    inline uint64_t NAME() { return bits(_data, OFFSET+BITS-1, OFFSET); } \
+    inline void NAME(uint64_t d) { replaceBits(_data, OFFSET+BITS-1, OFFSET,d); }
+
+struct Regs : public Serializable {
+    template<class T>
+    struct Reg {
+        T _data;
+        T operator()() { return _data; }
+        const Reg<T> &operator=(T d) { _data = d; return *this;}
+        bool operator==(T d) { return d == _data; }
+        void operator()(T d) { _data = d; }
+        Reg() { _data = 0; }
+        void serialize(CheckpointOut &cp) const
+        {
+            SERIALIZE_SCALAR(_data);
+        }
+        void unserialize(CheckpointIn &cp)
+        {
+            UNSERIALIZE_SCALAR(_data);
+        }
+    };
+
+    struct CTRL : public Reg<uint32_t> { // 0x0000 CTRL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(fd,0,1);       // full duplex
+        ADD_FIELD32(bem,1,1);      // big endian mode
+        ADD_FIELD32(pcipr,2,1);    // PCI priority
+        ADD_FIELD32(lrst,3,1);     // link reset
+        ADD_FIELD32(tme,4,1);      // test mode enable
+        ADD_FIELD32(asde,5,1);     // Auto-speed detection
+        ADD_FIELD32(slu,6,1);      // Set link up
+        ADD_FIELD32(ilos,7,1);     // invert los-of-signal
+        ADD_FIELD32(speed,8,2);    // speed selection bits
+        ADD_FIELD32(be32,10,1);    // big endian mode 32
+        ADD_FIELD32(frcspd,11,1);  // force speed
+        ADD_FIELD32(frcdpx,12,1);  // force duplex
+        ADD_FIELD32(duden,13,1);   // dock/undock enable
+        ADD_FIELD32(dudpol,14,1);  // dock/undock polarity
+        ADD_FIELD32(fphyrst,15,1); // force phy reset
+        ADD_FIELD32(extlen,16,1);  // external link status enable
+        ADD_FIELD32(rsvd,17,1);    // reserved
+        ADD_FIELD32(sdp0d,18,1);   // software controlled pin data
+        ADD_FIELD32(sdp1d,19,1);   // software controlled pin data
+        ADD_FIELD32(sdp2d,20,1);   // software controlled pin data
+        ADD_FIELD32(sdp3d,21,1);   // software controlled pin data
+        ADD_FIELD32(sdp0i,22,1);   // software controlled pin dir
+        ADD_FIELD32(sdp1i,23,1);   // software controlled pin dir
+        ADD_FIELD32(sdp2i,24,1);   // software controlled pin dir
+        ADD_FIELD32(sdp3i,25,1);   // software controlled pin dir
+        ADD_FIELD32(rst,26,1);     // reset
+        ADD_FIELD32(rfce,27,1);    // receive flow control enable
+        ADD_FIELD32(tfce,28,1);    // transmit flow control enable
+        ADD_FIELD32(rte,29,1);     // routing tag enable
+        ADD_FIELD32(vme,30,1);     // vlan enable
+        ADD_FIELD32(phyrst,31,1);  // phy reset
+    };
+    CTRL ctrl;
+
+    struct STATUS : public Reg<uint32_t> { // 0x0008 STATUS Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(fd,0,1);       // full duplex
+        ADD_FIELD32(lu,1,1);       // link up
+        ADD_FIELD32(func,2,2);     // function id
+        ADD_FIELD32(txoff,4,1);    // transmission paused
+        ADD_FIELD32(tbimode,5,1);  // tbi mode
+        ADD_FIELD32(speed,6,2);    // link speed
+        ADD_FIELD32(asdv,8,2);     // auto speed detection value
+        ADD_FIELD32(mtxckok,10,1); // mtx clock running ok
+        ADD_FIELD32(pci66,11,1);   // In 66Mhz pci slot
+        ADD_FIELD32(bus64,12,1);   // in 64 bit slot
+        ADD_FIELD32(pcix,13,1);    // Pci mode
+        ADD_FIELD32(pcixspd,14,2); // pci x speed
+    };
+    STATUS sts;
+
+    struct EECD : public Reg<uint32_t> { // 0x0010 EECD Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(sk,0,1);       // clack input to the eeprom
+        ADD_FIELD32(cs,1,1);       // chip select to eeprom
+        ADD_FIELD32(din,2,1);      // data input to eeprom
+        ADD_FIELD32(dout,3,1);     // data output bit
+        ADD_FIELD32(fwe,4,2);      // flash write enable
+        ADD_FIELD32(ee_req,6,1);   // request eeprom access
+        ADD_FIELD32(ee_gnt,7,1);   // grant eeprom access
+        ADD_FIELD32(ee_pres,8,1);  // eeprom present
+        ADD_FIELD32(ee_size,9,1);  // eeprom size
+        ADD_FIELD32(ee_sz1,10,1);  // eeprom size
+        ADD_FIELD32(rsvd,11,2);    // reserved
+        ADD_FIELD32(ee_type,13,1); // type of eeprom
+    } ;
+    EECD eecd;
+
+    struct EERD : public Reg<uint32_t> { // 0x0014 EERD Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(start,0,1);  // start read
+        ADD_FIELD32(done,1,1);   // done read
+        ADD_FIELD32(addr,2,14);   // address
+        ADD_FIELD32(data,16,16); // data
+    };
+    EERD eerd;
+
+    struct CTRL_EXT : public Reg<uint32_t> { // 0x0018 CTRL_EXT Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(gpi_en,0,4);      // enable interrupts from gpio
+        ADD_FIELD32(phyint,5,1);      // reads the phy internal int status
+        ADD_FIELD32(sdp2_data,6,1);   // data from gpio sdp
+        ADD_FIELD32(spd3_data,7,1);   // data frmo gpio sdp
+        ADD_FIELD32(spd2_iodir,10,1); // direction of sdp2
+        ADD_FIELD32(spd3_iodir,11,1); // direction of sdp2
+        ADD_FIELD32(asdchk,12,1);     // initiate auto-speed-detection
+        ADD_FIELD32(eerst,13,1);      // reset the eeprom
+        ADD_FIELD32(spd_byps,15,1);   // bypass speed select
+        ADD_FIELD32(ro_dis,17,1);     // disable relaxed memory ordering
+        ADD_FIELD32(vreg,21,1);       // power down the voltage regulator
+        ADD_FIELD32(link_mode,22,2);  // interface to talk to the link
+        ADD_FIELD32(iame, 27,1);      // interrupt acknowledge auto-mask ??
+        ADD_FIELD32(drv_loaded, 28,1);// driver is loaded and incharge of device
+        ADD_FIELD32(timer_clr, 29,1); // clear interrupt timers after IMS clear ??
+    };
+    CTRL_EXT ctrl_ext;
+
+    struct MDIC : public Reg<uint32_t> { // 0x0020 MDIC Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(data,0,16);   // data
+        ADD_FIELD32(regadd,16,5); // register address
+        ADD_FIELD32(phyadd,21,5); // phy addresses
+        ADD_FIELD32(op,26,2);     // opcode
+        ADD_FIELD32(r,28,1);      // ready
+        ADD_FIELD32(i,29,1);      // interrupt
+        ADD_FIELD32(e,30,1);      // error
+    };
+    MDIC mdic;
+
+    struct ICR : public Reg<uint32_t> { // 0x00C0 ICR Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(txdw,0,1)   // tx descr witten back
+        ADD_FIELD32(txqe,1,1)   // tx queue empty
+        ADD_FIELD32(lsc,2,1)    // link status change
+        ADD_FIELD32(rxseq,3,1)  // rcv sequence error
+        ADD_FIELD32(rxdmt0,4,1) // rcv descriptor min thresh
+        ADD_FIELD32(rsvd1,5,1)  // reserved
+        ADD_FIELD32(rxo,6,1)    // receive overrunn
+        ADD_FIELD32(rxt0,7,1)   // receiver timer interrupt
+        ADD_FIELD32(mdac,9,1)   // mdi/o access complete
+        ADD_FIELD32(rxcfg,10,1)  // recv /c/ ordered sets
+        ADD_FIELD32(phyint,12,1) // phy interrupt
+        ADD_FIELD32(gpi1,13,1)   // gpi int 1
+        ADD_FIELD32(gpi2,14,1)   // gpi int 2
+        ADD_FIELD32(txdlow,15,1) // transmit desc low thresh
+        ADD_FIELD32(srpd,16,1)   // small receive packet detected
+        ADD_FIELD32(ack,17,1);    // receive ack frame
+        ADD_FIELD32(int_assert, 31,1); // interrupt caused a system interrupt
+    };
+    ICR icr;
+
+    uint32_t imr; // register that contains the current interrupt mask
+
+    struct ITR : public Reg<uint32_t> { // 0x00C4 ITR Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(interval, 0,16); // minimum inter-interrutp inteval
+                                     // specified in 256ns interrupts
+    };
+    ITR itr;
+
+    // When CTRL_EXT.IAME and the ICR.INT_ASSERT is 1 an ICR read or write
+    // causes the IAM register contents to be written into the IMC
+    // automatically clearing all interrupts that have a bit in the IAM set
+    uint32_t iam;
+
+    struct RCTL : public Reg<uint32_t> { // 0x0100 RCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rst,0,1);   // Reset
+        ADD_FIELD32(en,1,1);    // Enable
+        ADD_FIELD32(sbp,2,1);   // Store bad packets
+        ADD_FIELD32(upe,3,1);   // Unicast Promiscuous enabled
+        ADD_FIELD32(mpe,4,1);   // Multicast promiscuous enabled
+        ADD_FIELD32(lpe,5,1);   // long packet reception enabled
+        ADD_FIELD32(lbm,6,2);   //
+        ADD_FIELD32(rdmts,8,2); //
+        ADD_FIELD32(mo,12,2);    //
+        ADD_FIELD32(mdr,14,1);   //
+        ADD_FIELD32(bam,15,1);   //
+        ADD_FIELD32(bsize,16,2); //
+        ADD_FIELD32(vfe,18,1);   //
+        ADD_FIELD32(cfien,19,1); //
+        ADD_FIELD32(cfi,20,1);   //
+        ADD_FIELD32(dpf,22,1);   // discard pause frames
+        ADD_FIELD32(pmcf,23,1);  // pass mac control  frames
+        ADD_FIELD32(bsex,25,1);  // buffer size extension
+        ADD_FIELD32(secrc,26,1); // strip ethernet crc from incoming packet
+        unsigned descSize()
+        {
+            switch(bsize()) {
+                case 0: return bsex() == 0 ? 2048 : 0;
+                case 1: return bsex() == 0 ? 1024 : 16384;
+                case 2: return bsex() == 0 ? 512 : 8192;
+                case 3: return bsex() == 0 ? 256 : 4096;
+                default:
+                        return 0;
+            }
+        }
+    };
+    RCTL rctl;
+
+    struct FCTTV : public Reg<uint32_t> { // 0x0170 FCTTV
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(ttv,0,16);    // Transmit Timer Value
+    };
+    FCTTV fcttv;
+
+    struct TCTL : public Reg<uint32_t> { // 0x0400 TCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rst,0,1);    // Reset
+        ADD_FIELD32(en,1,1);     // Enable
+        ADD_FIELD32(bce,2,1);    // busy check enable
+        ADD_FIELD32(psp,3,1);    // pad short packets
+        ADD_FIELD32(ct,4,8);     // collision threshold
+        ADD_FIELD32(cold,12,10); // collision distance
+        ADD_FIELD32(swxoff,22,1); // software xoff transmission
+        ADD_FIELD32(pbe,23,1);    // packet burst enable
+        ADD_FIELD32(rtlc,24,1);   // retransmit late collisions
+        ADD_FIELD32(nrtu,25,1);   // on underrun no TX
+        ADD_FIELD32(mulr,26,1);   // multiple request
+    };
+    TCTL tctl;
+
+    struct PBA : public Reg<uint32_t> { // 0x1000 PBA Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rxa,0,16);
+        ADD_FIELD32(txa,16,16);
+    };
+    PBA pba;
+
+    struct FCRTL : public Reg<uint32_t> { // 0x2160 FCRTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rtl,3,28); // make this bigger than the spec so we can have
+                               // a larger buffer
+        ADD_FIELD32(xone, 31,1);
+    };
+    FCRTL fcrtl;
+
+    struct FCRTH : public Reg<uint32_t> { // 0x2168 FCRTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rth,3,13); // make this bigger than the spec so we can have
+                               //a larger buffer
+        ADD_FIELD32(xfce, 31,1);
+    };
+    FCRTH fcrth;
+
+    struct RDBA : public Reg<uint64_t> { // 0x2800 RDBA Register
+        using Reg<uint64_t>::operator=;
+        ADD_FIELD64(rdbal,0,32); // base address of rx descriptor ring
+        ADD_FIELD64(rdbah,32,32); // base address of rx descriptor ring
+    };
+    RDBA rdba;
+
+    struct RDLEN : public Reg<uint32_t> { // 0x2808 RDLEN Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
+    };
+    RDLEN rdlen;
+
+    struct SRRCTL : public Reg<uint32_t> { // 0x280C SRRCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(pktlen, 0, 8);
+        ADD_FIELD32(hdrlen, 8, 8); // guess based on header, not documented
+        ADD_FIELD32(desctype, 25,3); // type of descriptor 000 legacy, 001 adv,
+                                     //101 hdr split
+        unsigned bufLen() { return pktlen() << 10; }
+        unsigned hdrLen() { return hdrlen() << 6; }
+    };
+    SRRCTL srrctl;
+
+    struct RDH : public Reg<uint32_t> { // 0x2810 RDH Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rdh,0,16); // head of the descriptor ring
+    };
+    RDH rdh;
+
+    struct RDT : public Reg<uint32_t> { // 0x2818 RDT Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(rdt,0,16); // tail of the descriptor ring
+    };
+    RDT rdt;
+
+    struct RDTR : public Reg<uint32_t> { // 0x2820 RDTR Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(delay,0,16); // receive delay timer
+        ADD_FIELD32(fpd, 31,1);   // flush partial descriptor block ??
+    };
+    RDTR rdtr;
+
+    struct RXDCTL : public Reg<uint32_t> { // 0x2828 RXDCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(pthresh,0,6);   // prefetch threshold, less that this
+                                    // consider prefetch
+        ADD_FIELD32(hthresh,8,6);   // number of descriptors in host mem to
+                                    // consider prefetch
+        ADD_FIELD32(wthresh,16,6);  // writeback threshold
+        ADD_FIELD32(gran,24,1);     // granularity 0 = desc, 1 = cacheline
+    };
+    RXDCTL rxdctl;
+
+    struct RADV : public Reg<uint32_t> { // 0x282C RADV Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(idv,0,16); // absolute interrupt delay
+    };
+    RADV radv;
+
+    struct RSRPD : public Reg<uint32_t> { // 0x2C00 RSRPD Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(idv,0,12); // size to interrutp on small packets
+    };
+    RSRPD rsrpd;
+
+    struct TDBA : public Reg<uint64_t> { // 0x3800 TDBAL Register
+        using Reg<uint64_t>::operator=;
+        ADD_FIELD64(tdbal,0,32); // base address of transmit descriptor ring
+        ADD_FIELD64(tdbah,32,32); // base address of transmit descriptor ring
+    };
+    TDBA tdba;
+
+    struct TDLEN : public Reg<uint32_t> { // 0x3808 TDLEN Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(len,7,13); // number of bytes in the descriptor buffer
+    };
+    TDLEN tdlen;
+
+    struct TDH : public Reg<uint32_t> { // 0x3810 TDH Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(tdh,0,16); // head of the descriptor ring
+    };
+    TDH tdh;
+
+    struct TXDCA_CTL : public Reg<uint32_t> { // 0x3814 TXDCA_CTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(cpu_mask, 0, 5);
+        ADD_FIELD32(enabled, 5,1);
+        ADD_FIELD32(relax_ordering, 6, 1);
+    };
+    TXDCA_CTL txdca_ctl;
+
+    struct TDT : public Reg<uint32_t> { // 0x3818 TDT Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(tdt,0,16); // tail of the descriptor ring
+    };
+    TDT tdt;
+
+    struct TIDV : public Reg<uint32_t> { // 0x3820 TIDV Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(idv,0,16); // interrupt delay
+    };
+    TIDV tidv;
+
+    struct TXDCTL : public Reg<uint32_t> { // 0x3828 TXDCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(pthresh, 0,6);  // if number of descriptors control has is
+                                    // below this number, a prefetch is considered
+        ADD_FIELD32(hthresh,8,8);   // number of valid descriptors is host memory
+                                    // before a prefetch is considered
+        ADD_FIELD32(wthresh,16,6);  // number of descriptors to keep until
+                                    // writeback is considered
+        ADD_FIELD32(gran, 24,1);    // granulatiry of above values (0 = cacheline,
+                                    // 1 == desscriptor)
+        ADD_FIELD32(lwthresh,25,7); // xmit descriptor low thresh, interrupt
+                                    // below this level
+    };
+    TXDCTL txdctl;
+
+    struct TADV : public Reg<uint32_t> { // 0x382C TADV Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(idv,0,16); // absolute interrupt delay
+    };
+    TADV tadv;
+/*
+    struct TDWBA : public Reg<uint64_t> { // 0x3838 TDWBA Register
+        using Reg<uint64_t>::operator=;
+        ADD_FIELD64(en,0,1); // enable  transmit description ring address writeback
+        ADD_FIELD64(tdwbal,2,32); // base address of transmit descriptor ring address writeback
+        ADD_FIELD64(tdwbah,32,32); // base address of transmit descriptor ring
+    };
+    TDWBA tdwba;*/
+    uint64_t tdwba;
+
+    struct RXCSUM : public Reg<uint32_t> { // 0x5000 RXCSUM Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(pcss,0,8);
+        ADD_FIELD32(ipofld,8,1);
+        ADD_FIELD32(tuofld,9,1);
+        ADD_FIELD32(pcsd, 13,1);
+    };
+    RXCSUM rxcsum;
+
+    uint32_t rlpml; // 0x5004 RLPML probably maximum accepted packet size
+
+    struct RFCTL : public Reg<uint32_t> { // 0x5008 RFCTL Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(iscsi_dis,0,1);
+        ADD_FIELD32(iscsi_dwc,1,5);
+        ADD_FIELD32(nfsw_dis,6,1);
+        ADD_FIELD32(nfsr_dis,7,1);
+        ADD_FIELD32(nfs_ver,8,2);
+        ADD_FIELD32(ipv6_dis,10,1);
+        ADD_FIELD32(ipv6xsum_dis,11,1);
+        ADD_FIELD32(ackdis,13,1);
+        ADD_FIELD32(ipfrsp_dis,14,1);
+        ADD_FIELD32(exsten,15,1);
+    };
+    RFCTL rfctl;
+
+    struct MANC : public Reg<uint32_t> { // 0x5820 MANC Register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(smbus,0,1);    // SMBus enabled #####
+        ADD_FIELD32(asf,1,1);      // ASF enabled #####
+        ADD_FIELD32(ronforce,2,1); // reset of force
+        ADD_FIELD32(rsvd,3,5);     // reserved
+        ADD_FIELD32(rmcp1,8,1);    // rcmp1 filtering
+        ADD_FIELD32(rmcp2,9,1);    // rcmp2 filtering
+        ADD_FIELD32(ipv4,10,1);     // enable ipv4
+        ADD_FIELD32(ipv6,11,1);     // enable ipv6
+        ADD_FIELD32(snap,12,1);     // accept snap
+        ADD_FIELD32(arp,13,1);      // filter arp #####
+        ADD_FIELD32(neighbor,14,1); // neighbor discovery
+        ADD_FIELD32(arp_resp,15,1); // arp response
+        ADD_FIELD32(tcorst,16,1);   // tco reset happened
+        ADD_FIELD32(rcvtco,17,1);   // receive tco enabled ######
+        ADD_FIELD32(blkphyrst,18,1);// block phy resets ########
+        ADD_FIELD32(rcvall,19,1);   // receive all
+        ADD_FIELD32(macaddrfltr,20,1); // mac address filtering ######
+        ADD_FIELD32(mng2host,21,1); // mng2 host packets #######
+        ADD_FIELD32(ipaddrfltr,22,1); // ip address filtering
+        ADD_FIELD32(xsumfilter,23,1); // checksum filtering
+        ADD_FIELD32(brfilter,24,1); // broadcast filtering
+        ADD_FIELD32(smbreq,25,1);   // smb request
+        ADD_FIELD32(smbgnt,26,1);   // smb grant
+        ADD_FIELD32(smbclkin,27,1); // smbclkin
+        ADD_FIELD32(smbdatain,28,1); // smbdatain
+        ADD_FIELD32(smbdataout,29,1); // smb data out
+        ADD_FIELD32(smbclkout,30,1); // smb clock out
+    };
+    MANC manc;
+
+    struct SWSM : public Reg<uint32_t> { // 0x5B50 SWSM register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(smbi,0,1); // Semaphone bit
+        ADD_FIELD32(swesmbi, 1,1); // Software eeporm semaphore
+        ADD_FIELD32(wmng, 2,1); // Wake MNG clock
+        ADD_FIELD32(reserved, 3, 29);
+    };
+    SWSM swsm;
+
+    struct FWSM : public Reg<uint32_t> { // 0x5B54 FWSM register
+        using Reg<uint32_t>::operator=;
+        ADD_FIELD32(eep_fw_semaphore,0,1); 
+        ADD_FIELD32(fw_mode, 1,3); 
+        ADD_FIELD32(ide, 4,1); 
+        ADD_FIELD32(sol, 5,1);
+        ADD_FIELD32(eep_roload, 6,1);
+        ADD_FIELD32(reserved, 7,8);
+        ADD_FIELD32(fw_val_bit, 15, 1);
+        ADD_FIELD32(reset_cnt, 16, 3);
+        ADD_FIELD32(ext_err_ind, 19, 6);
+        ADD_FIELD32(reserved2, 25, 7);
+    };
+    FWSM fwsm;
+
+    uint32_t sw_fw_sync;
+
+    void serialize(CheckpointOut &cp) const override
+    {
+        paramOut(cp, "ctrl", ctrl._data);
+        paramOut(cp, "sts", sts._data);
+        paramOut(cp, "eecd", eecd._data);
+        paramOut(cp, "eerd", eerd._data);
+        paramOut(cp, "ctrl_ext", ctrl_ext._data);
+        paramOut(cp, "mdic", mdic._data);
+        paramOut(cp, "icr", icr._data);
+        SERIALIZE_SCALAR(imr);
+        paramOut(cp, "itr", itr._data);
+        SERIALIZE_SCALAR(iam);
+        paramOut(cp, "rctl", rctl._data);
+        paramOut(cp, "fcttv", fcttv._data);
+        paramOut(cp, "tctl", tctl._data);
+        paramOut(cp, "pba", pba._data);
+        paramOut(cp, "fcrtl", fcrtl._data);
+        paramOut(cp, "fcrth", fcrth._data);
+        paramOut(cp, "rdba", rdba._data);
+        paramOut(cp, "rdlen", rdlen._data);
+        paramOut(cp, "srrctl", srrctl._data);
+        paramOut(cp, "rdh", rdh._data);
+        paramOut(cp, "rdt", rdt._data);
+        paramOut(cp, "rdtr", rdtr._data);
+        paramOut(cp, "rxdctl", rxdctl._data);
+        paramOut(cp, "radv", radv._data);
+        paramOut(cp, "rsrpd", rsrpd._data);
+        paramOut(cp, "tdba", tdba._data);
+        paramOut(cp, "tdlen", tdlen._data);
+        paramOut(cp, "tdh", tdh._data);
+        paramOut(cp, "txdca_ctl", txdca_ctl._data);
+        paramOut(cp, "tdt", tdt._data);
+        paramOut(cp, "tidv", tidv._data);
+        paramOut(cp, "txdctl", txdctl._data);
+        paramOut(cp, "tadv", tadv._data);
+        //paramOut(cp, "tdwba", tdwba._data);
+        SERIALIZE_SCALAR(tdwba);
+        paramOut(cp, "rxcsum", rxcsum._data);
+        SERIALIZE_SCALAR(rlpml);
+        paramOut(cp, "rfctl", rfctl._data);
+        paramOut(cp, "manc", manc._data);
+        paramOut(cp, "swsm", swsm._data);
+        paramOut(cp, "fwsm", fwsm._data);
+        SERIALIZE_SCALAR(sw_fw_sync);
+    }
+
+    void unserialize(CheckpointIn &cp) override
+    {
+        paramIn(cp, "ctrl", ctrl._data);
+        paramIn(cp, "sts", sts._data);
+        paramIn(cp, "eecd", eecd._data);
+        paramIn(cp, "eerd", eerd._data);
+        paramIn(cp, "ctrl_ext", ctrl_ext._data);
+        paramIn(cp, "mdic", mdic._data);
+        paramIn(cp, "icr", icr._data);
+        UNSERIALIZE_SCALAR(imr);
+        paramIn(cp, "itr", itr._data);
+        UNSERIALIZE_SCALAR(iam);
+        paramIn(cp, "rctl", rctl._data);
+        paramIn(cp, "fcttv", fcttv._data);
+        paramIn(cp, "tctl", tctl._data);
+        paramIn(cp, "pba", pba._data);
+        paramIn(cp, "fcrtl", fcrtl._data);
+        paramIn(cp, "fcrth", fcrth._data);
+        paramIn(cp, "rdba", rdba._data);
+        paramIn(cp, "rdlen", rdlen._data);
+        paramIn(cp, "srrctl", srrctl._data);
+        paramIn(cp, "rdh", rdh._data);
+        paramIn(cp, "rdt", rdt._data);
+        paramIn(cp, "rdtr", rdtr._data);
+        paramIn(cp, "rxdctl", rxdctl._data);
+        paramIn(cp, "radv", radv._data);
+        paramIn(cp, "rsrpd", rsrpd._data);
+        paramIn(cp, "tdba", tdba._data);
+        paramIn(cp, "tdlen", tdlen._data);
+        paramIn(cp, "tdh", tdh._data);
+        paramIn(cp, "txdca_ctl", txdca_ctl._data);
+        paramIn(cp, "tdt", tdt._data);
+        paramIn(cp, "tidv", tidv._data);
+        paramIn(cp, "txdctl", txdctl._data);
+        paramIn(cp, "tadv", tadv._data);
+        UNSERIALIZE_SCALAR(tdwba);
+        //paramIn(cp, "tdwba", tdwba._data);
+        paramIn(cp, "rxcsum", rxcsum._data);
+        UNSERIALIZE_SCALAR(rlpml);
+        paramIn(cp, "rfctl", rfctl._data);
+        paramIn(cp, "manc", manc._data);
+        paramIn(cp, "swsm", swsm._data);
+        paramIn(cp, "fwsm", fwsm._data);
+        UNSERIALIZE_SCALAR(sw_fw_sync);
+    }
+};
+} // namespace iGbReg
diff --git a/src/dev/net/multi_etherlink.cc b/src/dev/net/multi_etherlink.cc
new file mode 100644 (file)
index 0000000..cf4300d
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * Device module for a full duplex ethernet link for multi gem5 simulations.
+ */
+
+#include "dev/net/multi_etherlink.hh"
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <cmath>
+#include <deque>
+#include <string>
+#include <vector>
+
+#include "base/random.hh"
+#include "base/trace.hh"
+#include "debug/EthernetData.hh"
+#include "debug/MultiEthernet.hh"
+#include "debug/MultiEthernetPkt.hh"
+#include "dev/net/etherdump.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherlink.hh"
+#include "dev/net/etherobject.hh"
+#include "dev/net/etherpkt.hh"
+#include "dev/net/multi_iface.hh"
+#include "dev/net/tcp_iface.hh"
+#include "params/EtherLink.hh"
+#include "sim/core.hh"
+#include "sim/serialize.hh"
+#include "sim/system.hh"
+
+using namespace std;
+
+MultiEtherLink::MultiEtherLink(const Params *p)
+    : EtherObject(p)
+{
+    DPRINTF(MultiEthernet,"MultiEtherLink::MultiEtherLink() "
+            "link delay:%llu\n", p->delay);
+
+    txLink = new TxLink(name() + ".link0", this, p->speed, p->delay_var,
+                        p->dump);
+    rxLink = new RxLink(name() + ".link1", this, p->delay, p->dump);
+
+    // create the multi (TCP) interface to talk to the peer gem5 processes.
+    multiIface = new TCPIface(p->server_name, p->server_port, p->multi_rank,
+                              p->sync_start, p->sync_repeat, this);
+
+    localIface = new LocalIface(name() + ".int0", txLink, rxLink, multiIface);
+}
+
+MultiEtherLink::~MultiEtherLink()
+{
+    delete txLink;
+    delete rxLink;
+    delete localIface;
+    delete multiIface;
+}
+
+EtherInt*
+MultiEtherLink::getEthPort(const std::string &if_name, int idx)
+{
+    if (if_name != "int0") {
+        return nullptr;
+    } else {
+        panic_if(localIface->getPeer(), "interface already connected to");
+    }
+    return localIface;
+}
+
+void MultiEtherLink::memWriteback()
+{
+    DPRINTF(MultiEthernet,"MultiEtherLink::memWriteback() called\n");
+    multiIface->drainDone();
+}
+
+void
+MultiEtherLink::serialize(CheckpointOut &cp) const
+{
+    multiIface->serialize("multiIface", cp);
+    txLink->serialize("txLink", cp);
+    rxLink->serialize("rxLink", cp);
+}
+
+void
+MultiEtherLink::unserialize(CheckpointIn &cp)
+{
+    multiIface->unserialize("multiIface", cp);
+    txLink->unserialize("txLink", cp);
+    rxLink->unserialize("rxLink", cp);
+}
+
+void
+MultiEtherLink::init()
+{
+    DPRINTF(MultiEthernet,"MultiEtherLink::init() called\n");
+    multiIface->initRandom();
+}
+
+void
+MultiEtherLink::startup()
+{
+    DPRINTF(MultiEthernet,"MultiEtherLink::startup() called\n");
+    multiIface->startPeriodicSync();
+}
+
+void
+MultiEtherLink::RxLink::setMultiInt(MultiIface *m)
+{
+    assert(!multiIface);
+    multiIface = m;
+    // Spawn a new receiver thread that will process messages
+    // coming in from peer gem5 processes.
+    // The receive thread will also schedule a (receive) doneEvent
+    // for each incoming data packet.
+    multiIface->spawnRecvThread(&doneEvent, linkDelay);
+}
+
+void
+MultiEtherLink::RxLink::rxDone()
+{
+    assert(!busy());
+
+    // retrieve the packet that triggered the receive done event
+    packet = multiIface->packetIn();
+
+    if (dump)
+        dump->dump(packet);
+
+    DPRINTF(MultiEthernetPkt, "MultiEtherLink::MultiLink::rxDone() "
+            "packet received: len=%d\n", packet->length);
+    DDUMP(EthernetData, packet->data, packet->length);
+
+    localIface->sendPacket(packet);
+
+    packet = nullptr;
+}
+
+void
+MultiEtherLink::TxLink::txDone()
+{
+    if (dump)
+        dump->dump(packet);
+
+    packet = nullptr;
+    assert(!busy());
+
+    localIface->sendDone();
+}
+
+bool
+MultiEtherLink::TxLink::transmit(EthPacketPtr pkt)
+{
+    if (busy()) {
+        DPRINTF(MultiEthernet, "packet not sent, link busy\n");
+        return false;
+    }
+
+    packet = pkt;
+    Tick delay = (Tick)ceil(((double)pkt->length * ticksPerByte) + 1.0);
+    if (delayVar != 0)
+        delay += random_mt.random<Tick>(0, delayVar);
+
+    // send the packet to the peers
+    assert(multiIface);
+    multiIface->packetOut(pkt, delay);
+
+    // schedule the send done event
+    parent->schedule(doneEvent, curTick() + delay);
+
+    return true;
+}
+
+void
+MultiEtherLink::Link::serialize(const string &base, CheckpointOut &cp) const
+{
+    bool packet_exists = (packet != nullptr);
+    paramOut(cp, base + ".packet_exists", packet_exists);
+    if (packet_exists)
+        packet->serialize(base + ".packet", cp);
+
+    bool event_scheduled = event->scheduled();
+    paramOut(cp, base + ".event_scheduled", event_scheduled);
+    if (event_scheduled) {
+        Tick event_time = event->when();
+        paramOut(cp, base + ".event_time", event_time);
+    }
+}
+
+void
+MultiEtherLink::Link::unserialize(const string &base, CheckpointIn &cp)
+{
+    bool packet_exists;
+    paramIn(cp, base + ".packet_exists", packet_exists);
+    if (packet_exists) {
+        packet = make_shared<EthPacketData>(16384);
+        packet->unserialize(base + ".packet", cp);
+    }
+
+    bool event_scheduled;
+    paramIn(cp, base + ".event_scheduled", event_scheduled);
+    if (event_scheduled) {
+        Tick event_time;
+        paramIn(cp, base + ".event_time", event_time);
+        parent->schedule(*event, event_time);
+    }
+}
+
+MultiEtherLink::LocalIface::LocalIface(const std::string &name,
+                                       TxLink *tx,
+                                       RxLink *rx,
+                                       MultiIface *m) :
+    EtherInt(name), txLink(tx)
+{
+    tx->setLocalInt(this);
+    rx->setLocalInt(this);
+    tx->setMultiInt(m);
+    rx->setMultiInt(m);
+}
+
+MultiEtherLink *
+MultiEtherLinkParams::create()
+{
+    return new MultiEtherLink(this);
+}
+
+
diff --git a/src/dev/net/multi_etherlink.hh b/src/dev/net/multi_etherlink.hh
new file mode 100644 (file)
index 0000000..0a3e39b
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * Device module for a full duplex ethernet link for multi gem5 simulations.
+ *
+ * See comments in dev/multi_iface.hh for a generic description of multi
+ * gem5 simulations.
+ *
+ * This class is meant to be a drop in replacement for the EtherLink class for
+ * multi gem5 runs.
+ *
+ */
+#ifndef __DEV_NET_MULTIETHERLINK_HH__
+#define __DEV_NET_MULTIETHERLINK_HH__
+
+#include <iostream>
+
+#include "dev/net/etherlink.hh"
+#include "params/MultiEtherLink.hh"
+
+class MultiIface;
+class EthPacketData;
+
+/**
+ * Model for a fixed bandwidth full duplex ethernet link.
+ */
+class MultiEtherLink : public EtherObject
+{
+  protected:
+    class LocalIface;
+
+    /**
+     * Model base class for a single uni-directional link.
+     *
+     * The link will encapsulate and transfer Ethernet packets to/from
+     * the message server.
+     */
+    class Link
+    {
+      protected:
+        std::string objName;
+        MultiEtherLink *parent;
+        LocalIface *localIface;
+        EtherDump *dump;
+        MultiIface *multiIface;
+        Event *event;
+        EthPacketPtr packet;
+
+      public:
+        Link(const std::string &name, MultiEtherLink *p,
+             EtherDump *d, Event *e) :
+            objName(name), parent(p), localIface(nullptr), dump(d),
+            multiIface(nullptr), event(e) {}
+
+        ~Link() {}
+
+        const std::string name() const { return objName; }
+        bool busy() const { return (bool)packet; }
+        void setLocalInt(LocalIface *i) { assert(!localIface); localIface=i; }
+
+        void serialize(const std::string &base, CheckpointOut &cp) const;
+        void unserialize(const std::string &base, CheckpointIn &cp);
+    };
+
+    /**
+     * Model for a send link.
+     */
+    class TxLink : public Link
+    {
+      protected:
+        /**
+         * Per byte send delay
+         */
+        double ticksPerByte;
+        /**
+         * Random component of the send delay
+         */
+        Tick delayVar;
+
+        /**
+         * Send done callback. Called from doneEvent.
+         */
+        void txDone();
+        typedef EventWrapper<TxLink, &TxLink::txDone> DoneEvent;
+        friend void DoneEvent::process();
+        DoneEvent doneEvent;
+
+      public:
+        TxLink(const std::string &name, MultiEtherLink *p,
+               double invBW, Tick delay_var, EtherDump *d) :
+            Link(name, p, d, &doneEvent), ticksPerByte(invBW),
+            delayVar(delay_var), doneEvent(this) {}
+        ~TxLink() {}
+
+        /**
+         * Register the multi interface to be used to talk to the
+         * peer gem5 processes.
+         */
+        void setMultiInt(MultiIface *m) { assert(!multiIface); multiIface=m; }
+
+        /**
+         * Initiate sending of a packet via this link.
+         *
+         * @param packet Ethernet packet to send
+         */
+        bool transmit(EthPacketPtr packet);
+    };
+
+    /**
+     * Model for a receive link.
+     */
+    class RxLink : public Link
+    {
+      protected:
+
+        /**
+         * Transmission delay for the simulated Ethernet link.
+         */
+        Tick linkDelay;
+
+        /**
+         * Receive done callback method. Called from doneEvent.
+         */
+        void rxDone() ;
+        typedef EventWrapper<RxLink, &RxLink::rxDone> DoneEvent;
+        friend void DoneEvent::process();
+        DoneEvent doneEvent;
+
+      public:
+
+        RxLink(const std::string &name, MultiEtherLink *p,
+               Tick delay, EtherDump *d) :
+            Link(name, p, d, &doneEvent),
+            linkDelay(delay), doneEvent(this) {}
+        ~RxLink() {}
+
+        /**
+         * Register our multi interface to talk to the peer gem5 processes.
+         */
+        void setMultiInt(MultiIface *m);
+    };
+
+    /**
+     * Interface to the local simulated system
+     */
+    class LocalIface : public EtherInt
+    {
+      private:
+        TxLink *txLink;
+
+      public:
+        LocalIface(const std::string &name, TxLink *tx, RxLink *rx,
+                   MultiIface *m);
+
+        bool recvPacket(EthPacketPtr pkt) { return txLink->transmit(pkt); }
+        void sendDone() { peer->sendDone(); }
+        bool isBusy() { return txLink->busy(); }
+    };
+
+
+  protected:
+    /**
+     * Interface to talk to the peer gem5 processes.
+     */
+    MultiIface *multiIface;
+    /**
+     * Send link
+     */
+    TxLink *txLink;
+    /**
+     * Receive link
+     */
+    RxLink *rxLink;
+    LocalIface *localIface;
+
+  public:
+    typedef MultiEtherLinkParams Params;
+    MultiEtherLink(const Params *p);
+    ~MultiEtherLink();
+
+    const Params *
+    params() const
+    {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    virtual EtherInt *getEthPort(const std::string &if_name,
+                                 int idx) override;
+
+    void memWriteback() override;
+    void init() override;
+    void startup() override;
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+};
+
+#endif // __DEV_NET_MULTIETHERLINK_HH__
diff --git a/src/dev/net/multi_iface.cc b/src/dev/net/multi_iface.cc
new file mode 100644 (file)
index 0000000..15f69f2
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * The interface class for multi gem5 simulations.
+ */
+
+#include "dev/net/multi_iface.hh"
+
+#include <queue>
+#include <thread>
+
+#include "base/random.hh"
+#include "base/trace.hh"
+#include "debug/MultiEthernet.hh"
+#include "debug/MultiEthernetPkt.hh"
+#include "dev/net/etherpkt.hh"
+#include "sim/sim_exit.hh"
+#include "sim/sim_object.hh"
+
+
+MultiIface::Sync *MultiIface::sync = nullptr;
+MultiIface::SyncEvent *MultiIface::syncEvent = nullptr;
+unsigned MultiIface::recvThreadsNum = 0;
+MultiIface *MultiIface::master = nullptr;
+
+bool
+MultiIface::Sync::run(SyncTrigger t, Tick sync_tick)
+{
+    std::unique_lock<std::mutex> sync_lock(lock);
+
+    trigger = t;
+    if (trigger != SyncTrigger::periodic) {
+        DPRINTF(MultiEthernet,"MultiIface::Sync::run() trigger:%d\n",
+                (unsigned)trigger);
+    }
+
+    switch (state) {
+      case SyncState::asyncCkpt:
+        switch (trigger) {
+          case SyncTrigger::ckpt:
+            assert(MultiIface::syncEvent->interrupted == false);
+            state = SyncState::busy;
+            break;
+          case SyncTrigger::periodic:
+            if (waitNum == 0) {
+                // So all recv threads got an async checkpoint request already
+                // and a simExit is scheduled at the end of the current tick
+                // (i.e. it is a periodic sync scheduled at the same tick as
+                // the simExit).
+                state = SyncState::idle;
+                DPRINTF(MultiEthernet,"MultiIface::Sync::run() interrupted "
+                "due to async ckpt scheduled\n");
+                return false;
+            } else {
+                // we still need to wait for some receiver thread to get the
+                // aysnc ckpt request. We are going to proceed as 'interrupted'
+                // periodic sync.
+                state = SyncState::interrupted;
+                DPRINTF(MultiEthernet,"MultiIface::Sync::run() interrupted "
+                "due to ckpt request is coming in\n");
+            }
+            break;
+          case SyncTrigger::atomic:
+            assert(trigger != SyncTrigger::atomic);
+        }
+        break;
+      case SyncState::idle:
+        state = SyncState::busy;
+        break;
+        // Only one sync can be active at any time
+      case SyncState::interrupted:
+      case SyncState::busy:
+        assert(state != SyncState::interrupted);
+        assert(state != SyncState::busy);
+        break;
+    }
+    // Kick-off the sync unless we are in the middle of an interrupted
+    // periodic sync
+    if (state != SyncState::interrupted) {
+        assert(waitNum == 0);
+        waitNum = MultiIface::recvThreadsNum;
+        // initiate the global synchronisation
+        assert(MultiIface::master != nullptr);
+        MultiIface::master->syncRaw(triggerToMsg[(unsigned)trigger], sync_tick);
+    }
+    // now wait until all receiver threads complete the synchronisation
+    auto lf = [this]{ return waitNum == 0; };
+    cv.wait(sync_lock, lf);
+
+    // we are done
+    assert(state == SyncState::busy || state == SyncState::interrupted);
+    bool ret = (state != SyncState::interrupted);
+    state = SyncState::idle;
+    return ret;
+}
+
+void
+MultiIface::Sync::progress(MsgType msg)
+{
+    std::unique_lock<std::mutex> sync_lock(lock);
+
+    switch (msg) {
+      case MsgType::cmdAtomicSyncAck:
+        assert(state == SyncState::busy && trigger == SyncTrigger::atomic);
+        break;
+      case MsgType::cmdPeriodicSyncAck:
+        assert(state == SyncState::busy && trigger == SyncTrigger::periodic);
+        break;
+      case MsgType::cmdCkptSyncAck:
+        assert(state == SyncState::busy && trigger == SyncTrigger::ckpt);
+        break;
+      case MsgType::cmdCkptSyncReq:
+        switch (state) {
+          case SyncState::busy:
+            if (trigger == SyncTrigger::ckpt) {
+                // We are already in a checkpoint sync but got another ckpt
+                // sync request. This may happen if two (or more) peer gem5
+                // processes try to start a ckpt nearly at the same time.
+                // Incrementing waitNum here (before decrementing it below)
+                // effectively results in ignoring this new ckpt sync request.
+                waitNum++;
+                break;
+            }
+            assert (waitNum == recvThreadsNum);
+            state = SyncState::interrupted;
+            // we need to fall over here to handle "recvThreadsNum == 1" case
+          case SyncState::interrupted:
+            assert(trigger == SyncTrigger::periodic);
+            assert(waitNum >= 1);
+            if (waitNum == 1) {
+                exitSimLoop("checkpoint");
+            }
+            break;
+          case SyncState::idle:
+            // There is no on-going sync so we got an async ckpt request. If we
+            // are the only receiver thread then we need to schedule the
+            // checkpoint. Otherwise, only change the state to 'asyncCkpt' and
+            // let the last receiver thread to schedule the checkpoint at the
+            // 'asyncCkpt' case.
+            // Note that a periodic or resume sync may start later and that can
+            // trigger a state change to 'interrupted' (so the checkpoint may
+            // get scheduled at 'interrupted' case finally).
+            assert(waitNum == 0);
+            state = SyncState::asyncCkpt;
+            waitNum = MultiIface::recvThreadsNum;
+            // we need to fall over here to handle "recvThreadsNum == 1" case
+          case SyncState::asyncCkpt:
+            assert(waitNum >= 1);
+            if (waitNum == 1)
+                exitSimLoop("checkpoint");
+            break;
+          default:
+            panic("Unexpected state for checkpoint request message");
+            break;
+        }
+        break;
+      default:
+        panic("Unknown msg type");
+        break;
+    }
+    waitNum--;
+    assert(state != SyncState::idle);
+    // Notify the simultaion thread if there is an on-going sync.
+    if (state != SyncState::asyncCkpt) {
+        sync_lock.unlock();
+        cv.notify_one();
+    }
+}
+
+void MultiIface::SyncEvent::start(Tick start, Tick interval)
+{
+    assert(!scheduled());
+    if (interval == 0)
+        panic("Multi synchronisation period must be greater than zero");
+    repeat = interval;
+    schedule(start);
+}
+
+void
+MultiIface::SyncEvent::adjust(Tick start_tick, Tick repeat_tick)
+{
+    // The new multi interface may require earlier start of the
+    // synchronisation.
+    assert(scheduled() == true);
+    if (start_tick < when())
+        reschedule(start_tick);
+    // The new multi interface may require more frequent synchronisation.
+    if (repeat == 0)
+        panic("Multi synchronisation period must be greater than zero");
+    if (repeat < repeat_tick)
+        repeat = repeat_tick;
+}
+
+void
+MultiIface::SyncEvent::process()
+{
+    /*
+     * Note that this is a global event so this process method will be called
+     * by only exactly one thread.
+     */
+    // if we are draining the system then we must not start a periodic sync (as
+    // it is not sure that all peer gem5 will reach this tick before taking
+    // the checkpoint).
+    if (isDraining == true) {
+        assert(interrupted == false);
+        interrupted = true;
+        DPRINTF(MultiEthernet,"MultiIface::SyncEvent::process() interrupted "
+                "due to draining\n");
+        return;
+    }
+    if (interrupted == false)
+        scheduledAt = curTick();
+    /*
+     * We hold the eventq lock at this point but the receiver thread may
+     * need the lock to schedule new recv events while waiting for the
+     * multi sync to complete.
+     * Note that the other simulation threads also release their eventq
+     * locks while waiting for us due to the global event semantics.
+     */
+    curEventQueue()->unlock();
+    // we do a global sync here
+    interrupted = !MultiIface::sync->run(SyncTrigger::periodic, scheduledAt);
+    // Global sync completed or got interrupted.
+    // we are expected to exit with the eventq lock held
+    curEventQueue()->lock();
+    // schedule the next global sync event if this one completed. Otherwise
+    // (i.e. this one was interrupted by a checkpoint request), we will 
+    // reschedule this one after the draining is complete.
+    if (!interrupted)
+        schedule(scheduledAt + repeat);
+}
+
+void MultiIface::SyncEvent::resume()
+{
+    Tick sync_tick;
+    assert(!scheduled());
+    if (interrupted) {
+        assert(curTick() >= scheduledAt);
+        // We have to complete the interrupted periodic sync asap.
+        // Note that this sync might be interrupted now again with a checkpoint
+        // request from a peer gem5...
+        sync_tick = curTick();
+        schedule(sync_tick);
+    } else {
+        // So we completed the last periodic sync, let's find  out the tick for
+        // next one
+        assert(curTick() > scheduledAt);
+        sync_tick = scheduledAt + repeat;
+        if (sync_tick < curTick())
+            panic("Cannot resume periodic synchronisation");
+        schedule(sync_tick);
+    }
+    DPRINTF(MultiEthernet,
+            "MultiIface::SyncEvent periodic sync resumed at %lld "
+            "(curTick:%lld)\n", sync_tick, curTick());
+}
+
+void MultiIface::SyncEvent::serialize(const std::string &base,
+                                      CheckpointOut &cp) const
+{
+    // Save the periodic multi sync schedule information
+    paramOut(cp, base + ".periodicSyncRepeat", repeat);
+    paramOut(cp, base + ".periodicSyncInterrupted", interrupted);
+    paramOut(cp, base + ".periodicSyncAt", scheduledAt);
+}
+
+void MultiIface::SyncEvent::unserialize(const std::string &base,
+                                        CheckpointIn &cp)
+{
+    paramIn(cp, base + ".periodicSyncRepeat", repeat);
+    paramIn(cp, base + ".periodicSyncInterrupted", interrupted);
+    paramIn(cp, base + ".periodicSyncAt", scheduledAt);
+}
+
+MultiIface::MultiIface(unsigned multi_rank,
+                       Tick sync_start,
+                       Tick sync_repeat,
+                       EventManager *em) :
+    syncStart(sync_start), syncRepeat(sync_repeat),
+    recvThread(nullptr), eventManager(em), recvDone(nullptr),
+    scheduledRecvPacket(nullptr), linkDelay(0), rank(multi_rank)
+{
+    DPRINTF(MultiEthernet, "MultiIface() ctor rank:%d\n",multi_rank);
+    if (master == nullptr) {
+        assert(sync == nullptr);
+        assert(syncEvent == nullptr);
+        sync = new Sync();
+        syncEvent = new SyncEvent();
+        master = this;
+    }
+}
+
+MultiIface::~MultiIface()
+{
+    assert(recvThread);
+    delete recvThread;
+    if (this == master) {
+        assert(syncEvent);
+        delete syncEvent;
+        assert(sync);
+        delete sync;
+    }
+}
+
+void
+MultiIface::packetOut(EthPacketPtr pkt, Tick send_delay)
+{
+    MultiHeaderPkt::Header header_pkt;
+    unsigned address_length = MultiHeaderPkt::maxAddressLength();
+
+    // Prepare a multi header packet for the Ethernet packet we want to
+    // send out.
+    header_pkt.msgType = MsgType::dataDescriptor;
+    header_pkt.sendTick  = curTick();
+    header_pkt.sendDelay = send_delay;
+
+    // Store also the source and destination addresses.
+    pkt->packAddress(header_pkt.srcAddress, header_pkt.dstAddress,
+                     address_length);
+
+    header_pkt.dataPacketLength = pkt->size();
+
+    // Send out the multi hedare packet followed by the Ethernet packet.
+    sendRaw(&header_pkt, sizeof(header_pkt), header_pkt.dstAddress);
+    sendRaw(pkt->data, pkt->size(), header_pkt.dstAddress);
+    DPRINTF(MultiEthernetPkt,
+            "MultiIface::sendDataPacket() done size:%d send_delay:%llu "
+            "src:0x%02x%02x%02x%02x%02x%02x "
+            "dst:0x%02x%02x%02x%02x%02x%02x\n",
+            pkt->size(), send_delay,
+            header_pkt.srcAddress[0], header_pkt.srcAddress[1],
+            header_pkt.srcAddress[2], header_pkt.srcAddress[3],
+            header_pkt.srcAddress[4], header_pkt.srcAddress[5],
+            header_pkt.dstAddress[0], header_pkt.dstAddress[1],
+            header_pkt.dstAddress[2], header_pkt.dstAddress[3],
+            header_pkt.dstAddress[4], header_pkt.dstAddress[5]);
+}
+
+bool
+MultiIface::recvHeader(MultiHeaderPkt::Header &header_pkt)
+{
+    // Blocking receive of an incoming multi header packet.
+    return recvRaw((void *)&header_pkt, sizeof(header_pkt));
+}
+
+void
+MultiIface::recvData(const MultiHeaderPkt::Header &header_pkt)
+{
+    // We are here beacuse a header packet has been received implying
+    // that an Ethernet (data) packet is coming in next.
+    assert(header_pkt.msgType == MsgType::dataDescriptor);
+    // Allocate storage for the incoming Ethernet packet.
+    EthPacketPtr new_packet(new EthPacketData(header_pkt.dataPacketLength));
+    // Now execute the blocking receive and store the incoming data directly
+    // in the new EthPacketData object.
+    if (! recvRaw((void *)(new_packet->data), header_pkt.dataPacketLength))
+        panic("Missing data packet");
+
+    new_packet->length = header_pkt.dataPacketLength;
+    // Grab the event queue lock to schedule a new receive event for the
+    // data packet.
+    curEventQueue()->lock();
+    // Compute the receive tick. It includes the send delay and the
+    // simulated link delay.
+    Tick recv_tick = header_pkt.sendTick + header_pkt.sendDelay + linkDelay;
+    DPRINTF(MultiEthernetPkt, "MultiIface::recvThread() packet receive, "
+            "send_tick:%llu send_delay:%llu link_delay:%llu recv_tick:%llu\n",
+            header_pkt.sendTick, header_pkt.sendDelay, linkDelay, recv_tick);
+
+    if (recv_tick <= curTick()) {
+        panic("Simulators out of sync - missed packet receive by %llu ticks",
+              curTick() - recv_tick);
+    }
+    // Now we are about to schedule a recvDone event for the new data packet.
+    // We use the same recvDone object for all incoming data packets. If
+    // that is already scheduled - i.e. a receive event for a previous
+    // data packet is already pending - then we have to check whether the
+    // receive tick for the new packet is earlier than that of the currently
+    // pending event. Packets may arrive out-of-order with respect to
+    // simulated receive time. If that is the case, we need to re-schedule the
+    // recvDone event for the new packet. Otherwise, we save the packet
+    // pointer and the recv tick for the new packet in the recvQueue. See
+    // the implementation of the packetIn() method for comments on how this
+    // information is retrieved from the recvQueue by the simulation thread.
+    if (!recvDone->scheduled()) {
+        assert(recvQueue.size() == 0);
+        assert(scheduledRecvPacket == nullptr);
+        scheduledRecvPacket = new_packet;
+        eventManager->schedule(recvDone, recv_tick);
+    } else if (recvDone->when() > recv_tick) {
+        recvQueue.emplace(scheduledRecvPacket, recvDone->when());
+        eventManager->reschedule(recvDone, recv_tick);
+        scheduledRecvPacket = new_packet;
+    } else {
+        recvQueue.emplace(new_packet, recv_tick);
+    }
+    curEventQueue()->unlock();
+}
+
+void
+MultiIface::recvThreadFunc()
+{
+    EthPacketPtr new_packet;
+    MultiHeaderPkt::Header header;
+
+    // The new receiver thread shares the event queue with the simulation
+    // thread (associated with the simulated Ethernet link).
+    curEventQueue(eventManager->eventQueue());
+    // Main loop to wait for and process any incoming message.
+    for (;;) {
+        // recvHeader() blocks until the next multi header packet comes in.
+        if (!recvHeader(header)) {
+            // We lost connection to the peer gem5 processes most likely
+            // because one of them called m5 exit. So we stop here.
+            exit_message("info", 0, "Message server closed connection, "
+                         "simulation is exiting");
+        }
+        // We got a valid multi header packet, let's process it
+        if (header.msgType == MsgType::dataDescriptor) {
+            recvData(header);
+        } else {
+            // everything else must be synchronisation related command
+            sync->progress(header.msgType);
+        }
+    }
+}
+
+EthPacketPtr
+MultiIface::packetIn()
+{
+    // We are called within the process() method of the recvDone event. We
+    // return the packet that triggered the current receive event.
+    // If there is further packets in the recvQueue, we also have to schedule
+    // the recvEvent for the next packet with the smallest receive tick.
+    // The priority queue container ensures that smallest receive tick is
+    // always on the top of the queue.
+    assert(scheduledRecvPacket != nullptr);
+    EthPacketPtr next_packet = scheduledRecvPacket;
+
+    if (! recvQueue.empty()) {
+        eventManager->schedule(recvDone, recvQueue.top().second);
+        scheduledRecvPacket = recvQueue.top().first;
+        recvQueue.pop();
+    } else {
+        scheduledRecvPacket = nullptr;
+    }
+
+    return next_packet;
+}
+
+void
+MultiIface::spawnRecvThread(Event *recv_done, Tick link_delay)
+{
+    assert(recvThread == nullptr);
+    // all receive thread must be spawned before simulation starts
+    assert(eventManager->eventQueue()->getCurTick() == 0);
+
+    recvDone = recv_done;
+    linkDelay = link_delay;
+
+    recvThread = new std::thread(&MultiIface::recvThreadFunc, this);
+
+    recvThreadsNum++;
+}
+
+DrainState
+MultiIface::drain()
+{
+    DPRINTF(MultiEthernet,"MultiIFace::drain() called\n");
+
+    // This can be called multiple times in the same drain cycle.
+    if (master == this) {
+        syncEvent->isDraining = true;
+    }
+
+    return DrainState::Drained;
+}
+
+void MultiIface::drainDone() {
+    if (master == this) {
+        assert(syncEvent->isDraining == true);
+        syncEvent->isDraining = false;
+        // We need to resume the interrupted periodic sync here now that the
+        // draining is done. If the last periodic sync completed before the
+        // checkpoint then the next one is already scheduled.
+        if (syncEvent->interrupted)
+            syncEvent->resume();
+    }
+}
+
+void MultiIface::serialize(const std::string &base, CheckpointOut &cp) const
+{
+    // Drain the multi interface before the checkpoint is taken. We cannot call
+    // this as part of the normal drain cycle because this multi sync has to be
+    // called exactly once after the system is fully drained.
+    // Note that every peer will take a checkpoint but they may take it at
+    // different ticks.
+    // This sync request may interrupt an on-going periodic sync in some peers.
+    sync->run(SyncTrigger::ckpt, curTick());
+
+    // Save the periodic multi sync status
+    syncEvent->serialize(base, cp);
+
+    unsigned n_rx_packets = recvQueue.size();
+    if (scheduledRecvPacket != nullptr)
+        n_rx_packets++;
+
+    paramOut(cp, base + ".nRxPackets", n_rx_packets);
+
+    if (n_rx_packets > 0) {
+        assert(recvDone->scheduled());
+        scheduledRecvPacket->serialize(base + ".rxPacket[0]", cp);
+    }
+
+    for (unsigned i=1; i < n_rx_packets; i++)  {
+        const RecvInfo recv_info = recvQueue.impl().at(i-1);
+        recv_info.first->serialize(base + csprintf(".rxPacket[%d]", i), cp);
+        Tick rx_tick = recv_info.second;
+        paramOut(cp, base + csprintf(".rxTick[%d]", i), rx_tick);
+    }
+}
+
+void MultiIface::unserialize(const std::string &base, CheckpointIn &cp)
+{
+    assert(recvQueue.size() == 0);
+    assert(scheduledRecvPacket == nullptr);
+    assert(recvDone->scheduled() == false);
+
+    // restore periodic sync info
+    syncEvent->unserialize(base, cp);
+
+    unsigned n_rx_packets;
+    paramIn(cp, base + ".nRxPackets", n_rx_packets);
+
+    if (n_rx_packets > 0) {
+        scheduledRecvPacket = std::make_shared<EthPacketData>(16384);
+        scheduledRecvPacket->unserialize(base + ".rxPacket[0]", cp);
+        // Note: receive event will be scheduled when the link is unserialized
+    }
+
+    for (unsigned i=1; i < n_rx_packets; i++) {
+        EthPacketPtr rx_packet = std::make_shared<EthPacketData>(16384);
+        rx_packet->unserialize(base + csprintf(".rxPacket[%d]", i), cp);
+        Tick rx_tick = 0;
+        paramIn(cp, base + csprintf(".rxTick[%d]", i), rx_tick);
+        assert(rx_tick > 0);
+        recvQueue.emplace(rx_packet,rx_tick);
+    }
+}
+
+void MultiIface::initRandom()
+{
+    // Initialize the seed for random generator to avoid the same sequence
+    // in all gem5 peer processes
+    assert(master != nullptr);
+    if (this == master)
+        random_mt.init(5489 * (rank+1) + 257);
+}
+
+void MultiIface::startPeriodicSync()
+{
+    DPRINTF(MultiEthernet, "MultiIface:::initPeriodicSync started\n");
+    // Do a global sync here to ensure that peer gem5 processes are around
+    // (actually this may not be needed...)
+    sync->run(SyncTrigger::atomic, curTick());
+
+    // Start the periodic sync if it is a fresh simulation from scratch
+    if (curTick() == 0) {
+        if (this == master) {
+        syncEvent->start(syncStart, syncRepeat);
+        inform("Multi synchronisation activated: start at %lld, "
+               "repeat at every %lld ticks.\n",
+               syncStart, syncRepeat);
+        } else {
+            // In case another multiIface object requires different schedule
+            // for periodic sync than the master does.
+            syncEvent->adjust(syncStart, syncRepeat);
+        }
+    } else {
+        // Schedule the next periodic sync if resuming from a checkpoint
+        if (this == master)
+            syncEvent->resume();
+    }
+    DPRINTF(MultiEthernet, "MultiIface::initPeriodicSync done\n");
+}
diff --git a/src/dev/net/multi_iface.hh b/src/dev/net/multi_iface.hh
new file mode 100644 (file)
index 0000000..f8ce2ab
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * The interface class for multi gem5 simulations.
+ *
+ * Multi gem5 is an extension to gem5 to enable parallel simulation of a
+ * distributed system (e.g. simulation of a pool of machines
+ * connected by Ethernet links). A multi gem5 run consists of seperate gem5
+ * processes running in parallel. Each gem5 process executes
+ * the simulation of a component of the simulated distributed system.
+ * (An example component can be a multi-core board with an Ethernet NIC.)
+ * The MultiIface class below provides services to transfer data and
+ * control messages among the gem5 processes. The main such services are
+ * as follows.
+ *
+ * 1. Send a data packet coming from a simulated Ethernet link. The packet
+ * will be transferred to (all) the target(s) gem5 processes. The send
+ * operation is always performed by the simulation thread, i.e. the gem5
+ * thread that is processing the event queue associated with the simulated
+ * Ethernet link.
+ *
+ * 2. Spawn a receiver thread to process messages coming in from the
+ * from other gem5 processes. Each simulated Ethernet link has its own
+ * associated receiver thread. The receiver thread saves the incoming packet
+ * and schedule an appropriate receive event in the event queue.
+ *
+ * 3. Schedule a global barrier event periodically to keep the gem5
+ * processes in sync.
+ * Periodic barrier event to keep peer gem5 processes in sync. The basic idea
+ * is that no gem5 process can go ahead further than the simulated link
+ * transmission delay to ensure that a corresponding receive event can always
+ * be scheduled for any message coming in from a peer gem5 process.
+ *
+ *
+ *
+ * This interface is an abstract class (sendRaw() and recvRaw()
+ * methods are pure virtual). It can work with various low level
+ * send/receive service implementations (e.g. TCP/IP, MPI,...). A TCP
+ * stream socket version is implemented in dev/src/tcp_iface.[hh,cc].
+ */
+#ifndef __DEV_NET_MULTI_IFACE_HH__
+#define __DEV_NET_MULTI_IFACE_HH__
+
+#include <array>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+#include "dev/net/etherpkt.hh"
+#include "dev/net/multi_packet.hh"
+#include "sim/core.hh"
+#include "sim/drain.hh"
+#include "sim/global_event.hh"
+
+class EventManager;
+
+/**
+ * The interface class to talk to peer gem5 processes.
+ */
+class MultiIface : public Drainable
+{
+  public:
+    /*!
+     * The possible reasons a multi sync among gem5 peers is needed for.
+     */
+    enum
+    class SyncTrigger {
+        periodic, /*!< Regular periodic sync. This can be interrupted by a
+                   checkpoint sync request */
+        ckpt,     /*!< sync before taking a checkpoint */
+        atomic    /*!< sync that cannot be interrupted (e.g. sync at startup) */
+    };
+
+  private:
+    typedef MultiHeaderPkt::MsgType MsgType;
+
+    /** Sync State-Machine
+     \dot
+     digraph Sync {
+     node [shape=box, fontsize=10];
+     idle -> busy
+     [ label="new trigger\n by run()" fontsize=8 ];
+     busy -> busy
+     [ label="new message by progress():\n(msg == SyncAck &&\nwaitNum > 1) || \n(msg==CkptSyncReq &&\ntrigger == ckpt)" fontsize=8 ];
+     busy -> idle
+     [ label="new message by progress():\n(msg == SyncAck &&\nwaitNum == 1)" fontsize=8 ];
+     busy -> interrupted
+     [ label="new message by progress():\n(msg == CkptSyncReq &&\ntrigger == periodic)" fontsize=8 ];
+     idle -> asyncCkpt
+     [ label="new message by progress():\nmsg == CkptSyncReq" fontsize=8 ];
+     asyncCkpt -> asyncCkpt
+     [ label="new message by progress():\nmsg == CkptSyncReq" fontsize=8 ];
+     asyncCkpt -> busy
+     [ label="new trigger by run():\ntrigger == ckpt" fontsize=8 ];
+     asyncCkpt -> idle
+     [ label="new trigger by run():\n(trigger == periodic &&\nwaitNum == 0) " fontsize=8 ];
+     asyncCkpt -> interrupted
+     [ label="new trigger by run():\n(trigger == periodic &&\nwaitNum > 0) " fontsize=8 ];
+     interrupted -> interrupted
+     [ label="new message by progress():\n(msg == CkptSyncReq &&\nwaitNum > 1)" fontsize=8 ];
+     interrupted -> idle
+     [ label="new message by progress():\n(msg == CkptSyncReq &&\nwaitNum == 1)" fontsize=8 ];
+     }
+     \enddot
+     */
+    /** @class Sync
+     * This class implements global sync operations among gem5 peer processes.
+     *
+     * @note This class is used as a singleton object (shared by all MultiIface
+     * objects).
+     */
+    class Sync
+    {
+      private:
+        /*!
+         * Internal state of the sync singleton object.
+         */
+        enum class SyncState {
+            busy,        /*!< There is an on-going sync. */
+            interrupted, /*!< An on-going periodic sync was interrupted. */
+            asyncCkpt,   /*!< A checkpoint (sim_exit) is already scheduled */
+            idle         /*!< There is no active sync. */
+        };
+        /**
+         * The lock to protect access to the MultiSync object.
+         */
+        std::mutex lock;
+        /**
+         * Condition variable for the simulation thread to wait on
+         * until all receiver threads completes the current global
+         * synchronisation.
+         */
+        std::condition_variable cv;
+        /**
+         * Number of receiver threads that not yet completed the current global
+         * synchronisation.
+         */
+        unsigned waitNum;
+        /**
+         * The trigger for the most recent sync.
+         */
+        SyncTrigger trigger;
+        /**
+         * Map sync triggers to request messages.
+         */
+        std::array<MsgType, 3> triggerToMsg = {{
+                MsgType::cmdPeriodicSyncReq,
+                MsgType::cmdCkptSyncReq,
+                MsgType::cmdAtomicSyncReq
+            }};
+
+        /**
+         * Current sync state.
+         */
+        SyncState state;
+
+      public:
+        /**
+         *  Core method to perform a full multi sync.
+         *
+         * @param t Sync trigger.
+         * @param sync_tick The tick the sync was expected to happen at.
+         * @return true if the sync completed, false if it was interrupted.
+         *
+         * @note In case of an interrupted periodic sync, sync_tick can be less
+         * than curTick() when we resume (i.e. re-run) it
+         */
+        bool run(SyncTrigger t, Tick sync_tick);
+        /**
+         * Callback when the receiver thread gets a sync message.
+         */
+        void progress(MsgType m);
+
+        Sync() : waitNum(0), state(SyncState::idle) {}
+        ~Sync() {}
+    };
+
+
+    /**
+     * The global event to schedule peridic multi sync. It is used as a
+     * singleton object.
+     *
+     * The periodic synchronisation works as follows.
+     * 1. A MultisyncEvent is scheduled as a global event when startup() is
+     * called.
+     * 2. The progress() method of the MultisyncEvent initiates a new barrier
+     * for each simulated Ethernet links.
+     * 3. Simulation thread(s) then waits until all receiver threads
+     * completes the ongoing barrier. The global sync event is done.
+     */
+    class SyncEvent : public GlobalSyncEvent
+    {
+      public:
+        /**
+         * Flag to indicate that the most recent periodic sync was interrupted
+         * (by a checkpoint request).
+         */
+        bool interrupted;
+        /**
+         * The tick when the most recent periodic synchronisation was scheduled
+         * at.
+         */
+        Tick scheduledAt;
+        /**
+         * Flag to indicate an on-going drain cycle.
+         */
+         bool isDraining;
+
+      public:
+        /**
+         * Only the firstly instanstiated MultiIface object will
+         * call this constructor.
+         */
+        SyncEvent() : GlobalSyncEvent(Default_Pri, 0), interrupted(false),
+                      scheduledAt(0), isDraining(false) {}
+
+        ~SyncEvent() { assert (scheduled() == false); }
+        /**
+         * Schedule the first periodic sync event.
+         *
+         * @param start Start tick for multi synchronisation
+         * @param repeat Frequency of multi synchronisation
+         *
+         */
+        void start(Tick start, Tick repeat);
+        /**
+         * Reschedule (if necessary) the periodic sync event.
+         *
+         * @param start Start tick for multi synchronisation
+         * @param repeat Frequency of multi synchronisation
+         *
+         * @note Useful if we have multiple MultiIface objects with
+         * different 'start' and 'repeat' values for global sync.
+         */
+        void adjust(Tick start, Tick repeat);
+        /**
+         * This is a global event so process() will be called by each
+         * simulation threads. (See further comments in the .cc file.)
+         */
+        void process() override;
+        /**
+         * Schedule periodic sync when resuming from a checkpoint.
+         */
+        void resume();
+
+        void serialize(const std::string &base, CheckpointOut &cp) const;
+        void unserialize(const std::string &base, CheckpointIn &cp);
+    };
+
+    /**
+     * The receive thread needs to store the packet pointer and the computed
+     * receive tick for each incoming data packet. This information is used
+     * by the simulation thread when it processes the corresponding receive
+     * event. (See more comments at the implemetation of the recvThreadFunc()
+     * and RecvPacketIn() methods.)
+     */
+    typedef std::pair<EthPacketPtr, Tick> RecvInfo;
+
+    /**
+     * Comparison predicate for RecvInfo, needed by the recvQueue.
+     */
+    struct RecvInfoCompare {
+        bool operator()(const RecvInfo &lhs, const RecvInfo &rhs)
+        {
+            return lhs.second > rhs.second;
+        }
+    };
+
+    /**
+     * Customized priority queue used to store incoming data packets info by
+     * the receiver thread. We need to expose the underlying container to
+     * enable iterator access for serializing.
+     */
+    class RecvQueue : public std::priority_queue<RecvInfo,
+                                                 std::vector<RecvInfo>,
+                                                 RecvInfoCompare>
+    {
+      public:
+        std::vector<RecvInfo> &impl() { return c; }
+        const std::vector<RecvInfo> &impl() const { return c; }
+    };
+
+    /*
+     * The priority queue to store RecvInfo items ordered by receive ticks.
+     */
+    RecvQueue recvQueue;
+    /**
+     * The singleton Sync object to perform multi synchronisation.
+     */
+    static Sync *sync;
+    /**
+     * The singleton SyncEvent object to schedule periodic multi sync.
+     */
+    static SyncEvent *syncEvent;
+    /**
+     * Tick to schedule the first multi sync event.
+     * This is just as optimization : we do not need any multi sync
+     * event until the simulated NIC is brought up by the OS.
+     */
+    Tick syncStart;
+    /**
+     * Frequency of multi sync events in ticks.
+     */
+    Tick syncRepeat;
+    /**
+     * Receiver thread pointer.
+     * Each MultiIface object must have exactly one receiver thread.
+     */
+    std::thread *recvThread;
+    /**
+     * The event manager associated with the MultiIface object.
+     */
+    EventManager *eventManager;
+
+    /**
+     * The receive done event for the simulated Ethernet link.
+     * It is scheduled by the receiver thread for each incoming data
+     * packet.
+     */
+    Event *recvDone;
+
+    /**
+     * The packet that belongs to the currently scheduled recvDone event.
+     */
+    EthPacketPtr scheduledRecvPacket;
+
+    /**
+     * The link delay in ticks for the simulated Ethernet link.
+     */
+    Tick linkDelay;
+
+    /**
+     * The rank of this process among the gem5 peers.
+     */
+    unsigned rank;
+    /**
+     * Total number of receiver threads (in this gem5 process).
+     * During the simulation it should be constant and equal to the
+     * number of MultiIface objects (i.e. simulated Ethernet
+     * links).
+     */
+    static unsigned recvThreadsNum;
+    /**
+     * The very first MultiIface object created becomes the master. We need
+     * a master to co-ordinate the global synchronisation.
+     */
+    static MultiIface *master;
+
+  protected:
+    /**
+     * Low level generic send routine.
+     * @param buf buffer that holds the data to send out
+     * @param length number of bytes to send
+     * @param dest_addr address of the target (simulated NIC). This may be
+     * used by a subclass for optimization (e.g. optimize broadcast)
+     */
+    virtual void sendRaw(void *buf,
+                         unsigned length,
+                         const MultiHeaderPkt::AddressType dest_addr) = 0;
+    /**
+     * Low level generic receive routine.
+     * @param buf the buffer to store the incoming message
+     * @param length buffer size (in bytes)
+     */
+    virtual bool recvRaw(void *buf, unsigned length) = 0;
+    /**
+     * Low level request for synchronisation among gem5 processes. Only one
+     * MultiIface object needs to call this (in each gem5 process) to trigger
+     * a multi sync.
+     *
+     * @param sync_req Sync request command.
+     * @param sync_tick The tick when sync is expected to happen in the sender.
+     */
+    virtual void syncRaw(MsgType sync_req, Tick sync_tick) = 0;
+    /**
+     * The function executed by a receiver thread.
+     */
+    void recvThreadFunc();
+    /**
+     * Receive a multi header packet. Called by the receiver thread.
+     * @param header the structure to store the incoming header packet.
+     * @return false if any error occured during the receive, true otherwise
+     *
+     * A header packet can carry a control command (e.g. 'barrier leave') or
+     * information about a data packet that is following the header packet
+     * back to back.
+     */
+    bool recvHeader(MultiHeaderPkt::Header &header);
+    /**
+     * Receive a data packet. Called by the receiver thread.
+     * @param data_header The packet descriptor for the expected incoming data
+     * packet.
+     */
+    void recvData(const MultiHeaderPkt::Header &data_header);
+
+  public:
+
+    /**
+     * ctor
+     * @param multi_rank Rank of this gem5 process within the multi run
+     * @param sync_start Start tick for multi synchronisation
+     * @param sync_repeat Frequency for multi synchronisation
+     * @param em The event manager associated with the simulated Ethernet link
+     */
+    MultiIface(unsigned multi_rank,
+               Tick sync_start,
+               Tick sync_repeat,
+               EventManager *em);
+
+    virtual ~MultiIface();
+    /**
+     * Send out an Ethernet packet.
+     * @param pkt The Ethernet packet to send.
+     * @param send_delay The delay in ticks for the send completion event.
+     */
+    void packetOut(EthPacketPtr pkt, Tick send_delay);
+    /**
+     * Fetch the next packet from the receive queue.
+     */
+    EthPacketPtr packetIn();
+
+    /**
+     * spawn the receiver thread.
+     * @param recv_done The receive done event associated with the simulated
+     * Ethernet link.
+     * @param link_delay The link delay for the simulated Ethernet link.
+     */
+    void spawnRecvThread(Event *recv_done,
+                         Tick link_delay);
+    /**
+     * Initialize the random number generator with a different seed in each
+     * peer gem5 process.
+     */
+    void initRandom();
+
+    DrainState drain() override;
+
+    /**
+     * Callback when draining is complete.
+     */
+    void drainDone();
+
+    /**
+     * Initialize the periodic synchronisation among peer gem5 processes.
+     */
+    void startPeriodicSync();
+
+    void serialize(const std::string &base, CheckpointOut &cp) const;
+    void unserialize(const std::string &base, CheckpointIn &cp);
+
+};
+
+
+#endif // __DEV_NET_MULTI_IFACE_HH__
diff --git a/src/dev/net/multi_packet.cc b/src/dev/net/multi_packet.cc
new file mode 100644 (file)
index 0000000..85f76b0
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * MultiHeaderPkt class to encapsulate multi-gem5 header packets
+ *
+ */
+
+#include "dev/net/multi_packet.hh"
+
+#include <cstdint>
+#include <cstring>
+
+#include "base/inet.hh"
+
+unsigned
+MultiHeaderPkt::maxAddressLength()
+{
+    return sizeof(AddressType);
+}
+
+void
+MultiHeaderPkt::clearAddress(AddressType &addr)
+{
+    std::memset(addr, 0, sizeof(addr));
+}
+
+bool
+MultiHeaderPkt::isAddressEqual(const AddressType &addr1,
+                               const AddressType &addr2)
+{
+    return (std::memcmp(addr1, addr2, sizeof(addr1)) == 0);
+}
+
+bool
+MultiHeaderPkt::isAddressLess(const AddressType &addr1,
+                              const AddressType &addr2)
+{
+    return (std::memcmp(addr1, addr2, sizeof(addr1)) < 0);
+}
+
+void
+MultiHeaderPkt::copyAddress(AddressType &dest, const AddressType &src)
+{
+    std::memcpy(dest, src, sizeof(dest));
+}
+
+bool
+MultiHeaderPkt::isBroadcastAddress(const AddressType &addr)
+{
+    return ((Net::EthAddr *)&addr)->broadcast();
+}
+
+bool
+MultiHeaderPkt::isMulticastAddress(const AddressType &addr)
+{
+    return ((Net::EthAddr *)&addr)->multicast();
+}
+
+bool
+MultiHeaderPkt::isUnicastAddress(const AddressType &addr)
+{
+    return ((Net::EthAddr *)&addr)->unicast();
+}
diff --git a/src/dev/net/multi_packet.hh b/src/dev/net/multi_packet.hh
new file mode 100644 (file)
index 0000000..3d8e85d
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * Header packet class for multi gem5 runs.
+ *
+ * For a high level description about multi gem5 see comments in
+ * header file multi_iface.hh.
+ *
+ * The MultiHeaderPkt class defines the format of message headers
+ * sent among gem5 processes during a multi gem5 simulation. A header packet
+ * can either carry the description of data packet (i.e. a simulated Ethernet
+ * packet) or a synchronisation related control command. In case of
+ * data packet description, the corresponding data packet always follows
+ * the header packet back-to-back.
+ */
+#ifndef __DEV_NET_MULTI_PACKET_HH__
+#define __DEV_NET_MULTI_PACKET_HH__
+
+#include <cstring>
+
+#include "base/types.hh"
+
+class MultiHeaderPkt
+{
+  private:
+    MultiHeaderPkt() {}
+    ~MultiHeaderPkt() {}
+
+  public:
+    /**
+     * Simply type to help with calculating space requirements for
+     * the corresponding header field.
+     */
+    typedef uint8_t AddressType[6];
+
+    /**
+     *  The msg type defines what informarion a multi header packet carries.
+     */
+    enum class MsgType
+    {
+        dataDescriptor,
+        cmdPeriodicSyncReq,
+        cmdPeriodicSyncAck,
+        cmdCkptSyncReq,
+        cmdCkptSyncAck,
+        cmdAtomicSyncReq,
+        cmdAtomicSyncAck,
+        unknown
+    };
+
+    struct Header
+    {
+        /**
+         * The msg type field is valid for all header packets. In case of
+         * a synchronisation control command this is the only valid field.
+         */
+        MsgType msgType;
+        Tick sendTick;
+        Tick sendDelay;
+        /**
+         * Actual length of the simulated Ethernet packet.
+         */
+        unsigned dataPacketLength;
+        /**
+         * Source MAC address.
+         */
+        AddressType srcAddress;
+        /**
+         * Destination MAC address.
+         */
+        AddressType dstAddress;
+    };
+
+    static unsigned maxAddressLength();
+
+    /**
+     * Static functions for manipulating and comparing MAC addresses.
+     */
+    static void clearAddress(AddressType &addr);
+    static bool isAddressEqual(const AddressType &addr1,
+                               const AddressType &addr2);
+    static bool isAddressLess(const AddressType &addr1,
+                              const AddressType &addr2);
+
+    static void copyAddress(AddressType &dest,
+                            const AddressType &src);
+
+    static bool isUnicastAddress(const AddressType &addr);
+    static bool isMulticastAddress(const AddressType &addr);
+    static bool isBroadcastAddress(const AddressType &addr);
+};
+
+#endif // __DEV_NET_MULTI_PACKET_HH__
diff --git a/src/dev/net/ns_gige.cc b/src/dev/net/ns_gige.cc
new file mode 100644 (file)
index 0000000..a1dc23b
--- /dev/null
@@ -0,0 +1,2483 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Lisa Hsu
+ */
+
+/** @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller.  Does not support priority queueing
+ */
+
+#include "dev/net/ns_gige.hh"
+
+#include <deque>
+#include <memory>
+#include <string>
+
+#include "base/debug.hh"
+#include "base/inet.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
+#include "debug/EthernetAll.hh"
+#include "dev/net/etherlink.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/NSGigE.hh"
+#include "sim/system.hh"
+
+// clang complains about std::set being overloaded with Packet::set if
+// we open up the entire namespace std
+using std::make_shared;
+using std::min;
+using std::ostream;
+using std::string;
+
+const char *NsRxStateStrings[] =
+{
+    "rxIdle",
+    "rxDescRefr",
+    "rxDescRead",
+    "rxFifoBlock",
+    "rxFragWrite",
+    "rxDescWrite",
+    "rxAdvance"
+};
+
+const char *NsTxStateStrings[] =
+{
+    "txIdle",
+    "txDescRefr",
+    "txDescRead",
+    "txFifoBlock",
+    "txFragRead",
+    "txDescWrite",
+    "txAdvance"
+};
+
+const char *NsDmaState[] =
+{
+    "dmaIdle",
+    "dmaReading",
+    "dmaWriting",
+    "dmaReadWaiting",
+    "dmaWriteWaiting"
+};
+
+using namespace Net;
+using namespace TheISA;
+
+///////////////////////////////////////////////////////////////////////
+//
+// NSGigE PCI Device
+//
+NSGigE::NSGigE(Params *p)
+    : EtherDevBase(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), rxDmaFree(false), txDmaFree(false),
+      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
+      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
+      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
+      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
+      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
+      eepromOpcode(0), eepromAddress(0), eepromData(0),
+      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
+      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
+      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
+      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
+      rxDmaReadEvent(this), rxDmaWriteEvent(this),
+      txDmaReadEvent(this), txDmaWriteEvent(this),
+      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), multicastHashEnable(false),
+      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
+      intrEvent(0), interface(0)
+{
+
+
+    interface = new NSGigEInt(name() + ".int0", this);
+
+    regsReset();
+    memcpy(&rom.perfectMatch, p->hardware_address.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()
+{
+    delete interface;
+}
+
+/**
+ * This is to write to the PCI general configuration registers
+ */
+Tick
+NSGigE::writeConfig(PacketPtr pkt)
+{
+    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+    if (offset < PCI_DEVICE_SPECIFIC)
+        PciDevice::writeConfig(pkt);
+    else
+        panic("Device specific PCI config space not implemented!\n");
+
+    switch (offset) {
+        // seems to work fine without all these PCI settings, but i
+        // put in the IO to double check, an assertion will fail if we
+        // need to properly implement it
+      case PCI_COMMAND:
+        if (config.data[offset] & PCI_CMD_IOSE)
+            ioEnable = true;
+        else
+            ioEnable = false;
+        break;
+    }
+
+    return configDelay;
+}
+
+EtherInt*
+NSGigE::getEthPort(const std::string &if_name, int idx)
+{
+    if (if_name == "interface") {
+       if (interface->getPeer())
+           panic("interface already connected to\n");
+       return interface;
+    }
+    return NULL;
+}
+
+/**
+ * This reads the device registers, which are detailed in the NS83820
+ * spec sheet
+ */
+Tick
+NSGigE::read(PacketPtr pkt)
+{
+    assert(ioEnable);
+
+    //The mask is to give you only the offset into the device register file
+    Addr daddr = pkt->getAddr() & 0xfff;
+    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
+            daddr, pkt->getAddr(), pkt->getSize());
+
+
+    // there are some reserved registers, you can see ns_gige_reg.h and
+    // the spec sheet for details
+    if (daddr > LAST && daddr <=  RESERVED) {
+        panic("Accessing reserved register");
+    } else if (daddr > RESERVED && daddr <= 0x3FC) {
+        return readConfig(pkt);
+    } else if (daddr >= MIB_START && daddr <= MIB_END) {
+        // don't implement all the MIB's.  hopefully the kernel
+        // doesn't actually DEPEND upon their values
+        // MIB are just hardware stats keepers
+        pkt->set<uint32_t>(0);
+        pkt->makeAtomicResponse();
+        return pioDelay;
+    } else if (daddr > 0x3FC)
+        panic("Something is messed up!\n");
+
+    assert(pkt->getSize() == sizeof(uint32_t));
+        uint32_t &reg = *pkt->getPtr<uint32_t>();
+        uint16_t rfaddr;
+
+        switch (daddr) {
+          case CR:
+            reg = regs.command;
+            //these are supposed to be cleared on a read
+            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
+            break;
+
+          case CFGR:
+            reg = regs.config;
+            break;
+
+          case MEAR:
+            reg = regs.mear;
+            break;
+
+          case PTSCR:
+            reg = regs.ptscr;
+            break;
+
+          case ISR:
+            reg = regs.isr;
+            devIntrClear(ISR_ALL);
+            break;
+
+          case IMR:
+            reg = regs.imr;
+            break;
+
+          case IER:
+            reg = regs.ier;
+            break;
+
+          case IHR:
+            reg = regs.ihr;
+            break;
+
+          case TXDP:
+            reg = regs.txdp;
+            break;
+
+          case TXDP_HI:
+            reg = regs.txdp_hi;
+            break;
+
+          case TX_CFG:
+            reg = regs.txcfg;
+            break;
+
+          case GPIOR:
+            reg = regs.gpior;
+            break;
+
+          case RXDP:
+            reg = regs.rxdp;
+            break;
+
+          case RXDP_HI:
+            reg = regs.rxdp_hi;
+            break;
+
+          case RX_CFG:
+            reg = regs.rxcfg;
+            break;
+
+          case PQCR:
+            reg = regs.pqcr;
+            break;
+
+          case WCSR:
+            reg = regs.wcsr;
+            break;
+
+          case PCR:
+            reg = regs.pcr;
+            break;
+
+            // see the spec sheet for how RFCR and RFDR work
+            // basically, you write to RFCR to tell the machine
+            // what you want to do next, then you act upon RFDR,
+            // and the device will be prepared b/c of what you
+            // wrote to RFCR
+          case RFCR:
+            reg = regs.rfcr;
+            break;
+
+          case RFDR:
+            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
+            switch (rfaddr) {
+              // Read from perfect match ROM octets
+              case 0x000:
+                reg = rom.perfectMatch[1];
+                reg = reg << 8;
+                reg += rom.perfectMatch[0];
+                break;
+              case 0x002:
+                reg = rom.perfectMatch[3] << 8;
+                reg += rom.perfectMatch[2];
+                break;
+              case 0x004:
+                reg = rom.perfectMatch[5] << 8;
+                reg += rom.perfectMatch[4];
+                break;
+              default:
+                // 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;
+
+          case SRR:
+            reg = regs.srr;
+            break;
+
+          case MIBC:
+            reg = regs.mibc;
+            reg &= ~(MIBC_MIBS | MIBC_ACLR);
+            break;
+
+          case VRCR:
+            reg = regs.vrcr;
+            break;
+
+          case VTCR:
+            reg = regs.vtcr;
+            break;
+
+          case VDR:
+            reg = regs.vdr;
+            break;
+
+          case CCSR:
+            reg = regs.ccsr;
+            break;
+
+          case TBICR:
+            reg = regs.tbicr;
+            break;
+
+          case TBISR:
+            reg = regs.tbisr;
+            break;
+
+          case TANAR:
+            reg = regs.tanar;
+            break;
+
+          case TANLPAR:
+            reg = regs.tanlpar;
+            break;
+
+          case TANER:
+            reg = regs.taner;
+            break;
+
+          case TESR:
+            reg = regs.tesr;
+            break;
+
+          case M5REG:
+            reg = 0;
+            if (params()->rx_thread)
+                reg |= M5REG_RX_THREAD;
+            if (params()->tx_thread)
+                reg |= M5REG_TX_THREAD;
+            if (params()->rss)
+                reg |= M5REG_RSS;
+            break;
+
+          default:
+            panic("reading unimplemented register: addr=%#x", daddr);
+        }
+
+        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
+                daddr, reg, reg);
+
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+Tick
+NSGigE::write(PacketPtr pkt)
+{
+    assert(ioEnable);
+
+    Addr daddr = pkt->getAddr() & 0xfff;
+    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
+            daddr, pkt->getAddr(), pkt->getSize());
+
+    if (daddr > LAST && daddr <=  RESERVED) {
+        panic("Accessing reserved register");
+    } else if (daddr > RESERVED && daddr <= 0x3FC) {
+        return writeConfig(pkt);
+    } else if (daddr > 0x3FC)
+        panic("Something is messed up!\n");
+
+    if (pkt->getSize() == sizeof(uint32_t)) {
+        uint32_t reg = pkt->get<uint32_t>();
+        uint16_t rfaddr;
+
+        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
+
+        switch (daddr) {
+          case CR:
+            regs.command = reg;
+            if (reg & CR_TXD) {
+                txEnable = false;
+            } else if (reg & CR_TXE) {
+                txEnable = true;
+
+                // 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 (rxState == rxIdle)
+                    rxKick();
+            }
+
+            if (reg & CR_TXR)
+                txReset();
+
+            if (reg & CR_RXR)
+                rxReset();
+
+            if (reg & CR_SWI)
+                devIntrPost(ISR_SWI);
+
+            if (reg & CR_RST) {
+                txReset();
+                rxReset();
+
+                regsReset();
+            }
+            break;
+
+          case 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.
+
+// grouped together and #if 0'ed to avoid empty if body and make clang happy
+#if 0
+            if (reg & CFGR_TBI_EN) ;
+            if (reg & CFGR_MODE_1000) ;
+
+            if (reg & CFGR_PINT_DUPSTS ||
+                reg & CFGR_PINT_LNKSTS ||
+                reg & CFGR_PINT_SPDSTS)
+                ;
+
+            if (reg & CFGR_TMRTEST) ;
+            if (reg & CFGR_MRM_DIS) ;
+            if (reg & CFGR_MWI_DIS) ;
+
+            if (reg & CFGR_DATA64_EN) ;
+            if (reg & CFGR_M64ADDR) ;
+            if (reg & CFGR_PHY_RST) ;
+            if (reg & CFGR_PHY_DIS) ;
+
+            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) ;
+
+            if (reg & CFGR_T64ADDR) ;
+            // panic("CFGR_T64ADDR is read only register!\n");
+#endif
+            if (reg & CFGR_AUTO_1000)
+                panic("CFGR_AUTO_1000 not implemented!\n");
+
+            if (reg & CFGR_PCI64_DET)
+                panic("CFGR_PCI64_DET is read only register!\n");
+
+            if (reg & CFGR_EXTSTS_EN)
+                extstsEnable = true;
+            else
+                extstsEnable = false;
+            break;
+
+          case MEAR:
+            // 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
+
+// grouped together and #if 0'ed to avoid empty if body and make clang happy
+#if 0
+            if (reg & MEAR_MDIO) ;
+            if (reg & MEAR_MDDIR) ;
+            if (reg & MEAR_MDC) ;
+#endif
+            break;
+
+          case PTSCR:
+            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
+            // these control BISTs for various parts of chip - we
+            // don't care or do just fake that the BIST is done
+            if (reg & PTSCR_RBIST_EN)
+                regs.ptscr |= PTSCR_RBIST_DONE;
+            if (reg & PTSCR_EEBIST_EN)
+                regs.ptscr &= ~PTSCR_EEBIST_EN;
+            if (reg & PTSCR_EELOAD_EN)
+                regs.ptscr &= ~PTSCR_EELOAD_EN;
+            break;
+
+          case ISR: /* writing to the ISR has no effect */
+            panic("ISR is a read only register!\n");
+
+          case IMR:
+            regs.imr = reg;
+            devIntrChangeMask();
+            break;
+
+          case IER:
+            regs.ier = reg;
+            break;
+
+          case IHR:
+            regs.ihr = reg;
+            /* not going to implement real interrupt holdoff */
+            break;
+
+          case TXDP:
+            regs.txdp = (reg & 0xFFFFFFFC);
+            assert(txState == txIdle);
+            CTDD = false;
+            break;
+
+          case TXDP_HI:
+            regs.txdp_hi = reg;
+            break;
+
+          case TX_CFG:
+            regs.txcfg = reg;
+#if 0
+            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
+                 * sense to do this
+                 */
+            }
+
+            if (reg & TX_CFG_BRST_DIS) ;
+#endif
+
+#if 0
+            /* we handle our own DMA, ignore the kernel's exhortations */
+            if (reg & TX_CFG_MXDMA) ;
+#endif
+
+            // 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
+
+            break;
+
+          case GPIOR:
+            // 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;
+
+          case RXDP:
+            regs.rxdp = reg;
+            CRDD = false;
+            break;
+
+          case RXDP_HI:
+            regs.rxdp_hi = reg;
+            break;
+
+          case RX_CFG:
+            regs.rxcfg = reg;
+#if 0
+            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 & 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 & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
+#endif
+            break;
+
+          case PQCR:
+            /* there is no priority queueing used in the linux 2.6 driver */
+            regs.pqcr = reg;
+            break;
+
+          case WCSR:
+            /* not going to implement wake on LAN */
+            regs.wcsr = reg;
+            break;
+
+          case PCR:
+            /* not going to implement pause control */
+            regs.pcr = reg;
+            break;
+
+          case RFCR:
+            regs.rfcr = reg;
+
+            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
+            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
+            acceptMulticast = (reg & RFCR_AAM) ? true : false;
+            acceptUnicast = (reg & RFCR_AAU) ? true : false;
+            acceptPerfect = (reg & RFCR_APM) ? true : false;
+            acceptArp = (reg & RFCR_AARP) ? true : false;
+            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
+
+#if 0
+            if (reg & RFCR_APAT)
+                panic("RFCR_APAT not implemented!\n");
+#endif
+            if (reg & RFCR_UHEN)
+                panic("Unicast hash filtering not used by drivers!\n");
+
+            if (reg & RFCR_ULM)
+                panic("RFCR_ULM not implemented!\n");
+
+            break;
+
+          case RFDR:
+            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:
+            regs.brar = reg;
+            break;
+
+          case BRDR:
+            panic("the driver never uses BRDR, something is wrong!\n");
+
+          case SRR:
+            panic("SRR is read only register!\n");
+
+          case MIBC:
+            panic("the driver never uses MIBC, something is wrong!\n");
+
+          case VRCR:
+            regs.vrcr = reg;
+            break;
+
+          case VTCR:
+            regs.vtcr = reg;
+            break;
+
+          case VDR:
+            panic("the driver never uses VDR, something is wrong!\n");
+
+          case CCSR:
+            /* not going to implement clockrun stuff */
+            regs.ccsr = reg;
+            break;
+
+          case TBICR:
+            regs.tbicr = reg;
+            if (reg & TBICR_MR_LOOPBACK)
+                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
+
+            if (reg & TBICR_MR_AN_ENABLE) {
+                regs.tanlpar = regs.tanar;
+                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
+            }
+
+#if 0
+            if (reg & TBICR_MR_RESTART_AN) ;
+#endif
+
+            break;
+
+          case TBISR:
+            panic("TBISR is read only register!\n");
+
+          case TANAR:
+            // 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
+
+            break;
+
+          case TANLPAR:
+            panic("this should only be written to by the fake phy!\n");
+
+          case TANER:
+            panic("TANER is read only register!\n");
+
+          case TESR:
+            regs.tesr = reg;
+            break;
+
+          default:
+            panic("invalid register access daddr=%#x", daddr);
+        }
+    } else {
+        panic("Invalid Request Size");
+    }
+    pkt->makeAtomicResponse();
+    return pioDelay;
+}
+
+void
+NSGigE::devIntrPost(uint32_t interrupts)
+{
+    if (interrupts & ISR_RESERVE)
+        panic("Cannot set a reserved interrupt");
+
+    if (interrupts & ISR_NOIMPL)
+        warn("interrupt not implemented %#x\n", interrupts);
+
+    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) == 0)
+            when += intrDelay;
+        postedInterrupts++;
+        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++;
+    }
+
+    interrupts &= ~ISR_NOIMPL;
+    regs.isr &= ~interrupts;
+
+    DPRINTF(EthernetIntr,
+            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
+            interrupts, regs.isr, regs.imr);
+
+    if (!(regs.isr & regs.imr))
+        cpuIntrClear();
+}
+
+void
+NSGigE::devIntrChangeMask()
+{
+    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
+            regs.isr, regs.imr, regs.isr & regs.imr);
+
+    if (regs.isr & regs.imr)
+        cpuIntrPost(curTick());
+    else
+        cpuIntrClear();
+}
+
+void
+NSGigE::cpuIntrPost(Tick when)
+{
+    // If the interrupt you want to post is later than an interrupt
+    // already scheduled, just let it post in the coming one and don't
+    // schedule another.
+    // HOWEVER, must be sure that the scheduled intrTick is in the
+    // future (this was formerly the source of a bug)
+    /**
+     * @todo this warning should be removed and the intrTick code should
+     * be fixed.
+     */
+    assert(when >= curTick());
+    assert(intrTick >= curTick() || intrTick == 0);
+    if (when > intrTick && intrTick != 0) {
+        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
+                intrTick);
+        return;
+    }
+
+    intrTick = when;
+    if (intrTick < curTick()) {
+        Debug::breakpoint();
+        intrTick = curTick();
+    }
+
+    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
+            intrTick);
+
+    if (intrEvent)
+        intrEvent->squash();
+    intrEvent = new IntrEvent(this, true);
+    schedule(intrEvent, intrTick);
+}
+
+void
+NSGigE::cpuInterrupt()
+{
+    assert(intrTick == curTick());
+
+    // Whether or not there's a pending interrupt, we don't care about
+    // it anymore
+    intrEvent = 0;
+    intrTick = 0;
+
+    // Don't send an interrupt if there's already one
+    if (cpuPendingIntr) {
+        DPRINTF(EthernetIntr,
+                "would send an interrupt now, but there's already pending\n");
+    } else {
+        // Send interrupt
+        cpuPendingIntr = true;
+
+        DPRINTF(EthernetIntr, "posting interrupt\n");
+        intrPost();
+    }
+}
+
+void
+NSGigE::cpuIntrClear()
+{
+    if (!cpuPendingIntr)
+        return;
+
+    if (intrEvent) {
+        intrEvent->squash();
+        intrEvent = 0;
+    }
+
+    intrTick = 0;
+
+    cpuPendingIntr = false;
+
+    DPRINTF(EthernetIntr, "clearing interrupt\n");
+    intrClear();
+}
+
+bool
+NSGigE::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+NSGigE::txReset()
+{
+
+    DPRINTF(Ethernet, "transmit reset\n");
+
+    CTDD = false;
+    txEnable = false;;
+    txFragPtr = 0;
+    assert(txDescCnt == 0);
+    txFifo.clear();
+    txState = txIdle;
+    assert(txDmaState == dmaIdle);
+}
+
+void
+NSGigE::rxReset()
+{
+    DPRINTF(Ethernet, "receive reset\n");
+
+    CRDD = false;
+    assert(rxPktBytes == 0);
+    rxEnable = false;
+    rxFragPtr = 0;
+    assert(rxDescCnt == 0);
+    assert(rxDmaState == dmaIdle);
+    rxFifo.clear();
+    rxState = rxIdle;
+}
+
+void
+NSGigE::regsReset()
+{
+    memset(&regs, 0, sizeof(regs));
+    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
+    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
+    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;
+    acceptMulticast = false;
+    acceptUnicast = false;
+    acceptPerfect = false;
+    acceptArp = false;
+}
+
+bool
+NSGigE::doRxDmaRead()
+{
+    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
+    rxDmaState = dmaReading;
+
+    if (dmaPending() || drainState() != DrainState::Running)
+        rxDmaState = dmaReadWaiting;
+    else
+        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
+
+    return true;
+}
+
+void
+NSGigE::rxDmaReadDone()
+{
+    assert(rxDmaState == dmaReading);
+    rxDmaState = dmaIdle;
+
+    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
+            rxDmaAddr, rxDmaLen);
+    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+
+    // If the transmit state machine has a pending DMA, let it go first
+    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+        txKick();
+
+    rxKick();
+}
+
+bool
+NSGigE::doRxDmaWrite()
+{
+    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
+    rxDmaState = dmaWriting;
+
+    if (dmaPending() || drainState() != DrainState::Running)
+        rxDmaState = dmaWriteWaiting;
+    else
+        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
+    return true;
+}
+
+void
+NSGigE::rxDmaWriteDone()
+{
+    assert(rxDmaState == dmaWriting);
+    rxDmaState = dmaIdle;
+
+    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
+            rxDmaAddr, rxDmaLen);
+    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+
+    // If the transmit state machine has a pending DMA, let it go first
+    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+        txKick();
+
+    rxKick();
+}
+
+void
+NSGigE::rxKick()
+{
+    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
+
+    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 (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 = clockEdge(Cycles(1));
+
+    switch(rxDmaState) {
+      case dmaReadWaiting:
+        if (doRxDmaRead())
+            goto exit;
+        break;
+      case dmaWriteWaiting:
+        if (doRxDmaWrite())
+            goto exit;
+        break;
+      default:
+        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
+    // label "next".  however, if you have intermediate work, like DMA
+    // so that you can't go to the next state yet, you go to exit and
+    // exit the loop.  however, when the DMA is done it will trigger
+    // an event and come back to this loop.
+    switch (rxState) {
+      case rxIdle:
+        if (!rxEnable) {
+            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
+            goto exit;
+        }
+
+        if (CRDD) {
+            rxState = rxDescRefr;
+
+            rxDmaAddr = regs.rxdp & 0x3fffffff;
+            rxDmaData =
+                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
+            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
+            rxDmaFree = dmaDescFree;
+
+            descDmaReads++;
+            descDmaRdBytes += rxDmaLen;
+
+            if (doRxDmaRead())
+                goto exit;
+        } else {
+            rxState = rxDescRead;
+
+            rxDmaAddr = regs.rxdp & 0x3fffffff;
+            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
+            rxDmaFree = dmaDescFree;
+
+            descDmaReads++;
+            descDmaRdBytes += rxDmaLen;
+
+            if (doRxDmaRead())
+                goto exit;
+        }
+        break;
+
+      case rxDescRefr:
+        if (rxDmaState != dmaIdle)
+            goto exit;
+
+        rxState = rxAdvance;
+        break;
+
+     case rxDescRead:
+        if (rxDmaState != dmaIdle)
+            goto exit;
+
+        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
+                regs.rxdp & 0x3fffffff);
+        DPRINTF(EthernetDesc,
+                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+                link, bufptr, cmdsts, extsts);
+
+        if (cmdsts & CMDSTS_OWN) {
+            devIntrPost(ISR_RXIDLE);
+            rxState = rxIdle;
+            goto exit;
+        } else {
+            rxState = rxFifoBlock;
+            rxFragPtr = bufptr;
+            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
+        }
+        break;
+
+      case rxFifoBlock:
+        if (!rxPacket) {
+            /**
+             * @todo in reality, we should be able to start processing
+             * the packet as it arrives, and not have to wait for the
+             * full packet ot be in the receive fifo.
+             */
+            if (rxFifo.empty())
+                goto exit;
+
+            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
+
+            // If we don't have a packet, grab a new one from the fifo.
+            rxPacket = rxFifo.front();
+            rxPktBytes = rxPacket->length;
+            rxPacketBufPtr = rxPacket->data;
+
+#if TRACING_ON
+            if (DTRACE(Ethernet)) {
+                IpPtr ip(rxPacket);
+                if (ip) {
+                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
+                    TcpPtr tcp(ip);
+                    if (tcp) {
+                        DPRINTF(Ethernet,
+                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                                tcp->sport(), tcp->dport(), tcp->seq(),
+                                tcp->ack());
+                    }
+                }
+            }
+#endif
+
+            // sanity check - i think the driver behaves like this
+            assert(rxDescCnt >= rxPktBytes);
+            rxFifo.pop();
+        }
+
+
+        // dont' need the && rxDescCnt > 0 if driver sanity check
+        // above holds
+        if (rxPktBytes > 0) {
+            rxState = rxFragWrite;
+            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
+            // check holds
+            rxXferLen = rxPktBytes;
+
+            rxDmaAddr = rxFragPtr & 0x3fffffff;
+            rxDmaData = rxPacketBufPtr;
+            rxDmaLen = rxXferLen;
+            rxDmaFree = dmaDataFree;
+
+            if (doRxDmaWrite())
+                goto exit;
+
+        } else {
+            rxState = rxDescWrite;
+
+            //if (rxPktBytes == 0) {  /* packet is done */
+            assert(rxPktBytes == 0);
+            DPRINTF(EthernetSM, "done with receiving packet\n");
+
+            cmdsts |= CMDSTS_OWN;
+            cmdsts &= ~CMDSTS_MORE;
+            cmdsts |= CMDSTS_OK;
+            cmdsts &= 0xffff0000;
+            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
+
+#if 0
+            /*
+             * all the driver uses these are for its own stats keeping
+             * which we don't care about, aren't necessary for
+             * functionality and doing this would just slow us down.
+             * if they end up using this in a later version for
+             * functional purposes, just undef
+             */
+            if (rxFilterEnable) {
+                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
+
+            IpPtr ip(rxPacket);
+            if (extstsEnable && ip) {
+                extsts |= EXTSTS_IPPKT;
+                rxIpChecksums++;
+                if (cksum(ip) != 0) {
+                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
+                    extsts |= EXTSTS_IPERR;
+                }
+                TcpPtr tcp(ip);
+                UdpPtr udp(ip);
+                if (tcp) {
+                    extsts |= EXTSTS_TCPPKT;
+                    rxTcpChecksums++;
+                    if (cksum(tcp) != 0) {
+                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
+                        extsts |= EXTSTS_TCPERR;
+
+                    }
+                } else if (udp) {
+                    extsts |= EXTSTS_UDPPKT;
+                    rxUdpChecksums++;
+                    if (cksum(udp) != 0) {
+                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
+                        extsts |= EXTSTS_UDPERR;
+                    }
+                }
+            }
+            rxPacket = 0;
+
+            /*
+             * the driver seems to always receive into desc buffers
+             * of size 1514, so you never have a pkt that is split
+             * into multiple descriptors on the receive side, so
+             * i don't implement that case, hence the assert above.
+             */
+
+            DPRINTF(EthernetDesc,
+                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
+                    regs.rxdp & 0x3fffffff);
+            DPRINTF(EthernetDesc,
+                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
+                    link, bufptr, cmdsts, 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++;
+            descDmaWrBytes += rxDmaLen;
+
+            if (doRxDmaWrite())
+                goto exit;
+        }
+        break;
+
+      case rxFragWrite:
+        if (rxDmaState != dmaIdle)
+            goto exit;
+
+        rxPacketBufPtr += rxXferLen;
+        rxFragPtr += rxXferLen;
+        rxPktBytes -= rxXferLen;
+
+        rxState = rxFifoBlock;
+        break;
+
+      case rxDescWrite:
+        if (rxDmaState != dmaIdle)
+            goto exit;
+
+        assert(cmdsts & CMDSTS_OWN);
+
+        assert(rxPacket == 0);
+        devIntrPost(ISR_RXOK);
+
+        if (cmdsts & CMDSTS_INTR)
+            devIntrPost(ISR_RXDESC);
+
+        if (!rxEnable) {
+            DPRINTF(EthernetSM, "Halting the RX state machine\n");
+            rxState = rxIdle;
+            goto exit;
+        } else
+            rxState = rxAdvance;
+        break;
+
+      case rxAdvance:
+        if (link == 0) {
+            devIntrPost(ISR_RXIDLE);
+            rxState = rxIdle;
+            CRDD = true;
+            goto exit;
+        } else {
+            if (rxDmaState != dmaIdle)
+                goto exit;
+            rxState = rxDescRead;
+            regs.rxdp = link;
+            CRDD = false;
+
+            rxDmaAddr = regs.rxdp & 0x3fffffff;
+            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
+            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
+            rxDmaFree = dmaDescFree;
+
+            if (doRxDmaRead())
+                goto exit;
+        }
+        break;
+
+      default:
+        panic("Invalid rxState!");
+    }
+
+    DPRINTF(EthernetSM, "entering next rxState=%s\n",
+            NsRxStateStrings[rxState]);
+    goto next;
+
+  exit:
+    /**
+     * @todo do we want to schedule a future kick?
+     */
+    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
+            NsRxStateStrings[rxState]);
+
+    if (!rxKickEvent.scheduled())
+        schedule(rxKickEvent, rxKickTick);
+}
+
+void
+NSGigE::transmit()
+{
+    if (txFifo.empty()) {
+        DPRINTF(Ethernet, "nothing to transmit\n");
+        return;
+    }
+
+    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
+            txFifo.size());
+    if (interface->sendPacket(txFifo.front())) {
+#if TRACING_ON
+        if (DTRACE(Ethernet)) {
+            IpPtr ip(txFifo.front());
+            if (ip) {
+                DPRINTF(Ethernet, "ID is %d\n", ip->id());
+                TcpPtr tcp(ip);
+                if (tcp) {
+                    DPRINTF(Ethernet,
+                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                            tcp->sport(), tcp->dport(), tcp->seq(),
+                            tcp->ack());
+                }
+            }
+        }
+#endif
+
+        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
+        txBytes += txFifo.front()->length;
+        txPackets++;
+
+        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
+                txFifo.avail());
+        txFifo.pop();
+
+        /*
+         * normally do a writeback of the descriptor here, and ONLY
+         * after that is done, send this interrupt.  but since our
+         * stuff never actually fails, just do this interrupt here,
+         * otherwise the code has to stray from this nice format.
+         * besides, it's functionally the same.
+         */
+        devIntrPost(ISR_TXOK);
+    }
+
+   if (!txFifo.empty() && !txEvent.scheduled()) {
+       DPRINTF(Ethernet, "reschedule transmit\n");
+       schedule(txEvent, curTick() + retryTime);
+   }
+}
+
+bool
+NSGigE::doTxDmaRead()
+{
+    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
+    txDmaState = dmaReading;
+
+    if (dmaPending() || drainState() != DrainState::Running)
+        txDmaState = dmaReadWaiting;
+    else
+        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
+
+    return true;
+}
+
+void
+NSGigE::txDmaReadDone()
+{
+    assert(txDmaState == dmaReading);
+    txDmaState = dmaIdle;
+
+    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
+            txDmaAddr, txDmaLen);
+    DDUMP(EthernetDMA, txDmaData, txDmaLen);
+
+    // If the receive state machine  has a pending DMA, let it go first
+    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+        rxKick();
+
+    txKick();
+}
+
+bool
+NSGigE::doTxDmaWrite()
+{
+    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
+    txDmaState = dmaWriting;
+
+    if (dmaPending() || drainState() != DrainState::Running)
+        txDmaState = dmaWriteWaiting;
+    else
+        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
+    return true;
+}
+
+void
+NSGigE::txDmaWriteDone()
+{
+    assert(txDmaState == dmaWriting);
+    txDmaState = dmaIdle;
+
+    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
+            txDmaAddr, txDmaLen);
+    DDUMP(EthernetDMA, txDmaData, txDmaLen);
+
+    // If the receive state machine  has a pending DMA, let it go first
+    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+        rxKick();
+
+    txKick();
+}
+
+void
+NSGigE::txKick()
+{
+    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
+
+    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
+            NsTxStateStrings[txState], is64bit ? 64 : 32);
+
+    Addr link, bufptr;
+    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
+    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
+
+  next:
+    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 = clockEdge(Cycles(1));
+
+    switch(txDmaState) {
+      case dmaReadWaiting:
+        if (doTxDmaRead())
+            goto exit;
+        break;
+      case dmaWriteWaiting:
+        if (doTxDmaWrite())
+            goto exit;
+        break;
+      default:
+        break;
+    }
+
+    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
+    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
+    switch (txState) {
+      case txIdle:
+        if (!txEnable) {
+            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
+            goto exit;
+        }
+
+        if (CTDD) {
+            txState = txDescRefr;
+
+            txDmaAddr = regs.txdp & 0x3fffffff;
+            txDmaData =
+                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
+            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
+            txDmaFree = dmaDescFree;
+
+            descDmaReads++;
+            descDmaRdBytes += txDmaLen;
+
+            if (doTxDmaRead())
+                goto exit;
+
+        } else {
+            txState = txDescRead;
+
+            txDmaAddr = regs.txdp & 0x3fffffff;
+            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
+            txDmaFree = dmaDescFree;
+
+            descDmaReads++;
+            descDmaRdBytes += txDmaLen;
+
+            if (doTxDmaRead())
+                goto exit;
+        }
+        break;
+
+      case txDescRefr:
+        if (txDmaState != dmaIdle)
+            goto exit;
+
+        txState = txAdvance;
+        break;
+
+      case txDescRead:
+        if (txDmaState != dmaIdle)
+            goto exit;
+
+        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
+                regs.txdp & 0x3fffffff);
+        DPRINTF(EthernetDesc,
+                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
+                link, bufptr, cmdsts, extsts);
+
+        if (cmdsts & CMDSTS_OWN) {
+            txState = txFifoBlock;
+            txFragPtr = bufptr;
+            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
+        } else {
+            devIntrPost(ISR_TXIDLE);
+            txState = txIdle;
+            goto exit;
+        }
+        break;
+
+      case txFifoBlock:
+        if (!txPacket) {
+            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
+            txPacket = make_shared<EthPacketData>(16384);
+            txPacketBufPtr = txPacket->data;
+        }
+
+        if (txDescCnt == 0) {
+            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
+            if (cmdsts & CMDSTS_MORE) {
+                DPRINTF(EthernetSM, "there are more descriptors to come\n");
+                txState = txDescWrite;
+
+                cmdsts &= ~CMDSTS_OWN;
+
+                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())
+                    goto exit;
+
+            } else { /* this packet is totally done */
+                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) {
+                    IpPtr ip(txPacket);
+                    if (extsts & EXTSTS_UDPPKT) {
+                        UdpPtr udp(ip);
+                        if (udp) {
+                            udp->sum(0);
+                            udp->sum(cksum(udp));
+                            txUdpChecksums++;
+                        } else {
+                            Debug::breakpoint();
+                            warn_once("UDPPKT set, but not UDP!\n");
+                        }
+                    } else if (extsts & EXTSTS_TCPPKT) {
+                        TcpPtr tcp(ip);
+                        if (tcp) {
+                            tcp->sum(0);
+                            tcp->sum(cksum(tcp));
+                            txTcpChecksums++;
+                        } else {
+                            Debug::breakpoint();
+                            warn_once("TCPPKT set, but not UDP!\n");
+                        }
+                    }
+                    if (extsts & EXTSTS_IPPKT) {
+                        if (ip) {
+                            ip->sum(0);
+                            ip->sum(cksum(ip));
+                            txIpChecksums++;
+                        } else {
+                            Debug::breakpoint();
+                            warn_once("IPPKT set, but not UDP!\n");
+                        }
+                    }
+                }
+
+                txPacket->length = txPacketBufPtr - txPacket->data;
+                // this is just because the receive can't handle a
+                // packet bigger want to make sure
+                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
+                 * functionally shouldn't be any different.  normally,
+                 * the chip will wait til the transmit has occurred
+                 * before writing back the descriptor because it has
+                 * to wait to see that it was successfully transmitted
+                 * to decide whether to set CMDSTS_OK or not.
+                 * however, in the simulator since it is always
+                 * successfully transmitted, and writing it exactly to
+                 * spec would complicate the code, we just do it here
+                 */
+
+                cmdsts &= ~CMDSTS_OWN;
+                cmdsts |= CMDSTS_OK;
+
+                DPRINTF(EthernetDesc,
+                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
+                        cmdsts, 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;
+
+                transmit();
+                txPacket = 0;
+
+                if (!txEnable) {
+                    DPRINTF(EthernetSM, "halting TX state machine\n");
+                    txState = txIdle;
+                    goto exit;
+                } else
+                    txState = txAdvance;
+
+                if (doTxDmaWrite())
+                    goto exit;
+            }
+        } else {
+            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
+            if (!txFifo.full()) {
+                txState = txFragRead;
+
+                /*
+                 * The number of bytes transferred is either whatever
+                 * is left in the descriptor (txDescCnt), or if there
+                 * is not enough room in the fifo, just whatever room
+                 * is left in the fifo
+                 */
+                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
+
+                txDmaAddr = txFragPtr & 0x3fffffff;
+                txDmaData = txPacketBufPtr;
+                txDmaLen = txXferLen;
+                txDmaFree = dmaDataFree;
+
+                if (doTxDmaRead())
+                    goto exit;
+            } else {
+                txState = txFifoBlock;
+                transmit();
+
+                goto exit;
+            }
+
+        }
+        break;
+
+      case txFragRead:
+        if (txDmaState != dmaIdle)
+            goto exit;
+
+        txPacketBufPtr += txXferLen;
+        txFragPtr += txXferLen;
+        txDescCnt -= txXferLen;
+        txFifo.reserve(txXferLen);
+
+        txState = txFifoBlock;
+        break;
+
+      case txDescWrite:
+        if (txDmaState != dmaIdle)
+            goto exit;
+
+        if (cmdsts & CMDSTS_INTR)
+            devIntrPost(ISR_TXDESC);
+
+        if (!txEnable) {
+            DPRINTF(EthernetSM, "halting TX state machine\n");
+            txState = txIdle;
+            goto exit;
+        } else
+            txState = txAdvance;
+        break;
+
+      case txAdvance:
+        if (link == 0) {
+            devIntrPost(ISR_TXIDLE);
+            txState = txIdle;
+            goto exit;
+        } else {
+            if (txDmaState != dmaIdle)
+                goto exit;
+            txState = txDescRead;
+            regs.txdp = link;
+            CTDD = false;
+
+            txDmaAddr = link & 0x3fffffff;
+            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
+            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
+            txDmaFree = dmaDescFree;
+
+            if (doTxDmaRead())
+                goto exit;
+        }
+        break;
+
+      default:
+        panic("invalid state");
+    }
+
+    DPRINTF(EthernetSM, "entering next txState=%s\n",
+            NsTxStateStrings[txState]);
+    goto next;
+
+  exit:
+    /**
+     * @todo do we want to schedule a future kick?
+     */
+    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
+            NsTxStateStrings[txState]);
+
+    if (!txKickEvent.scheduled())
+        schedule(txKickEvent, 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
+NSGigE::transferDone()
+{
+    if (txFifo.empty()) {
+        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
+        return;
+    }
+
+    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
+
+    reschedule(txEvent, clockEdge(Cycles(1)), true);
+}
+
+bool
+NSGigE::rxFilter(const EthPacketPtr &packet)
+{
+    EthPtr eth = packet;
+    bool drop = true;
+    string type;
+
+    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 && dst == rom.perfectMatch)
+            drop = false;
+
+        if (acceptArp && eth->type() == ETH_TYPE_ARP)
+            drop = false;
+
+    } else if (dst.broadcast()) {
+        // if we're accepting broadcasts
+        if (acceptBroadcast)
+            drop = false;
+
+    } 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) {
+        DPRINTF(Ethernet, "rxFilter drop\n");
+        DDUMP(EthernetData, packet->data, packet->length);
+    }
+
+    return drop;
+}
+
+bool
+NSGigE::recvPacket(EthPacketPtr packet)
+{
+    rxBytes += packet->length;
+    rxPackets++;
+
+    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
+            rxFifo.avail());
+
+    if (!rxEnable) {
+        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+        return true;
+    }
+
+    if (!rxFilterEnable) {
+        DPRINTF(Ethernet,
+            "receive packet filtering disabled . . . packet dropped\n");
+        return true;
+    }
+
+    if (rxFilter(packet)) {
+        DPRINTF(Ethernet, "packet filtered...dropped\n");
+        return true;
+    }
+
+    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(packet);
+
+    rxKick();
+    return true;
+}
+
+
+void
+NSGigE::drainResume()
+{
+    Drainable::drainResume();
+
+    // During drain we could have left the state machines in a waiting state and
+    // they wouldn't get out until some other event occured to kick them.
+    // This way they'll get out immediately
+    txKick();
+    rxKick();
+}
+
+
+//=====================================================================
+//
+//
+void
+NSGigE::serialize(CheckpointOut &cp) const
+{
+    // Serialize the PciDevice base class
+    PciDevice::serialize(cp);
+
+    /*
+     * Finalize any DMA events now.
+     */
+    // @todo will mem system save pending dma?
+
+    /*
+     * Serialize the device registers
+     */
+    SERIALIZE_SCALAR(regs.command);
+    SERIALIZE_SCALAR(regs.config);
+    SERIALIZE_SCALAR(regs.mear);
+    SERIALIZE_SCALAR(regs.ptscr);
+    SERIALIZE_SCALAR(regs.isr);
+    SERIALIZE_SCALAR(regs.imr);
+    SERIALIZE_SCALAR(regs.ier);
+    SERIALIZE_SCALAR(regs.ihr);
+    SERIALIZE_SCALAR(regs.txdp);
+    SERIALIZE_SCALAR(regs.txdp_hi);
+    SERIALIZE_SCALAR(regs.txcfg);
+    SERIALIZE_SCALAR(regs.gpior);
+    SERIALIZE_SCALAR(regs.rxdp);
+    SERIALIZE_SCALAR(regs.rxdp_hi);
+    SERIALIZE_SCALAR(regs.rxcfg);
+    SERIALIZE_SCALAR(regs.pqcr);
+    SERIALIZE_SCALAR(regs.wcsr);
+    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);
+    SERIALIZE_SCALAR(regs.vtcr);
+    SERIALIZE_SCALAR(regs.vdr);
+    SERIALIZE_SCALAR(regs.ccsr);
+    SERIALIZE_SCALAR(regs.tbicr);
+    SERIALIZE_SCALAR(regs.tbisr);
+    SERIALIZE_SCALAR(regs.tanar);
+    SERIALIZE_SCALAR(regs.tanlpar);
+    SERIALIZE_SCALAR(regs.taner);
+    SERIALIZE_SCALAR(regs.tesr);
+
+    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
+
+    SERIALIZE_SCALAR(ioEnable);
+
+    /*
+     * Serialize the data Fifos
+     */
+    rxFifo.serialize("rxFifo", cp);
+    txFifo.serialize("txFifo", cp);
+
+    /*
+     * Serialize the various helper variables
+     */
+    bool txPacketExists = txPacket != nullptr;
+    SERIALIZE_SCALAR(txPacketExists);
+    if (txPacketExists) {
+        txPacket->length = txPacketBufPtr - txPacket->data;
+        txPacket->serialize("txPacket", cp);
+        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
+        SERIALIZE_SCALAR(txPktBufPtr);
+    }
+
+    bool rxPacketExists = rxPacket != nullptr;
+    SERIALIZE_SCALAR(rxPacketExists);
+    if (rxPacketExists) {
+        rxPacket->serialize("rxPacket", cp);
+        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
+        SERIALIZE_SCALAR(rxPktBufPtr);
+    }
+
+    SERIALIZE_SCALAR(txXferLen);
+    SERIALIZE_SCALAR(rxXferLen);
+
+    /*
+     * Serialize Cached Descriptors
+     */
+    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
+     */
+    int txState = this->txState;
+    SERIALIZE_SCALAR(txState);
+    SERIALIZE_SCALAR(txEnable);
+    SERIALIZE_SCALAR(CTDD);
+    SERIALIZE_SCALAR(txFragPtr);
+    SERIALIZE_SCALAR(txDescCnt);
+    int txDmaState = this->txDmaState;
+    SERIALIZE_SCALAR(txDmaState);
+    SERIALIZE_SCALAR(txKickTick);
+
+    /*
+     * Serialize rx state machine
+     */
+    int rxState = this->rxState;
+    SERIALIZE_SCALAR(rxState);
+    SERIALIZE_SCALAR(rxEnable);
+    SERIALIZE_SCALAR(CRDD);
+    SERIALIZE_SCALAR(rxPktBytes);
+    SERIALIZE_SCALAR(rxFragPtr);
+    SERIALIZE_SCALAR(rxDescCnt);
+    int rxDmaState = this->rxDmaState;
+    SERIALIZE_SCALAR(rxDmaState);
+    SERIALIZE_SCALAR(rxKickTick);
+
+    /*
+     * 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
+     * reschedule it later
+     */
+    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
+    SERIALIZE_SCALAR(transmitTick);
+
+    /*
+     * receive address filter settings
+     */
+    SERIALIZE_SCALAR(rxFilterEnable);
+    SERIALIZE_SCALAR(acceptBroadcast);
+    SERIALIZE_SCALAR(acceptMulticast);
+    SERIALIZE_SCALAR(acceptUnicast);
+    SERIALIZE_SCALAR(acceptPerfect);
+    SERIALIZE_SCALAR(acceptArp);
+    SERIALIZE_SCALAR(multicastHashEnable);
+
+    /*
+     * Keep track of pending interrupt status.
+     */
+    SERIALIZE_SCALAR(intrTick);
+    SERIALIZE_SCALAR(cpuPendingIntr);
+    Tick intrEventTick = 0;
+    if (intrEvent)
+        intrEventTick = intrEvent->when();
+    SERIALIZE_SCALAR(intrEventTick);
+
+}
+
+void
+NSGigE::unserialize(CheckpointIn &cp)
+{
+    // Unserialize the PciDevice base class
+    PciDevice::unserialize(cp);
+
+    UNSERIALIZE_SCALAR(regs.command);
+    UNSERIALIZE_SCALAR(regs.config);
+    UNSERIALIZE_SCALAR(regs.mear);
+    UNSERIALIZE_SCALAR(regs.ptscr);
+    UNSERIALIZE_SCALAR(regs.isr);
+    UNSERIALIZE_SCALAR(regs.imr);
+    UNSERIALIZE_SCALAR(regs.ier);
+    UNSERIALIZE_SCALAR(regs.ihr);
+    UNSERIALIZE_SCALAR(regs.txdp);
+    UNSERIALIZE_SCALAR(regs.txdp_hi);
+    UNSERIALIZE_SCALAR(regs.txcfg);
+    UNSERIALIZE_SCALAR(regs.gpior);
+    UNSERIALIZE_SCALAR(regs.rxdp);
+    UNSERIALIZE_SCALAR(regs.rxdp_hi);
+    UNSERIALIZE_SCALAR(regs.rxcfg);
+    UNSERIALIZE_SCALAR(regs.pqcr);
+    UNSERIALIZE_SCALAR(regs.wcsr);
+    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);
+    UNSERIALIZE_SCALAR(regs.vtcr);
+    UNSERIALIZE_SCALAR(regs.vdr);
+    UNSERIALIZE_SCALAR(regs.ccsr);
+    UNSERIALIZE_SCALAR(regs.tbicr);
+    UNSERIALIZE_SCALAR(regs.tbisr);
+    UNSERIALIZE_SCALAR(regs.tanar);
+    UNSERIALIZE_SCALAR(regs.tanlpar);
+    UNSERIALIZE_SCALAR(regs.taner);
+    UNSERIALIZE_SCALAR(regs.tesr);
+
+    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
+    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
+
+    UNSERIALIZE_SCALAR(ioEnable);
+
+    /*
+     * unserialize the data fifos
+     */
+    rxFifo.unserialize("rxFifo", cp);
+    txFifo.unserialize("txFifo", cp);
+
+    /*
+     * unserialize the various helper variables
+     */
+    bool txPacketExists;
+    UNSERIALIZE_SCALAR(txPacketExists);
+    if (txPacketExists) {
+        txPacket = make_shared<EthPacketData>(16384);
+        txPacket->unserialize("txPacket", cp);
+        uint32_t txPktBufPtr;
+        UNSERIALIZE_SCALAR(txPktBufPtr);
+        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
+    } else
+        txPacket = 0;
+
+    bool rxPacketExists;
+    UNSERIALIZE_SCALAR(rxPacketExists);
+    rxPacket = 0;
+    if (rxPacketExists) {
+        rxPacket = make_shared<EthPacketData>(16384);
+        rxPacket->unserialize("rxPacket", cp);
+        uint32_t rxPktBufPtr;
+        UNSERIALIZE_SCALAR(rxPktBufPtr);
+        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
+    } else
+        rxPacket = 0;
+
+    UNSERIALIZE_SCALAR(txXferLen);
+    UNSERIALIZE_SCALAR(rxXferLen);
+
+    /*
+     * Unserialize Cached Descriptors
+     */
+    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
+     */
+    int txState;
+    UNSERIALIZE_SCALAR(txState);
+    this->txState = (TxState) txState;
+    UNSERIALIZE_SCALAR(txEnable);
+    UNSERIALIZE_SCALAR(CTDD);
+    UNSERIALIZE_SCALAR(txFragPtr);
+    UNSERIALIZE_SCALAR(txDescCnt);
+    int txDmaState;
+    UNSERIALIZE_SCALAR(txDmaState);
+    this->txDmaState = (DmaState) txDmaState;
+    UNSERIALIZE_SCALAR(txKickTick);
+    if (txKickTick)
+        schedule(txKickEvent, txKickTick);
+
+    /*
+     * unserialize rx state machine
+     */
+    int rxState;
+    UNSERIALIZE_SCALAR(rxState);
+    this->rxState = (RxState) rxState;
+    UNSERIALIZE_SCALAR(rxEnable);
+    UNSERIALIZE_SCALAR(CRDD);
+    UNSERIALIZE_SCALAR(rxPktBytes);
+    UNSERIALIZE_SCALAR(rxFragPtr);
+    UNSERIALIZE_SCALAR(rxDescCnt);
+    int rxDmaState;
+    UNSERIALIZE_SCALAR(rxDmaState);
+    this->rxDmaState = (DmaState) rxDmaState;
+    UNSERIALIZE_SCALAR(rxKickTick);
+    if (rxKickTick)
+        schedule(rxKickEvent, rxKickTick);
+
+    /*
+     * 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;
+    UNSERIALIZE_SCALAR(transmitTick);
+    if (transmitTick)
+        schedule(txEvent, curTick() + transmitTick);
+
+    /*
+     * unserialize receive address filter settings
+     */
+    UNSERIALIZE_SCALAR(rxFilterEnable);
+    UNSERIALIZE_SCALAR(acceptBroadcast);
+    UNSERIALIZE_SCALAR(acceptMulticast);
+    UNSERIALIZE_SCALAR(acceptUnicast);
+    UNSERIALIZE_SCALAR(acceptPerfect);
+    UNSERIALIZE_SCALAR(acceptArp);
+    UNSERIALIZE_SCALAR(multicastHashEnable);
+
+    /*
+     * Keep track of pending interrupt status.
+     */
+    UNSERIALIZE_SCALAR(intrTick);
+    UNSERIALIZE_SCALAR(cpuPendingIntr);
+    Tick intrEventTick;
+    UNSERIALIZE_SCALAR(intrEventTick);
+    if (intrEventTick) {
+        intrEvent = new IntrEvent(this, true);
+        schedule(intrEvent, intrEventTick);
+    }
+}
+
+NSGigE *
+NSGigEParams::create()
+{
+    return new NSGigE(this);
+}
diff --git a/src/dev/net/ns_gige.hh b/src/dev/net/ns_gige.hh
new file mode 100644 (file)
index 0000000..096b2b6
--- /dev/null
@@ -0,0 +1,392 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ *          Lisa Hsu
+ */
+
+/** @file
+ * Device module for modelling the National Semiconductor
+ * DP83820 ethernet controller
+ */
+
+#ifndef __DEV_NET_NS_GIGE_HH__
+#define __DEV_NET_NS_GIGE_HH__
+
+#include "base/inet.hh"
+#include "dev/io_device.hh"
+#include "dev/net/etherdevice.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+#include "dev/net/ns_gige_reg.h"
+#include "dev/net/pktfifo.hh"
+#include "params/NSGigE.hh"
+#include "sim/eventq.hh"
+
+// Hash filtering constants
+const uint16_t FHASH_ADDR  = 0x100;
+const uint16_t FHASH_SIZE  = 0x100;
+
+// EEPROM constants
+const uint8_t  EEPROM_READ = 0x2;
+const uint8_t  EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM
+const uint8_t  EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2
+const uint8_t  EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1
+const uint8_t  EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0
+
+/**
+ * Ethernet device registers
+ */
+struct dp_regs {
+    uint32_t    command;
+    uint32_t    config;
+    uint32_t    mear;
+    uint32_t    ptscr;
+    uint32_t    isr;
+    uint32_t    imr;
+    uint32_t    ier;
+    uint32_t    ihr;
+    uint32_t    txdp;
+    uint32_t    txdp_hi;
+    uint32_t    txcfg;
+    uint32_t    gpior;
+    uint32_t    rxdp;
+    uint32_t    rxdp_hi;
+    uint32_t    rxcfg;
+    uint32_t    pqcr;
+    uint32_t    wcsr;
+    uint32_t    pcr;
+    uint32_t    rfcr;
+    uint32_t    rfdr;
+    uint32_t    brar;
+    uint32_t    brdr;
+    uint32_t    srr;
+    uint32_t    mibc;
+    uint32_t    vrcr;
+    uint32_t    vtcr;
+    uint32_t    vdr;
+    uint32_t    ccsr;
+    uint32_t    tbicr;
+    uint32_t    tbisr;
+    uint32_t    tanar;
+    uint32_t    tanlpar;
+    uint32_t    taner;
+    uint32_t    tesr;
+};
+
+struct dp_rom {
+    /**
+     * for perfect match memory.
+     * the linux driver doesn't use any other ROM
+     */
+    uint8_t perfectMatch[ETH_ADDR_LEN];
+
+    /**
+     * for hash table memory.
+     * used by the freebsd driver
+     */
+    uint8_t filterHash[FHASH_SIZE];
+};
+
+class NSGigEInt;
+class Packet;
+
+/**
+ * NS DP83820 Ethernet device model
+ */
+class NSGigE : public EtherDevBase
+{
+  public:
+    /** Transmit State Machine states */
+    enum TxState
+    {
+        txIdle,
+        txDescRefr,
+        txDescRead,
+        txFifoBlock,
+        txFragRead,
+        txDescWrite,
+        txAdvance
+    };
+
+    /** Receive State Machine States */
+    enum RxState
+    {
+        rxIdle,
+        rxDescRefr,
+        rxDescRead,
+        rxFifoBlock,
+        rxFragWrite,
+        rxDescWrite,
+        rxAdvance
+    };
+
+    enum DmaState
+    {
+        dmaIdle,
+        dmaReading,
+        dmaWriting,
+        dmaReadWaiting,
+        dmaWriteWaiting
+    };
+
+    /** EEPROM State Machine States */
+    enum EEPROMState
+    {
+        eepromStart,
+        eepromGetOpcode,
+        eepromGetAddress,
+        eepromRead
+    };
+
+  protected:
+    /** device register file */
+    dp_regs regs;
+    dp_rom rom;
+
+    /** pci settings */
+    bool ioEnable;
+#if 0
+    bool memEnable;
+    bool bmEnable;
+#endif
+
+    /*** BASIC STRUCTURES FOR TX/RX ***/
+    /* Data FIFOs */
+    PacketFifo txFifo;
+    PacketFifo rxFifo;
+
+    /** various helper vars */
+    EthPacketPtr txPacket;
+    EthPacketPtr rxPacket;
+    uint8_t *txPacketBufPtr;
+    uint8_t *rxPacketBufPtr;
+    uint32_t txXferLen;
+    uint32_t rxXferLen;
+    bool rxDmaFree;
+    bool txDmaFree;
+
+    /** DescCaches */
+    ns_desc32 txDesc32;
+    ns_desc32 rxDesc32;
+    ns_desc64 txDesc64;
+    ns_desc64 rxDesc64;
+
+    /* tx State Machine */
+    TxState txState;
+    bool txEnable;
+
+    /** Current Transmit Descriptor Done */
+    bool CTDD;
+    /** halt the tx state machine after next packet */
+    bool txHalt;
+    /** ptr to the next byte in the current fragment */
+    Addr txFragPtr;
+    /** count of bytes remaining in the current descriptor */
+    uint32_t txDescCnt;
+    DmaState txDmaState;
+
+    /** rx State Machine */
+    RxState rxState;
+    bool rxEnable;
+
+    /** Current Receive Descriptor Done */
+    bool CRDD;
+    /** num of bytes in the current packet being drained from rxDataFifo */
+    uint32_t rxPktBytes;
+    /** halt the rx state machine after current packet */
+    bool rxHalt;
+    /** ptr to the next byte in current fragment */
+    Addr rxFragPtr;
+    /** count of bytes remaining in the current descriptor */
+    uint32_t rxDescCnt;
+    DmaState rxDmaState;
+
+    bool extstsEnable;
+
+    /** EEPROM State Machine */
+    EEPROMState eepromState;
+    bool eepromClk;
+    uint8_t eepromBitsToRx;
+    uint8_t eepromOpcode;
+    uint8_t eepromAddress;
+    uint16_t eepromData;
+
+  protected:
+    Tick dmaReadDelay;
+    Tick dmaWriteDelay;
+
+    Tick dmaReadFactor;
+    Tick dmaWriteFactor;
+
+    void *rxDmaData;
+    Addr  rxDmaAddr;
+    int   rxDmaLen;
+    bool  doRxDmaRead();
+    bool  doRxDmaWrite();
+
+    void *txDmaData;
+    Addr  txDmaAddr;
+    int   txDmaLen;
+    bool  doTxDmaRead();
+    bool  doTxDmaWrite();
+
+    void rxDmaReadDone();
+    friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>;
+    EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent;
+
+    void rxDmaWriteDone();
+    friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>;
+    EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent;
+
+    void txDmaReadDone();
+    friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>;
+    EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent;
+
+    void txDmaWriteDone();
+    friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>;
+    EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent;
+
+    bool dmaDescFree;
+    bool dmaDataFree;
+
+  protected:
+    Tick txDelay;
+    Tick rxDelay;
+
+    void txReset();
+    void rxReset();
+    void regsReset();
+
+    void rxKick();
+    Tick rxKickTick;
+    typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent;
+    friend void RxKickEvent::process();
+    RxKickEvent rxKickEvent;
+
+    void txKick();
+    Tick txKickTick;
+    typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent;
+    friend void TxKickEvent::process();
+    TxKickEvent txKickEvent;
+
+    void eepromKick();
+
+    /**
+     * Retransmit event
+     */
+    void transmit();
+    void txEventTransmit()
+    {
+        transmit();
+        if (txState == txFifoBlock)
+            txKick();
+    }
+    typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent;
+    friend void TxEvent::process();
+    TxEvent txEvent;
+
+    void txDump() const;
+    void rxDump() const;
+
+    /**
+     * receive address filter
+     */
+    bool rxFilterEnable;
+    bool rxFilter(const EthPacketPtr &packet);
+    bool acceptBroadcast;
+    bool acceptMulticast;
+    bool acceptUnicast;
+    bool acceptPerfect;
+    bool acceptArp;
+    bool multicastHashEnable;
+
+    /**
+     * Interrupt management
+     */
+    void devIntrPost(uint32_t interrupts);
+    void devIntrClear(uint32_t interrupts);
+    void devIntrChangeMask();
+
+    Tick intrDelay;
+    Tick intrTick;
+    bool cpuPendingIntr;
+    void cpuIntrPost(Tick when);
+    void cpuInterrupt();
+    void cpuIntrClear();
+
+    typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent;
+    friend void IntrEvent::process();
+    IntrEvent *intrEvent;
+    NSGigEInt *interface;
+
+  public:
+    typedef NSGigEParams Params;
+    const Params *params() const {
+        return dynamic_cast<const Params *>(_params);
+    }
+
+    NSGigE(Params *params);
+    ~NSGigE();
+
+    EtherInt *getEthPort(const std::string &if_name, int idx) override;
+
+    Tick writeConfig(PacketPtr pkt) override;
+
+    Tick read(PacketPtr pkt) override;
+    Tick write(PacketPtr pkt) override;
+
+    bool cpuIntrPending() const;
+    void cpuIntrAck() { cpuIntrClear(); }
+
+    bool recvPacket(EthPacketPtr packet);
+    void transferDone();
+
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+    void drainResume() override;
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class NSGigEInt : public EtherInt
+{
+  private:
+    NSGigE *dev;
+
+  public:
+    NSGigEInt(const std::string &name, NSGigE *d)
+        : EtherInt(name), dev(d)
+    { }
+
+    virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
+    virtual void sendDone() { dev->transferDone(); }
+};
+
+#endif // __DEV_NET_NS_GIGE_HH__
diff --git a/src/dev/net/ns_gige_reg.h b/src/dev/net/ns_gige_reg.h
new file mode 100644 (file)
index 0000000..c37c06a
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Lisa Hsu
+ */
+
+/** @file
+ * Ethernet device register definitions for the National
+ * Semiconductor DP83820 Ethernet controller
+ */
+
+#ifndef __DEV_NS_GIGE_REG_H__
+#define __DEV_NS_GIGE_REG_H__
+
+/* Device Register Address Map */
+enum DeviceRegisterAddress {
+    CR =                0x00,
+    CFGR =              0x04,
+    MEAR =              0x08,
+    PTSCR =             0x0c,
+    ISR =               0x10,
+    IMR =               0x14,
+    IER =               0x18,
+    IHR =               0x1c,
+    TXDP =              0x20,
+    TXDP_HI =           0x24,
+    TX_CFG =            0x28,
+    GPIOR =             0x2c,
+    RXDP =              0x30,
+    RXDP_HI =           0x34,
+    RX_CFG =            0x38,
+    PQCR =              0x3c,
+    WCSR =              0x40,
+    PCR =               0x44,
+    RFCR =              0x48,
+    RFDR =              0x4c,
+    BRAR =              0x50,
+    BRDR =              0x54,
+    SRR =               0x58,
+    MIBC =              0x5c,
+    MIB_START =         0x60,
+    MIB_END =           0x88,
+    VRCR =              0xbc,
+    VTCR =              0xc0,
+    VDR =               0xc4,
+    CCSR =              0xcc,
+    TBICR =             0xe0,
+    TBISR =             0xe4,
+    TANAR =             0xe8,
+    TANLPAR =           0xec,
+    TANER =             0xf0,
+    TESR =              0xf4,
+    M5REG =             0xf8,
+    LAST =              0xf8,
+    RESERVED =          0xfc
+};
+
+/* Chip Command Register */
+enum ChipCommandRegister {
+     CR_TXE =           0x00000001,
+     CR_TXD =           0x00000002,
+     CR_RXE =           0x00000004,
+     CR_RXD =           0x00000008,
+     CR_TXR =           0x00000010,
+     CR_RXR =           0x00000020,
+     CR_SWI =           0x00000080,
+     CR_RST =           0x00000100
+};
+
+/* configuration register */
+enum ConfigurationRegisters {
+     CFGR_LNKSTS =      0x80000000,
+     CFGR_SPDSTS =      0x60000000,
+     CFGR_SPDSTS1 =     0x40000000,
+     CFGR_SPDSTS0 =     0x20000000,
+     CFGR_DUPSTS =      0x10000000,
+     CFGR_TBI_EN =      0x01000000,
+     CFGR_RESERVED =    0x0e000000,
+     CFGR_MODE_1000 =   0x00400000,
+     CFGR_AUTO_1000 =   0x00200000,
+     CFGR_PINT_CTL =    0x001c0000,
+     CFGR_PINT_DUPSTS = 0x00100000,
+     CFGR_PINT_LNKSTS = 0x00080000,
+     CFGR_PINT_SPDSTS = 0x00040000,
+     CFGR_TMRTEST =     0x00020000,
+     CFGR_MRM_DIS =     0x00010000,
+     CFGR_MWI_DIS =     0x00008000,
+     CFGR_T64ADDR =     0x00004000,
+     CFGR_PCI64_DET =   0x00002000,
+     CFGR_DATA64_EN =   0x00001000,
+     CFGR_M64ADDR =     0x00000800,
+     CFGR_PHY_RST =     0x00000400,
+     CFGR_PHY_DIS =     0x00000200,
+     CFGR_EXTSTS_EN =   0x00000100,
+     CFGR_REQALG =      0x00000080,
+     CFGR_SB =          0x00000040,
+     CFGR_POW =         0x00000020,
+     CFGR_EXD =         0x00000010,
+     CFGR_PESEL =       0x00000008,
+     CFGR_BROM_DIS =    0x00000004,
+     CFGR_EXT_125 =     0x00000002,
+     CFGR_BEM =         0x00000001
+};
+
+/* EEPROM access register */
+enum EEPROMAccessRegister {
+     MEAR_EEDI =        0x00000001,
+     MEAR_EEDO =        0x00000002,
+     MEAR_EECLK =       0x00000004,
+     MEAR_EESEL =       0x00000008,
+     MEAR_MDIO =        0x00000010,
+     MEAR_MDDIR =       0x00000020,
+     MEAR_MDC =         0x00000040,
+};
+
+/* PCI test control register */
+enum PCITestControlRegister {
+     PTSCR_EEBIST_FAIL =        0x00000001,
+     PTSCR_EEBIST_EN =          0x00000002,
+     PTSCR_EELOAD_EN =          0x00000004,
+     PTSCR_RBIST_FAIL =         0x000001b8,
+     PTSCR_RBIST_DONE =         0x00000200,
+     PTSCR_RBIST_EN =           0x00000400,
+     PTSCR_RBIST_RST =          0x00002000,
+     PTSCR_RBIST_RDONLY =       0x000003f9
+};
+
+/* interrupt status register */
+enum InterruptStatusRegister {
+     ISR_RESERVE =      0x80000000,
+     ISR_TXDESC3 =      0x40000000,
+     ISR_TXDESC2 =      0x20000000,
+     ISR_TXDESC1 =      0x10000000,
+     ISR_TXDESC0 =      0x08000000,
+     ISR_RXDESC3 =      0x04000000,
+     ISR_RXDESC2 =      0x02000000,
+     ISR_RXDESC1 =      0x01000000,
+     ISR_RXDESC0 =      0x00800000,
+     ISR_TXRCMP =       0x00400000,
+     ISR_RXRCMP =       0x00200000,
+     ISR_DPERR =        0x00100000,
+     ISR_SSERR =        0x00080000,
+     ISR_RMABT =        0x00040000,
+     ISR_RTAB =         0x00020000,
+     ISR_RXSOVR =       0x00010000,
+     ISR_HIBINT =       0x00008000,
+     ISR_PHY =          0x00004000,
+     ISR_PME =          0x00002000,
+     ISR_SWI =          0x00001000,
+     ISR_MIB =          0x00000800,
+     ISR_TXURN =        0x00000400,
+     ISR_TXIDLE =       0x00000200,
+     ISR_TXERR =        0x00000100,
+     ISR_TXDESC =       0x00000080,
+     ISR_TXOK =         0x00000040,
+     ISR_RXORN =        0x00000020,
+     ISR_RXIDLE =       0x00000010,
+     ISR_RXEARLY =      0x00000008,
+     ISR_RXERR =        0x00000004,
+     ISR_RXDESC =       0x00000002,
+     ISR_RXOK =         0x00000001,
+     ISR_ALL =          0x7FFFFFFF,
+     ISR_DELAY =        (ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|
+                         ISR_RXIDLE|ISR_RXDESC|ISR_RXOK),
+     ISR_NODELAY =      (ISR_ALL & ~ISR_DELAY),
+     ISR_IMPL =         (ISR_SWI|ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|ISR_RXORN|
+                         ISR_RXIDLE|ISR_RXDESC|ISR_RXOK),
+     ISR_NOIMPL =       (ISR_ALL & ~ISR_IMPL)
+};
+
+/* transmit configuration register */
+enum TransmitConfigurationRegister {
+     TX_CFG_CSI =       0x80000000,
+     TX_CFG_HBI =       0x40000000,
+     TX_CFG_MLB =       0x20000000,
+     TX_CFG_ATP =       0x10000000,
+     TX_CFG_ECRETRY =   0x00800000,
+     TX_CFG_BRST_DIS =  0x00080000,
+     TX_CFG_MXDMA1024 = 0x00000000,
+     TX_CFG_MXDMA512 =  0x00700000,
+     TX_CFG_MXDMA256 =  0x00600000,
+     TX_CFG_MXDMA128 =  0x00500000,
+     TX_CFG_MXDMA64 =   0x00400000,
+     TX_CFG_MXDMA32 =   0x00300000,
+     TX_CFG_MXDMA16 =   0x00200000,
+     TX_CFG_MXDMA8 =    0x00100000,
+     TX_CFG_MXDMA =     0x00700000,
+
+     TX_CFG_FLTH_MASK = 0x0000ff00,
+     TX_CFG_DRTH_MASK = 0x000000ff
+};
+
+/*general purpose I/O control register */
+enum GeneralPurposeIOControlRegister {
+     GPIOR_UNUSED =     0xffff8000,
+     GPIOR_GP5_IN =     0x00004000,
+     GPIOR_GP4_IN =     0x00002000,
+     GPIOR_GP3_IN =     0x00001000,
+     GPIOR_GP2_IN =     0x00000800,
+     GPIOR_GP1_IN =     0x00000400,
+     GPIOR_GP5_OE =     0x00000200,
+     GPIOR_GP4_OE =     0x00000100,
+     GPIOR_GP3_OE =     0x00000080,
+     GPIOR_GP2_OE =     0x00000040,
+     GPIOR_GP1_OE =     0x00000020,
+     GPIOR_GP5_OUT =    0x00000010,
+     GPIOR_GP4_OUT =    0x00000008,
+     GPIOR_GP3_OUT =    0x00000004,
+     GPIOR_GP2_OUT =    0x00000002,
+     GPIOR_GP1_OUT =    0x00000001
+};
+
+/* receive configuration register */
+enum ReceiveConfigurationRegister {
+     RX_CFG_AEP =       0x80000000,
+     RX_CFG_ARP =       0x40000000,
+     RX_CFG_STRIPCRC =  0x20000000,
+     RX_CFG_RX_FD =     0x10000000,
+     RX_CFG_ALP =       0x08000000,
+     RX_CFG_AIRL =      0x04000000,
+     RX_CFG_MXDMA512 =  0x00700000,
+     RX_CFG_MXDMA =     0x00700000,
+     RX_CFG_DRTH =      0x0000003e,
+     RX_CFG_DRTH0 =     0x00000002
+};
+
+/* pause control status register */
+enum PauseControlStatusRegister {
+     PCR_PSEN =         (1 << 31),
+     PCR_PS_MCAST =     (1 << 30),
+     PCR_PS_DA =        (1 << 29),
+     PCR_STHI_8 =       (3 << 23),
+     PCR_STLO_4 =       (1 << 23),
+     PCR_FFHI_8K =      (3 << 21),
+     PCR_FFLO_4K =      (1 << 21),
+     PCR_PAUSE_CNT =    0xFFFE
+};
+
+/*receive filter/match control register */
+enum ReceiveFilterMatchControlRegister {
+     RFCR_RFEN =        0x80000000,
+     RFCR_AAB =         0x40000000,
+     RFCR_AAM =         0x20000000,
+     RFCR_AAU =         0x10000000,
+     RFCR_APM =         0x08000000,
+     RFCR_APAT =        0x07800000,
+     RFCR_APAT3 =       0x04000000,
+     RFCR_APAT2 =       0x02000000,
+     RFCR_APAT1 =       0x01000000,
+     RFCR_APAT0 =       0x00800000,
+     RFCR_AARP =        0x00400000,
+     RFCR_MHEN =        0x00200000,
+     RFCR_UHEN =        0x00100000,
+     RFCR_ULM =         0x00080000,
+     RFCR_RFADDR =      0x000003ff
+};
+
+/* receive filter/match data register */
+enum ReceiveFilterMatchDataRegister {
+     RFDR_BMASK =       0x00030000,
+     RFDR_RFDATA0 =     0x000000ff,
+     RFDR_RFDATA1 =     0x0000ff00
+};
+
+/* management information base control register */
+enum ManagementInformationBaseControlRegister {
+     MIBC_MIBS =        0x00000008,
+     MIBC_ACLR =        0x00000004,
+     MIBC_FRZ =         0x00000002,
+     MIBC_WRN =         0x00000001
+};
+
+/* VLAN/IP receive control register */
+enum VLANIPReceiveControlRegister {
+     VRCR_RUDPE =       0x00000080,
+     VRCR_RTCPE =       0x00000040,
+     VRCR_RIPE =        0x00000020,
+     VRCR_IPEN =        0x00000010,
+     VRCR_DUTF =        0x00000008,
+     VRCR_DVTF =        0x00000004,
+     VRCR_VTREN =       0x00000002,
+     VRCR_VTDEN =       0x00000001
+};
+
+/* VLAN/IP transmit control register */
+enum VLANIPTransmitControlRegister {
+     VTCR_PPCHK =       0x00000008,
+     VTCR_GCHK =        0x00000004,
+     VTCR_VPPTI =       0x00000002,
+     VTCR_VGTI =        0x00000001
+};
+
+/* Clockrun Control/Status Register */
+enum ClockrunControlStatusRegister {
+     CCSR_CLKRUN_EN =   0x00000001
+};
+
+/* TBI control register */
+enum TBIControlRegister {
+     TBICR_MR_LOOPBACK =        0x00004000,
+     TBICR_MR_AN_ENABLE =       0x00001000,
+     TBICR_MR_RESTART_AN =      0x00000200
+};
+
+/* TBI status register */
+enum TBIStatusRegister {
+     TBISR_MR_LINK_STATUS =     0x00000020,
+     TBISR_MR_AN_COMPLETE =     0x00000004
+};
+
+/* TBI auto-negotiation advertisement register */
+enum TBIAutoNegotiationAdvertisementRegister {
+     TANAR_NP =         0x00008000,
+     TANAR_RF2 =        0x00002000,
+     TANAR_RF1 =        0x00001000,
+     TANAR_PS2 =        0x00000100,
+     TANAR_PS1 =        0x00000080,
+     TANAR_HALF_DUP =   0x00000040,
+     TANAR_FULL_DUP =   0x00000020,
+     TANAR_UNUSED =     0x00000E1F
+};
+
+/* M5 control register */
+enum M5ControlRegister {
+     M5REG_RESERVED =   0xfffffffc,
+     M5REG_RSS =        0x00000004,
+     M5REG_RX_THREAD =  0x00000002,
+     M5REG_TX_THREAD =  0x00000001
+};
+
+struct ns_desc32 {
+    uint32_t link;    /* link field to next descriptor in linked list */
+    uint32_t bufptr;  /* pointer to the first fragment or buffer */
+    uint32_t cmdsts;  /* command/status field */
+    uint32_t extsts;  /* extended status field for VLAN and IP info */
+};
+
+struct ns_desc64 {
+    uint64_t link;    /* link field to next descriptor in linked list */
+    uint64_t bufptr;  /* pointer to the first fragment or buffer */
+    uint32_t cmdsts;  /* command/status field */
+    uint32_t extsts;  /* extended status field for VLAN and IP info */
+};
+
+/* cmdsts flags for descriptors */
+enum CMDSTSFlatsForDescriptors {
+     CMDSTS_OWN =       0x80000000,
+     CMDSTS_MORE =      0x40000000,
+     CMDSTS_INTR =      0x20000000,
+     CMDSTS_ERR =       0x10000000,
+     CMDSTS_OK =        0x08000000,
+     CMDSTS_LEN_MASK =  0x0000ffff,
+
+     CMDSTS_DEST_MASK = 0x01800000,
+     CMDSTS_DEST_SELF = 0x00800000,
+     CMDSTS_DEST_MULTI = 0x01000000
+};
+
+/* extended flags for descriptors */
+enum ExtendedFlagsForDescriptors {
+     EXTSTS_UDPERR =    0x00400000,
+     EXTSTS_UDPPKT =    0x00200000,
+     EXTSTS_TCPERR =    0x00100000,
+     EXTSTS_TCPPKT =    0x00080000,
+     EXTSTS_IPERR =     0x00040000,
+     EXTSTS_IPPKT =     0x00020000
+};
+
+/* speed status */
+static inline int
+SPDSTS_POLARITY(int lnksts)
+{
+    return (CFGR_SPDSTS1 | CFGR_SPDSTS0 | CFGR_DUPSTS |
+            (lnksts ? CFGR_LNKSTS : 0));
+}
+
+#endif /* __DEV_NS_GIGE_REG_H__ */
diff --git a/src/dev/net/pktfifo.cc b/src/dev/net/pktfifo.cc
new file mode 100644 (file)
index 0000000..af4dbf4
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include "dev/net/pktfifo.hh"
+
+#include "base/misc.hh"
+
+using namespace std;
+
+bool
+PacketFifo::copyout(void *dest, unsigned offset, unsigned len)
+{
+    char *data = (char *)dest;
+    if (offset + len >= size())
+        return false;
+
+    iterator i = fifo.begin();
+    iterator end = fifo.end();
+    while (len > 0) {
+        EthPacketPtr &pkt = i->packet;
+        while (offset >= pkt->length) {
+            offset -= pkt->length;
+            ++i;
+        }
+
+        if (i == end)
+            panic("invalid fifo");
+
+        unsigned size = min(pkt->length - offset, len);
+        memcpy(data, pkt->data, size);
+        offset = 0;
+        len -= size;
+        data += size;
+        ++i;
+    }
+
+    return true;
+}
+
+
+void
+PacketFifoEntry::serialize(const string &base, CheckpointOut &cp) const
+{
+    packet->serialize(base + ".packet", cp);
+    paramOut(cp, base + ".slack", slack);
+    paramOut(cp, base + ".number", number);
+    paramOut(cp, base + ".priv", priv);
+}
+
+void
+PacketFifoEntry::unserialize(const string &base, CheckpointIn &cp)
+{
+    packet = make_shared<EthPacketData>(16384);
+    packet->unserialize(base + ".packet", cp);
+    paramIn(cp, base + ".slack", slack);
+    paramIn(cp, base + ".number", number);
+    paramIn(cp, base + ".priv", priv);
+}
+
+void
+PacketFifo::serialize(const string &base, CheckpointOut &cp) const
+{
+    paramOut(cp, base + ".size", _size);
+    paramOut(cp, base + ".maxsize", _maxsize);
+    paramOut(cp, base + ".reserved", _reserved);
+    paramOut(cp, base + ".packets", fifo.size());
+
+    int i = 0;
+    for (const auto &entry : fifo)
+        entry.serialize(csprintf("%s.entry%d", base, i++), cp);
+}
+
+void
+PacketFifo::unserialize(const string &base, CheckpointIn &cp)
+{
+    paramIn(cp, base + ".size", _size);
+//  paramIn(cp, base + ".maxsize", _maxsize);
+    paramIn(cp, base + ".reserved", _reserved);
+    int fifosize;
+    paramIn(cp, base + ".packets", fifosize);
+
+    fifo.clear();
+
+    for (int i = 0; i < fifosize; ++i) {
+        PacketFifoEntry entry;
+        entry.unserialize(csprintf("%s.entry%d", base, i), cp);
+        fifo.push_back(entry);
+    }
+}
diff --git a/src/dev/net/pktfifo.hh b/src/dev/net/pktfifo.hh
new file mode 100644 (file)
index 0000000..5ef7542
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __DEV_NET_PKTFIFO_HH__
+#define __DEV_NET_PKTFIFO_HH__
+
+#include <iosfwd>
+#include <list>
+#include <string>
+
+#include "base/misc.hh"
+#include "dev/net/etherpkt.hh"
+#include "sim/serialize.hh"
+
+class Checkpoint;
+
+struct PacketFifoEntry
+{
+    EthPacketPtr packet;
+    uint64_t number;
+    unsigned slack;
+    int priv;
+
+    PacketFifoEntry()
+    {
+        clear();
+    }
+
+    PacketFifoEntry(const PacketFifoEntry &s)
+        : packet(s.packet), number(s.number), slack(s.slack), priv(s.priv)
+    {
+    }
+
+    PacketFifoEntry(EthPacketPtr p, uint64_t n)
+        : packet(p), number(n), slack(0), priv(-1)
+    {
+    }
+
+    void clear()
+    {
+        packet = NULL;
+        number = 0;
+        slack = 0;
+        priv = -1;
+    }
+
+    void serialize(const std::string &base, CheckpointOut &cp) const;
+    void unserialize(const std::string &base, CheckpointIn &cp);
+};
+
+class PacketFifo
+{
+  public:
+
+    typedef std::list<PacketFifoEntry> fifo_list;
+    typedef fifo_list::iterator iterator;
+    typedef fifo_list::const_iterator const_iterator;
+
+  protected:
+    std::list<PacketFifoEntry> fifo;
+    uint64_t _counter;
+    unsigned _maxsize;
+    unsigned _size;
+    unsigned _reserved;
+
+  public:
+    explicit PacketFifo(int max)
+        : _counter(0), _maxsize(max), _size(0), _reserved(0) {}
+    virtual ~PacketFifo() {}
+
+    unsigned packets() const { return fifo.size(); }
+    unsigned maxsize() const { return _maxsize; }
+    unsigned size() const { return _size; }
+    unsigned reserved() const { return _reserved; }
+    unsigned avail() const { return _maxsize - _size - _reserved; }
+    bool empty() const { return size() <= 0; }
+    bool full() const { return avail() <= 0; }
+
+    unsigned
+    reserve(unsigned len = 0)
+    {
+        _reserved += len;
+        assert(avail() >= 0);
+        return _reserved;
+    }
+
+    iterator begin() { return fifo.begin(); }
+    iterator end() { return fifo.end(); }
+
+    const_iterator begin() const { return fifo.begin(); }
+    const_iterator end() const { return fifo.end(); }
+
+    EthPacketPtr front() { return fifo.begin()->packet; }
+
+    bool push(EthPacketPtr ptr)
+    {
+        assert(ptr->length);
+        assert(_reserved <= ptr->length);
+        if (avail() < ptr->length - _reserved)
+            return false;
+
+        _size += ptr->length;
+
+        PacketFifoEntry entry;
+        entry.packet = ptr;
+        entry.number = _counter++;
+        fifo.push_back(entry);
+        _reserved = 0;
+        return true;
+    }
+
+    void pop()
+    {
+        if (empty())
+            return;
+
+        iterator entry = fifo.begin();
+        _size -= entry->packet->length;
+        _size -= entry->slack;
+        entry->packet = NULL;
+        fifo.pop_front();
+    }
+
+    void clear()
+    {
+        for (iterator i = begin(); i != end(); ++i)
+            i->clear();
+        fifo.clear();
+        _size = 0;
+        _reserved = 0;
+    }
+
+    void remove(iterator i)
+    {
+        if (i != fifo.begin()) {
+            iterator prev = i;
+            --prev;
+            assert(prev != fifo.end());
+            prev->slack += i->packet->length;
+            prev->slack += i->slack;
+        } else {
+            _size -= i->packet->length;
+            _size -= i->slack;
+        }
+
+        i->clear();
+        fifo.erase(i);
+    }
+
+    bool copyout(void *dest, unsigned offset, unsigned len);
+
+    int countPacketsBefore(const_iterator i) const
+    {
+        if (i == fifo.end())
+            return 0;
+        return i->number - fifo.begin()->number;
+    }
+
+    int countPacketsAfter(const_iterator i) const
+    {
+        auto end = fifo.end();
+        if (i == end)
+            return 0;
+        return (--end)->number - i->number;
+    }
+
+    void check() const
+    {
+        unsigned total = 0;
+        for (auto i = begin(); i != end(); ++i)
+            total += i->packet->length + i->slack;
+
+        if (total != _size)
+            panic("total (%d) is not == to size (%d)\n", total, _size);
+    }
+
+/**
+ * Serialization stuff
+ */
+  public:
+    void serialize(const std::string &base, CheckpointOut &cp) const;
+    void unserialize(const std::string &base, CheckpointIn &cp);
+};
+
+#endif // __DEV_NET_PKTFIFO_HH__
diff --git a/src/dev/net/sinic.cc b/src/dev/net/sinic.cc
new file mode 100644 (file)
index 0000000..d0adb10
--- /dev/null
@@ -0,0 +1,1563 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#include "dev/net/sinic.hh"
+
+#include <deque>
+#include <limits>
+#include <string>
+
+#ifdef SINIC_VTOPHYS
+#include "arch/vtophys.hh"
+
+#endif
+#include "base/compiler.hh"
+#include "base/debug.hh"
+#include "base/inet.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
+#include "debug/EthernetAll.hh"
+#include "dev/net/etherlink.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "sim/eventq.hh"
+#include "sim/stats.hh"
+
+using namespace std;
+using namespace Net;
+using namespace TheISA;
+
+namespace Sinic {
+
+const char *RxStateStrings[] =
+{
+    "rxIdle",
+    "rxFifoBlock",
+    "rxBeginCopy",
+    "rxCopy",
+    "rxCopyDone"
+};
+
+const char *TxStateStrings[] =
+{
+    "txIdle",
+    "txFifoBlock",
+    "txBeginCopy",
+    "txCopy",
+    "txCopyDone"
+};
+
+
+///////////////////////////////////////////////////////////////////////
+//
+// Sinic PCI Device
+//
+Base::Base(const Params *p)
+    : EtherDevBase(p), rxEnable(false), txEnable(false),
+      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
+      cpuPendingIntr(false), intrEvent(0), interface(NULL)
+{
+}
+
+Device::Device(const Params *p)
+    : Base(p), rxUnique(0), txUnique(0),
+      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
+      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
+      rxKickTick(0), txKickTick(0),
+      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
+      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
+      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
+{
+    interface = new Interface(name() + ".int0", this);
+    reset();
+
+}
+
+Device::~Device()
+{}
+
+void
+Device::regStats()
+{
+    Base::regStats();
+
+    _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()
+{
+    Base::resetStats();
+
+    _maxVnicDistance = 0;
+}
+
+EtherInt*
+Device::getEthPort(const std::string &if_name, int idx)
+{
+    if (if_name == "interface") {
+        if (interface->getPeer())
+            panic("interface already connected to\n");
+
+        return interface;
+    }
+    return NULL;
+}
+
+
+void
+Device::prepareIO(ContextID cpu, int index)
+{
+    int size = virtualRegs.size();
+    if (index > size)
+        panic("Trying to access a vnic that doesn't exist %d > %d\n",
+              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(ContextID cpu, int index)
+{
+    using namespace Regs;
+    prepareIO(cpu, index);
+
+    VirtualReg &vnic = virtualRegs[index];
+
+    // update rx registers
+    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.RxFifoHigh);
+    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
+    regs.RxData = vnic.RxData;
+    regs.RxDone = rxdone;
+    regs.RxWait = rxdone;
+
+    // update tx regsiters
+    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.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
+Device::prepareWrite(ContextID cpu, int index)
+{
+    prepareIO(cpu, index);
+}
+
+/**
+ * I/O read of device register
+ */
+Tick
+Device::read(PacketPtr pkt)
+{
+    assert(config.command & PCI_CMD_MSE);
+    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
+
+    ContextID cpu = pkt->req->contextId();
+    Addr daddr = pkt->getAddr() - BARAddrs[0];
+    Addr index = daddr >> Regs::VirtualShift;
+    Addr raddr = daddr & Regs::VirtualMask;
+
+    if (!regValid(raddr))
+        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
+
+    const Regs::Info &info = regInfo(raddr);
+    if (!info.read)
+        panic("read %s (write only): "
+              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
+
+        panic("read %s (invalid size): "
+              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
+
+    prepareRead(cpu, index);
+
+    uint64_t value M5_VAR_USED = 0;
+    if (pkt->getSize() == 4) {
+        uint32_t reg = regData32(raddr);
+        pkt->set(reg);
+        value = reg;
+    }
+
+    if (pkt->getSize() == 8) {
+        uint64_t reg = regData64(raddr);
+        pkt->set(reg);
+        value = reg;
+    }
+
+    DPRINTF(EthernetPIO,
+            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
+            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
+
+    // reading the interrupt status register has the side effect of
+    // clearing it
+    if (raddr == Regs::IntrStatus)
+        devIntrClear();
+
+    return pioDelay;
+}
+
+/**
+ * IPR read of device register
+
+    Fault
+Device::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
+{
+    if (!regValid(daddr))
+        panic("invalid address: da=%#x", daddr);
+
+    const Regs::Info &info = regInfo(daddr);
+    if (!info.read)
+        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
+
+    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
+            info.name, cpu, daddr);
+
+    prepareRead(cpu, 0);
+
+    if (info.size == 4)
+        result = regData32(daddr);
+
+    if (info.size == 8)
+        result = regData64(daddr);
+
+    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
+            info.name, cpu, result);
+
+    return NoFault;
+}
+*/
+/**
+ * I/O write of device register
+ */
+Tick
+Device::write(PacketPtr pkt)
+{
+    assert(config.command & PCI_CMD_MSE);
+    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
+
+    ContextID cpu = pkt->req->contextId();
+    Addr daddr = pkt->getAddr() - BARAddrs[0];
+    Addr index = daddr >> Regs::VirtualShift;
+    Addr raddr = daddr & Regs::VirtualMask;
+
+    if (!regValid(raddr))
+        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
+                cpu, daddr, pkt->getAddr(), pkt->getSize());
+
+    const Regs::Info &info = regInfo(raddr);
+    if (!info.write)
+        panic("write %s (read only): "
+              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
+
+    if (pkt->getSize() != info.size)
+        panic("write %s (invalid size): "
+              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
+
+    VirtualReg &vnic = virtualRegs[index];
+
+    DPRINTF(EthernetPIO,
+            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
+            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
+            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
+
+    prepareWrite(cpu, index);
+
+    switch (raddr) {
+      case Regs::Config:
+        changeConfig(pkt->get<uint32_t>());
+        break;
+
+      case Regs::Command:
+        command(pkt->get<uint32_t>());
+        break;
+
+      case Regs::IntrStatus:
+        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
+        break;
+
+      case Regs::IntrMask:
+        devIntrChangeMask(pkt->get<uint32_t>());
+        break;
+
+      case Regs::RxData:
+        if (Regs::get_RxDone_Busy(vnic.RxDone))
+            panic("receive machine busy with another request! rxState=%s",
+                  RxStateStrings[rxState]);
+
+        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");
+#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);
+#endif
+        } else {
+            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
+                    index, vnic.rxUnique);
+        }
+
+        if (vnic.rxIndex == rxFifo.end()) {
+            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
+            rxList.push_back(index);
+        } else {
+            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
+            rxBusy.push_back(index);
+        }
+
+        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
+            rxState = rxFifoBlock;
+            rxKick();
+        }
+        break;
+
+      case Regs::TxData:
+        if (Regs::get_TxDone_Busy(vnic.TxDone))
+            panic("transmit machine busy with another request! txState=%s",
+                  TxStateStrings[txState]);
+
+        vnic.txUnique = txUnique++;
+        vnic.TxDone = Regs::TxDone_Busy;
+
+        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
+            panic("vtophys won't work here in newmem.\n");
+#ifdef SINIC_VTOPHYS
+            Addr vaddr = Regs::get_TxData_Addr(reg64);
+            Addr paddr = vtophys(req->xc, vaddr);
+            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);
+#endif
+        } else {
+            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
+                    index, vnic.txUnique);
+        }
+
+        if (txList.empty() || txList.front() != index)
+            txList.push_back(index);
+        if (txEnable && txState == txIdle && txList.front() == index) {
+            txState = txFifoBlock;
+            txKick();
+        }
+        break;
+    }
+
+    return pioDelay;
+}
+
+void
+Device::devIntrPost(uint32_t interrupts)
+{
+    if ((interrupts & Regs::Intr_Res))
+        panic("Cannot set a reserved interrupt");
+
+    regs.IntrStatus |= interrupts;
+
+    DPRINTF(EthernetIntr,
+            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
+            interrupts, regs.IntrStatus, regs.IntrMask);
+
+    interrupts = regs.IntrStatus & regs.IntrMask;
+
+    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
+    // and then filled it above the high watermark
+    if (rxEmpty)
+        rxEmpty = false;
+    else
+        interrupts &= ~Regs::Intr_RxHigh;
+
+    // Intr_TxLow is special, we only signal it if we've filled up the fifo
+    // and then dropped below the low watermark
+    if (txFull)
+        txFull = false;
+    else
+        interrupts &= ~Regs::Intr_TxLow;
+
+    if (interrupts) {
+        Tick when = curTick();
+        if ((interrupts & Regs::Intr_NoDelay) == 0)
+            when += intrDelay;
+        cpuIntrPost(when);
+    }
+}
+
+void
+Device::devIntrClear(uint32_t interrupts)
+{
+    if ((interrupts & Regs::Intr_Res))
+        panic("Cannot clear a reserved interrupt");
+
+    regs.IntrStatus &= ~interrupts;
+
+    DPRINTF(EthernetIntr,
+            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
+            interrupts, regs.IntrStatus, regs.IntrMask);
+
+    if (!(regs.IntrStatus & regs.IntrMask))
+        cpuIntrClear();
+}
+
+void
+Device::devIntrChangeMask(uint32_t newmask)
+{
+    if (regs.IntrMask == newmask)
+        return;
+
+    regs.IntrMask = newmask;
+
+    DPRINTF(EthernetIntr,
+            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
+            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
+
+    if (regs.IntrStatus & regs.IntrMask)
+        cpuIntrPost(curTick());
+    else
+        cpuIntrClear();
+}
+
+void
+Base::cpuIntrPost(Tick when)
+{
+    // If the interrupt you want to post is later than an interrupt
+    // already scheduled, just let it post in the coming one and don't
+    // schedule another.
+    // HOWEVER, must be sure that the scheduled intrTick is in the
+    // future (this was formerly the source of a bug)
+    /**
+     * @todo this warning should be removed and the intrTick code should
+     * be fixed.
+     */
+    assert(when >= curTick());
+    assert(intrTick >= curTick() || intrTick == 0);
+    if (!cpuIntrEnable) {
+        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
+                intrTick);
+        return;
+    }
+
+    if (when > intrTick && intrTick != 0) {
+        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
+                intrTick);
+        return;
+    }
+
+    intrTick = when;
+    if (intrTick < curTick()) {
+        Debug::breakpoint();
+        intrTick = curTick();
+    }
+
+    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
+            intrTick);
+
+    if (intrEvent)
+        intrEvent->squash();
+    intrEvent = new IntrEvent(this, true);
+    schedule(intrEvent, intrTick);
+}
+
+void
+Base::cpuInterrupt()
+{
+    assert(intrTick == curTick());
+
+    // Whether or not there's a pending interrupt, we don't care about
+    // it anymore
+    intrEvent = 0;
+    intrTick = 0;
+
+    // Don't send an interrupt if there's already one
+    if (cpuPendingIntr) {
+        DPRINTF(EthernetIntr,
+                "would send an interrupt now, but there's already pending\n");
+    } else {
+        // Send interrupt
+        cpuPendingIntr = true;
+
+        DPRINTF(EthernetIntr, "posting interrupt\n");
+        intrPost();
+    }
+}
+
+void
+Base::cpuIntrClear()
+{
+    if (!cpuPendingIntr)
+        return;
+
+    if (intrEvent) {
+        intrEvent->squash();
+        intrEvent = 0;
+    }
+
+    intrTick = 0;
+
+    cpuPendingIntr = false;
+
+    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
+    intrClear();
+}
+
+bool
+Base::cpuIntrPending() const
+{ return cpuPendingIntr; }
+
+void
+Device::changeConfig(uint32_t newconf)
+{
+    uint32_t changed = regs.Config ^ newconf;
+    if (!changed)
+        return;
+
+    regs.Config = newconf;
+
+    if ((changed & Regs::Config_IntEn)) {
+        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
+        if (cpuIntrEnable) {
+            if (regs.IntrStatus & regs.IntrMask)
+                cpuIntrPost(curTick());
+        } else {
+            cpuIntrClear();
+        }
+    }
+
+    if ((changed & Regs::Config_TxEn)) {
+        txEnable = regs.Config & Regs::Config_TxEn;
+        if (txEnable)
+            txKick();
+    }
+
+    if ((changed & Regs::Config_RxEn)) {
+        rxEnable = regs.Config & Regs::Config_RxEn;
+        if (rxEnable)
+            rxKick();
+    }
+}
+
+void
+Device::command(uint32_t command)
+{
+    if (command & Regs::Command_Intr)
+        devIntrPost(Regs::Intr_Soft);
+
+    if (command & Regs::Command_Reset)
+        reset();
+}
+
+void
+Device::reset()
+{
+    using namespace Regs;
+
+    memset(&regs, 0, sizeof(regs));
+
+    regs.Config = 0;
+    if (params()->rx_thread)
+        regs.Config |= Config_RxThread;
+    if (params()->tx_thread)
+        regs.Config |= Config_TxThread;
+    if (params()->rss)
+        regs.Config |= Config_RSS;
+    if (params()->zero_copy)
+        regs.Config |= Config_ZeroCopy;
+    if (params()->delay_copy)
+        regs.Config |= Config_DelayCopy;
+    if (params()->virtual_addr)
+        regs.Config |= Config_Vaddr;
+
+    if (params()->delay_copy && params()->zero_copy)
+        panic("Can't delay copy and zero copy");
+
+    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
+    regs.RxMaxCopy = params()->rx_max_copy;
+    regs.TxMaxCopy = params()->tx_max_copy;
+    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.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;
+
+    rxFifo.clear();
+    rxFifoPtr = rxFifo.end();
+    txFifo.clear();
+    rxEmpty = false;
+    rxLow = true;
+    txFull = false;
+
+    int size = virtualRegs.size();
+    virtualRegs.clear();
+    virtualRegs.resize(size);
+    for (int i = 0; i < size; ++i)
+        virtualRegs[i].rxIndex = rxFifo.end();
+}
+
+void
+Device::rxDmaDone()
+{
+    assert(rxState == rxCopy);
+    rxState = rxCopyDone;
+    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
+            rxDmaAddr, rxDmaLen);
+    DDUMP(EthernetData, rxDmaData, rxDmaLen);
+
+    // If the transmit state machine  has a pending DMA, let it go first
+    if (txState == txBeginCopy)
+        txKick();
+
+    rxKick();
+}
+
+void
+Device::rxKick()
+{
+    VirtualReg *vnic = NULL;
+
+    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
+            RxStateStrings[rxState], rxFifo.size());
+
+    if (rxKickTick > curTick()) {
+        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
+                rxKickTick);
+        return;
+    }
+
+  next:
+    rxFifo.check();
+    if (rxState == rxIdle)
+        goto exit;
+
+    if (rxActive == -1) {
+        if (rxState != rxFifoBlock)
+            panic("no active vnic while in state %s", RxStateStrings[rxState]);
+
+        DPRINTF(EthernetSM, "processing rxState=%s\n",
+                RxStateStrings[rxState]);
+    } else {
+        vnic = &virtualRegs[rxActive];
+        DPRINTF(EthernetSM,
+                "processing rxState=%s for vnic %d (rxunique %d)\n",
+                RxStateStrings[rxState], rxActive, vnic->rxUnique);
+    }
+
+    switch (rxState) {
+      case rxFifoBlock:
+        if (DTRACE(EthernetSM)) {
+            PacketFifo::iterator end = rxFifo.end();
+            int size = virtualRegs.size();
+            for (int i = 0; i < size; ++i) {
+                VirtualReg *vn = &virtualRegs[i];
+                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
+                if (vn->rxIndex != end) {
+#ifndef NDEBUG
+                    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 %s (rxunique %d), packet %d, slack %d\n",
+                            i, status, vn->rxUnique,
+                            rxFifo.countPacketsBefore(vn->rxIndex),
+                            vn->rxIndex->slack);
+#endif
+                } else if (busy) {
+                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
+                            i, vn->rxUnique);
+                }
+            }
+        }
+
+        if (!rxBusy.empty()) {
+            rxActive = rxBusy.front();
+            rxBusy.pop_front();
+            vnic = &virtualRegs[rxActive];
+
+            if (vnic->rxIndex == rxFifo.end())
+                panic("continuing vnic without packet\n");
+
+            DPRINTF(EthernetSM,
+                    "continue processing for vnic %d (rxunique %d)\n",
+                    rxActive, vnic->rxUnique);
+
+            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;
+        }
+
+        if (rxFifoPtr == rxFifo.end()) {
+            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
+            goto exit;
+        }
+
+        if (rxList.empty())
+            panic("Not idle, but nothing to do!");
+
+        assert(!rxFifo.empty());
+
+        rxActive = rxList.front();
+        rxList.pop_front();
+        vnic = &virtualRegs[rxActive];
+
+        DPRINTF(EthernetSM,
+                "processing new packet for vnic %d (rxunique %d)\n",
+                rxActive, vnic->rxUnique);
+
+        // Grab a new packet from the fifo.
+        vnic->rxIndex = rxFifoPtr++;
+        vnic->rxIndex->priv = rxActive;
+        vnic->rxPacketOffset = 0;
+        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
+        assert(vnic->rxPacketBytes);
+        rxMappedCount++;
+
+        vnic->rxDoneData = 0;
+        /* scope for variables */ {
+            IpPtr ip(vnic->rxIndex->packet);
+            if (ip) {
+                DPRINTF(Ethernet, "ID is %d\n", ip->id());
+                vnic->rxDoneData |= Regs::RxDone_IpPacket;
+                rxIpChecksums++;
+                if (cksum(ip) != 0) {
+                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
+                    vnic->rxDoneData |= Regs::RxDone_IpError;
+                }
+                TcpPtr tcp(ip);
+                UdpPtr udp(ip);
+                if (tcp) {
+                    DPRINTF(Ethernet,
+                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                            tcp->sport(), tcp->dport(), tcp->seq(),
+                            tcp->ack());
+                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
+                    rxTcpChecksums++;
+                    if (cksum(tcp) != 0) {
+                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
+                        vnic->rxDoneData |= Regs::RxDone_TcpError;
+                    }
+                } else if (udp) {
+                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
+                    rxUdpChecksums++;
+                    if (cksum(udp) != 0) {
+                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
+                        vnic->rxDoneData |= Regs::RxDone_UdpError;
+                    }
+                }
+            }
+        }
+        rxState = rxBeginCopy;
+        break;
+
+      case rxBeginCopy:
+        if (dmaPending() || drainState() != DrainState::Running)
+            goto exit;
+
+        rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
+        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
+                                 vnic->rxPacketBytes);
+
+        /*
+         * 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 rxCopy:
+        DPRINTF(EthernetSM, "receive machine still copying\n");
+        goto exit;
+
+      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->rxIndex);
+            vnic->rxIndex = rxFifo.end();
+            rxMappedCount--;
+        } else {
+            if (!vnic->rxPacketOffset)
+                rxDirtyCount++;
+
+            vnic->rxPacketBytes -= rxDmaLen;
+            vnic->rxPacketOffset += rxDmaLen;
+            vnic->RxDone |= Regs::RxDone_More;
+            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
+                                                    vnic->rxPacketBytes);
+            DPRINTF(EthernetSM,
+                    "rxKick: packet not complete on vnic %d (rxunique %d): "
+                    "%d bytes left\n",
+                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
+        }
+
+        rxActive = -1;
+        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
+
+        if (rxFifo.empty()) {
+            devIntrPost(Regs::Intr_RxEmpty);
+            rxEmpty = true;
+        }
+
+        if (rxFifo.size() < regs.RxFifoLow)
+            rxLow = true;
+
+        if (rxFifo.size() > regs.RxFifoHigh)
+            rxLow = false;
+
+        devIntrPost(Regs::Intr_RxDMA);
+        break;
+
+      default:
+        panic("Invalid rxState!");
+    }
+
+    DPRINTF(EthernetSM, "entering next rxState=%s\n",
+            RxStateStrings[rxState]);
+
+    goto next;
+
+  exit:
+    /**
+     * @todo do we want to schedule a future kick?
+     */
+    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
+            RxStateStrings[rxState]);
+}
+
+void
+Device::txDmaDone()
+{
+    assert(txState == txCopy);
+    txState = txCopyDone;
+    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
+            txDmaAddr, txDmaLen);
+    DDUMP(EthernetData, txDmaData, txDmaLen);
+
+    // If the receive state machine  has a pending DMA, let it go first
+    if (rxState == rxBeginCopy)
+        rxKick();
+
+    txKick();
+}
+
+void
+Device::transmit()
+{
+    if (txFifo.empty()) {
+        DPRINTF(Ethernet, "nothing to transmit\n");
+        return;
+    }
+
+    uint32_t interrupts;
+    EthPacketPtr packet = txFifo.front();
+    if (!interface->sendPacket(packet)) {
+        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
+                txFifo.avail());
+        return;
+    }
+
+    txFifo.pop();
+#if TRACING_ON
+    if (DTRACE(Ethernet)) {
+        IpPtr ip(packet);
+        if (ip) {
+            DPRINTF(Ethernet, "ID is %d\n", ip->id());
+            TcpPtr tcp(ip);
+            if (tcp) {
+                DPRINTF(Ethernet,
+                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+                        tcp->sport(), tcp->dport(), tcp->seq(),
+                        tcp->ack());
+            }
+        }
+    }
+#endif
+
+    DDUMP(EthernetData, packet->data, packet->length);
+    txBytes += packet->length;
+    txPackets++;
+
+    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
+            txFifo.avail());
+
+    interrupts = Regs::Intr_TxPacket;
+    if (txFifo.size() < regs.TxFifoLow)
+        interrupts |= Regs::Intr_TxLow;
+    devIntrPost(interrupts);
+}
+
+void
+Device::txKick()
+{
+    VirtualReg *vnic;
+    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
+            TxStateStrings[txState], txFifo.size());
+
+    if (txKickTick > curTick()) {
+        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
+                txKickTick);
+        return;
+    }
+
+  next:
+    if (txState == txIdle)
+        goto exit;
+
+    assert(!txList.empty());
+    vnic = &virtualRegs[txList.front()];
+
+    switch (txState) {
+      case txFifoBlock:
+        assert(Regs::get_TxDone_Busy(vnic->TxDone));
+        if (!txPacket) {
+            // Grab a new packet from the fifo.
+            txPacket = make_shared<EthPacketData>(16384);
+            txPacketOffset = 0;
+        }
+
+        if (txFifo.avail() - txPacket->length <
+            Regs::get_TxData_Len(vnic->TxData)) {
+            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
+            goto exit;
+        }
+
+        txState = txBeginCopy;
+        break;
+
+      case txBeginCopy:
+        if (dmaPending() || drainState() != DrainState::Running)
+            goto exit;
+
+        txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
+        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
+        txDmaData = txPacket->data + txPacketOffset;
+        txState = txCopy;
+
+        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
+        break;
+
+      case txCopy:
+        DPRINTF(EthernetSM, "transmit machine still copying\n");
+        goto exit;
+
+      case txCopyDone:
+        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
+        txPacket->length += txDmaLen;
+        if ((vnic->TxData & Regs::TxData_More)) {
+            txPacketOffset += txDmaLen;
+            txState = txIdle;
+            devIntrPost(Regs::Intr_TxDMA);
+            break;
+        }
+
+        assert(txPacket->length <= txFifo.avail());
+        if ((vnic->TxData & Regs::TxData_Checksum)) {
+            IpPtr ip(txPacket);
+            if (ip) {
+                TcpPtr tcp(ip);
+                if (tcp) {
+                    tcp->sum(0);
+                    tcp->sum(cksum(tcp));
+                    txTcpChecksums++;
+                }
+
+                UdpPtr udp(ip);
+                if (udp) {
+                    udp->sum(0);
+                    udp->sum(cksum(udp));
+                    txUdpChecksums++;
+                }
+
+                ip->sum(0);
+                ip->sum(cksum(ip));
+                txIpChecksums++;
+            }
+        }
+
+        txFifo.push(txPacket);
+        if (txFifo.avail() < regs.TxMaxCopy) {
+            devIntrPost(Regs::Intr_TxFull);
+            txFull = true;
+        }
+        txPacket = 0;
+        transmit();
+        txList.pop_front();
+        txState = txList.empty() ? txIdle : txFifoBlock;
+        devIntrPost(Regs::Intr_TxDMA);
+        break;
+
+      default:
+        panic("Invalid txState!");
+    }
+
+    DPRINTF(EthernetSM, "entering next txState=%s\n",
+            TxStateStrings[txState]);
+
+    goto next;
+
+  exit:
+    /**
+     * @todo do we want to schedule a future kick?
+     */
+    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
+            TxStateStrings[txState]);
+}
+
+void
+Device::transferDone()
+{
+    if (txFifo.empty()) {
+        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
+        return;
+    }
+
+    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
+
+    reschedule(txEvent, clockEdge(Cycles(1)), true);
+}
+
+bool
+Device::rxFilter(const EthPacketPtr &packet)
+{
+    if (!Regs::get_Config_Filter(regs.Config))
+        return false;
+
+    panic("receive filter not implemented\n");
+    bool drop = true;
+
+#if 0
+    string type;
+
+    EthHdr *eth = packet->eth();
+    if (eth->unicast()) {
+        // If we're accepting all unicast addresses
+        if (acceptUnicast)
+            drop = false;
+
+        // If we make a perfect match
+        if (acceptPerfect && params->eaddr == eth.dst())
+            drop = false;
+
+        if (acceptArp && eth->type() == ETH_TYPE_ARP)
+            drop = false;
+
+    } else if (eth->broadcast()) {
+        // if we're accepting broadcasts
+        if (acceptBroadcast)
+            drop = false;
+
+    } else if (eth->multicast()) {
+        // if we're accepting all multicasts
+        if (acceptMulticast)
+            drop = false;
+
+    }
+
+    if (drop) {
+        DPRINTF(Ethernet, "rxFilter drop\n");
+        DDUMP(EthernetData, packet->data, packet->length);
+    }
+#endif
+    return drop;
+}
+
+bool
+Device::recvPacket(EthPacketPtr packet)
+{
+    rxBytes += packet->length;
+    rxPackets++;
+
+    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
+            rxFifo.avail());
+
+    if (!rxEnable) {
+        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
+        return true;
+    }
+
+    if (rxFilter(packet)) {
+        DPRINTF(Ethernet, "packet filtered...dropped\n");
+        return true;
+    }
+
+    if (rxFifo.size() >= regs.RxFifoHigh)
+        devIntrPost(Regs::Intr_RxHigh);
+
+    if (!rxFifo.push(packet)) {
+        DPRINTF(Ethernet,
+                "packet will not fit in receive buffer...packet dropped\n");
+        return false;
+    }
+
+    // If we were at the last element, back up one ot go to the new
+    // last element of the list.
+    if (rxFifoPtr == rxFifo.end())
+        --rxFifoPtr;
+
+    devIntrPost(Regs::Intr_RxPacket);
+    rxKick();
+    return true;
+}
+
+void
+Device::drainResume()
+{
+    Drainable::drainResume();
+
+    // During drain we could have left the state machines in a waiting state and
+    // they wouldn't get out until some other event occured to kick them.
+    // This way they'll get out immediately
+    txKick();
+    rxKick();
+}
+
+//=====================================================================
+//
+//
+void
+Base::serialize(CheckpointOut &cp) const
+{
+    // Serialize the PciDevice base class
+    PciDevice::serialize(cp);
+
+    SERIALIZE_SCALAR(rxEnable);
+    SERIALIZE_SCALAR(txEnable);
+    SERIALIZE_SCALAR(cpuIntrEnable);
+
+    /*
+     * Keep track of pending interrupt status.
+     */
+    SERIALIZE_SCALAR(intrTick);
+    SERIALIZE_SCALAR(cpuPendingIntr);
+    Tick intrEventTick = 0;
+    if (intrEvent)
+        intrEventTick = intrEvent->when();
+    SERIALIZE_SCALAR(intrEventTick);
+}
+
+void
+Base::unserialize(CheckpointIn &cp)
+{
+    // Unserialize the PciDevice base class
+    PciDevice::unserialize(cp);
+
+    UNSERIALIZE_SCALAR(rxEnable);
+    UNSERIALIZE_SCALAR(txEnable);
+    UNSERIALIZE_SCALAR(cpuIntrEnable);
+
+    /*
+     * Keep track of pending interrupt status.
+     */
+    UNSERIALIZE_SCALAR(intrTick);
+    UNSERIALIZE_SCALAR(cpuPendingIntr);
+    Tick intrEventTick;
+    UNSERIALIZE_SCALAR(intrEventTick);
+    if (intrEventTick) {
+        intrEvent = new IntrEvent(this, true);
+        schedule(intrEvent, intrEventTick);
+    }
+}
+
+void
+Device::serialize(CheckpointOut &cp) const
+{
+    int count;
+
+    // Serialize the PciDevice base class
+    Base::serialize(cp);
+
+    if (rxState == rxCopy)
+        panic("can't serialize with an in flight dma request rxState=%s",
+              RxStateStrings[rxState]);
+
+    if (txState == txCopy)
+        panic("can't serialize with an in flight dma request txState=%s",
+              TxStateStrings[txState]);
+
+    /*
+     * 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.RxData);
+    SERIALIZE_SCALAR(regs.TxData);
+
+    /*
+     * Serialize the virtual nic state
+     */
+    int virtualRegsSize = virtualRegs.size();
+    SERIALIZE_SCALAR(virtualRegsSize);
+    for (int i = 0; i < virtualRegsSize; ++i) {
+        const VirtualReg *vnic = &virtualRegs[i];
+
+        std::string reg = csprintf("vnic%d", i);
+        paramOut(cp, reg + ".RxData", vnic->RxData);
+        paramOut(cp, reg + ".RxDone", vnic->RxDone);
+        paramOut(cp, reg + ".TxData", vnic->TxData);
+        paramOut(cp, reg + ".TxDone", vnic->TxDone);
+
+        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
+        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
+        if (rxPacketExists) {
+            int rxPacket = 0;
+            auto i = rxFifo.begin();
+            while (i != vnic->rxIndex) {
+                assert(i != rxFifo.end());
+                ++i;
+                ++rxPacket;
+            }
+
+            paramOut(cp, reg + ".rxPacket", rxPacket);
+            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
+            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+        }
+        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
+    }
+
+    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::const_iterator i, end;
+    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
+        paramOut(cp, csprintf("rxList%d", count++), *i);
+    int rxListSize = count;
+    SERIALIZE_SCALAR(rxListSize);
+
+    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
+        paramOut(cp, csprintf("rxBusy%d", count++), *i);
+    int rxBusySize = count;
+    SERIALIZE_SCALAR(rxBusySize);
+
+    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
+        paramOut(cp, csprintf("txList%d", count++), *i);
+    int txListSize = count;
+    SERIALIZE_SCALAR(txListSize);
+
+    /*
+     * Serialize rx state machine
+     */
+    int rxState = this->rxState;
+    SERIALIZE_SCALAR(rxState);
+    SERIALIZE_SCALAR(rxEmpty);
+    SERIALIZE_SCALAR(rxLow);
+    rxFifo.serialize("rxFifo", cp);
+
+    /*
+     * Serialize tx state machine
+     */
+    int txState = this->txState;
+    SERIALIZE_SCALAR(txState);
+    SERIALIZE_SCALAR(txFull);
+    txFifo.serialize("txFifo", cp);
+    bool txPacketExists = txPacket != nullptr;
+    SERIALIZE_SCALAR(txPacketExists);
+    if (txPacketExists) {
+        txPacket->serialize("txPacket", cp);
+        SERIALIZE_SCALAR(txPacketOffset);
+        SERIALIZE_SCALAR(txPacketBytes);
+    }
+
+    /*
+     * If there's a pending transmit, store the time so we can
+     * reschedule it later
+     */
+    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
+    SERIALIZE_SCALAR(transmitTick);
+}
+
+void
+Device::unserialize(CheckpointIn &cp)
+{
+    // Unserialize the PciDevice base class
+    Base::unserialize(cp);
+
+    /*
+     * 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.RxData);
+    UNSERIALIZE_SCALAR(regs.TxData);
+
+    UNSERIALIZE_SCALAR(rxActive);
+    UNSERIALIZE_SCALAR(rxBusyCount);
+    UNSERIALIZE_SCALAR(rxDirtyCount);
+    UNSERIALIZE_SCALAR(rxMappedCount);
+
+    int rxListSize;
+    UNSERIALIZE_SCALAR(rxListSize);
+    rxList.clear();
+    for (int i = 0; i < rxListSize; ++i) {
+        int value;
+        paramIn(cp, csprintf("rxList%d", i), value);
+        rxList.push_back(value);
+    }
+
+    int rxBusySize;
+    UNSERIALIZE_SCALAR(rxBusySize);
+    rxBusy.clear();
+    for (int i = 0; i < rxBusySize; ++i) {
+        int value;
+        paramIn(cp, csprintf("rxBusy%d", i), value);
+        rxBusy.push_back(value);
+    }
+
+    int txListSize;
+    UNSERIALIZE_SCALAR(txListSize);
+    txList.clear();
+    for (int i = 0; i < txListSize; ++i) {
+        int value;
+        paramIn(cp, csprintf("txList%d", i), value);
+        txList.push_back(value);
+    }
+
+    /*
+     * Unserialize rx state machine
+     */
+    int rxState;
+    UNSERIALIZE_SCALAR(rxState);
+    UNSERIALIZE_SCALAR(rxEmpty);
+    UNSERIALIZE_SCALAR(rxLow);
+    this->rxState = (RxState) rxState;
+    rxFifo.unserialize("rxFifo", cp);
+
+    int rxFifoPtr;
+    UNSERIALIZE_SCALAR(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
+     */
+    int txState;
+    UNSERIALIZE_SCALAR(txState);
+    UNSERIALIZE_SCALAR(txFull);
+    this->txState = (TxState) txState;
+    txFifo.unserialize("txFifo", cp);
+    bool txPacketExists;
+    UNSERIALIZE_SCALAR(txPacketExists);
+    txPacket = 0;
+    if (txPacketExists) {
+        txPacket = make_shared<EthPacketData>(16384);
+        txPacket->unserialize("txPacket", cp);
+        UNSERIALIZE_SCALAR(txPacketOffset);
+        UNSERIALIZE_SCALAR(txPacketBytes);
+    }
+
+    /*
+     * unserialize the virtual nic registers/state
+     *
+     * this must be done after the unserialization of the rxFifo
+     * because the packet iterators depend on the fifo being populated
+     */
+    int virtualRegsSize;
+    UNSERIALIZE_SCALAR(virtualRegsSize);
+    virtualRegs.clear();
+    virtualRegs.resize(virtualRegsSize);
+    for (int i = 0; i < virtualRegsSize; ++i) {
+        VirtualReg *vnic = &virtualRegs[i];
+        std::string reg = csprintf("vnic%d", i);
+
+        paramIn(cp, reg + ".RxData", vnic->RxData);
+        paramIn(cp, reg + ".RxDone", vnic->RxDone);
+        paramIn(cp, reg + ".TxData", vnic->TxData);
+        paramIn(cp, reg + ".TxDone", vnic->TxDone);
+
+        vnic->rxUnique = rxUnique++;
+        vnic->txUnique = txUnique++;
+
+        bool rxPacketExists;
+        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
+        if (rxPacketExists) {
+            int rxPacket;
+            paramIn(cp, reg + ".rxPacket", rxPacket);
+            vnic->rxIndex = rxFifo.begin();
+            while (rxPacket--)
+                ++vnic->rxIndex;
+
+            paramIn(cp, reg + ".rxPacketOffset",
+                    vnic->rxPacketOffset);
+            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+        } else {
+            vnic->rxIndex = rxFifo.end();
+        }
+        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
+    }
+
+    /*
+     * If there's a pending transmit, reschedule it now
+     */
+    Tick transmitTick;
+    UNSERIALIZE_SCALAR(transmitTick);
+    if (transmitTick)
+        schedule(txEvent, curTick() + transmitTick);
+
+    pioPort.sendRangeChange();
+
+}
+
+} // namespace Sinic
+
+Sinic::Device *
+SinicParams::create()
+{
+    return new Sinic::Device(this);
+}
diff --git a/src/dev/net/sinic.hh b/src/dev/net/sinic.hh
new file mode 100644 (file)
index 0000000..b041cb1
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __DEV_NET_SINIC_HH__
+#define __DEV_NET_SINIC_HH__
+
+#include "base/inet.hh"
+#include "base/statistics.hh"
+#include "dev/io_device.hh"
+#include "dev/net/etherdevice.hh"
+#include "dev/net/etherint.hh"
+#include "dev/net/etherpkt.hh"
+#include "dev/net/pktfifo.hh"
+#include "dev/net/sinicreg.hh"
+#include "dev/pci/device.hh"
+#include "params/Sinic.hh"
+#include "sim/eventq.hh"
+
+namespace Sinic {
+
+class Interface;
+class Base : public EtherDevBase
+{
+  protected:
+    bool rxEnable;
+    bool txEnable;
+
+  protected:
+    Tick intrDelay;
+    Tick intrTick;
+    bool cpuIntrEnable;
+    bool cpuPendingIntr;
+    void cpuIntrPost(Tick when);
+    void cpuInterrupt();
+    void cpuIntrClear();
+
+    typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent;
+    friend void IntrEvent::process();
+    IntrEvent *intrEvent;
+    Interface *interface;
+
+    bool cpuIntrPending() const;
+    void cpuIntrAck() { cpuIntrClear(); }
+
+/**
+ * Serialization stuff
+ */
+  public:
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+/**
+ * Construction/Destruction/Parameters
+ */
+  public:
+    typedef SinicParams Params;
+    const Params *params() const { return (const Params *)_params; }
+    Base(const Params *p);
+};
+
+class Device : public Base
+{
+  protected:
+    /** Receive State Machine States */
+    enum RxState {
+        rxIdle,
+        rxFifoBlock,
+        rxBeginCopy,
+        rxCopy,
+        rxCopyDone
+    };
+
+    /** Transmit State Machine states */
+    enum TxState {
+        txIdle,
+        txFifoBlock,
+        txBeginCopy,
+        txCopy,
+        txCopyDone
+    };
+
+    /** device register file */
+    struct {
+        uint32_t Config;       // 0x00
+        uint32_t Command;      // 0x04
+        uint32_t IntrStatus;   // 0x08
+        uint32_t IntrMask;     // 0x0c
+        uint32_t RxMaxCopy;    // 0x10
+        uint32_t TxMaxCopy;    // 0x14
+        uint32_t ZeroCopySize; // 0x18
+        uint32_t ZeroCopyMark; // 0x1c
+        uint32_t VirtualCount; // 0x20
+        uint32_t RxMaxIntr;    // 0x24
+        uint32_t RxFifoSize;   // 0x28
+        uint32_t TxFifoSize;   // 0x2c
+        uint32_t RxFifoLow;    // 0x30
+        uint32_t TxFifoLow;    // 0x34
+        uint32_t RxFifoHigh;   // 0x38
+        uint32_t TxFifoHigh;   // 0x3c
+        uint64_t RxData;       // 0x40
+        uint64_t RxDone;       // 0x48
+        uint64_t RxWait;       // 0x50
+        uint64_t TxData;       // 0x58
+        uint64_t TxDone;       // 0x60
+        uint64_t TxWait;       // 0x68
+        uint64_t HwAddr;       // 0x70
+        uint64_t RxStatus;     // 0x78
+    } regs;
+
+    struct VirtualReg {
+        uint64_t RxData;
+        uint64_t RxDone;
+        uint64_t TxData;
+        uint64_t TxDone;
+
+        PacketFifo::iterator rxIndex;
+        unsigned rxPacketOffset;
+        unsigned rxPacketBytes;
+        uint64_t rxDoneData;
+
+        Counter rxUnique;
+        Counter txUnique;
+
+        VirtualReg()
+            : RxData(0), RxDone(0), TxData(0), TxDone(0),
+              rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0)
+        { }
+    };
+    typedef std::vector<VirtualReg> VirtualRegs;
+    typedef std::list<unsigned> VirtualList;
+    Counter rxUnique;
+    Counter txUnique;
+    VirtualRegs virtualRegs;
+    VirtualList rxList;
+    VirtualList rxBusy;
+    int rxActive;
+    VirtualList txList;
+
+    int rxBusyCount;
+    int rxMappedCount;
+    int rxDirtyCount;
+
+    uint8_t  &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
+    uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
+    uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
+
+  protected:
+    RxState rxState;
+    PacketFifo rxFifo;
+    PacketFifo::iterator rxFifoPtr;
+    bool rxEmpty;
+    bool rxLow;
+    Addr rxDmaAddr;
+    uint8_t *rxDmaData;
+    unsigned rxDmaLen;
+
+    TxState txState;
+    PacketFifo txFifo;
+    bool txFull;
+    EthPacketPtr txPacket;
+    int txPacketOffset;
+    int txPacketBytes;
+    Addr txDmaAddr;
+    uint8_t *txDmaData;
+    int txDmaLen;
+
+  protected:
+    void reset();
+
+    void rxKick();
+    Tick rxKickTick;
+    typedef EventWrapper<Device, &Device::rxKick> RxKickEvent;
+    friend void RxKickEvent::process();
+
+    void txKick();
+    Tick txKickTick;
+    typedef EventWrapper<Device, &Device::txKick> TxKickEvent;
+    friend void TxKickEvent::process();
+
+    /**
+     * Retransmit event
+     */
+    void transmit();
+    void txEventTransmit()
+    {
+        transmit();
+        if (txState == txFifoBlock)
+            txKick();
+    }
+    typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent;
+    friend void TxEvent::process();
+    TxEvent txEvent;
+
+    void txDump() const;
+    void rxDump() const;
+
+    /**
+     * receive address filter
+     */
+    bool rxFilter(const EthPacketPtr &packet);
+
+/**
+ * device configuration
+ */
+    void changeConfig(uint32_t newconfig);
+    void command(uint32_t command);
+
+/**
+ * device ethernet interface
+ */
+  public:
+    bool recvPacket(EthPacketPtr packet);
+    void transferDone();
+    EtherInt *getEthPort(const std::string &if_name, int idx) override;
+
+/**
+ * DMA parameters
+ */
+  protected:
+    void rxDmaDone();
+    friend class EventWrapper<Device, &Device::rxDmaDone>;
+    EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent;
+
+    void txDmaDone();
+    friend class EventWrapper<Device, &Device::txDmaDone>;
+    EventWrapper<Device, &Device::txDmaDone> txDmaEvent;
+
+    Tick dmaReadDelay;
+    Tick dmaReadFactor;
+    Tick dmaWriteDelay;
+    Tick dmaWriteFactor;
+
+/**
+ * Interrupt management
+ */
+  protected:
+    void devIntrPost(uint32_t interrupts);
+    void devIntrClear(uint32_t interrupts = Regs::Intr_All);
+    void devIntrChangeMask(uint32_t newmask);
+
+/**
+ * Memory Interface
+ */
+  public:
+    Tick read(PacketPtr pkt) override;
+    Tick write(PacketPtr pkt) override;
+    virtual void drainResume() override;
+
+    void prepareIO(ContextID cpu, int index);
+    void prepareRead(ContextID cpu, int index);
+    void prepareWrite(ContextID cpu, int index);
+ //   Fault iprRead(Addr daddr, ContextID cpu, uint64_t &result);
+
+/**
+ * Statistics
+ */
+  private:
+    Stats::Scalar totalVnicDistance;
+    Stats::Scalar numVnicDistance;
+    Stats::Scalar maxVnicDistance;
+    Stats::Formula avgVnicDistance;
+
+    int _maxVnicDistance;
+
+  public:
+    void regStats() override;
+    void resetStats() override;
+
+/**
+ * Serialization stuff
+ */
+  public:
+    void serialize(CheckpointOut &cp) const override;
+    void unserialize(CheckpointIn &cp) override;
+
+  public:
+    Device(const Params *p);
+    ~Device();
+};
+
+/*
+ * Ethernet Interface for an Ethernet Device
+ */
+class Interface : public EtherInt
+{
+  private:
+    Device *dev;
+
+  public:
+    Interface(const std::string &name, Device *d)
+        : EtherInt(name), dev(d)
+    { }
+
+    virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
+    virtual void sendDone() { dev->transferDone(); }
+};
+
+} // namespace Sinic
+
+#endif // __DEV_NET_SINIC_HH__
diff --git a/src/dev/net/sinicreg.hh b/src/dev/net/sinicreg.hh
new file mode 100644 (file)
index 0000000..fc74889
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Nathan Binkert
+ */
+
+#ifndef __DEV_NET_SINICREG_HH__
+#define __DEV_NET_SINICREG_HH__
+
+#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL);
+#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL);
+
+#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \
+        static const uint32_t NAME##_width = WIDTH; \
+        static const uint32_t NAME##_offset = OFFSET; \
+        static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \
+        static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \
+        static inline uint32_t get_##NAME(uint32_t reg) \
+        { return (reg & NAME) >> OFFSET; } \
+        static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \
+        { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
+
+#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \
+        static const uint64_t NAME##_width = WIDTH; \
+        static const uint64_t NAME##_offset = OFFSET; \
+        static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \
+        static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
+        static inline uint64_t get_##NAME(uint64_t reg) \
+        { return (reg & NAME) >> OFFSET; } \
+        static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \
+        { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
+
+namespace Sinic {
+namespace Regs {
+
+static const int VirtualShift = 8;
+static const int VirtualMask = 0xff;
+
+// Registers
+__SINIC_REG32(Config,        0x00) // 32: configuration register
+__SINIC_REG32(Command,       0x04) // 32: command register
+__SINIC_REG32(IntrStatus,    0x08) // 32: interrupt status
+__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(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_VAL32(Config_DelayCopy,11, 1) // enable delayed copy
+__SINIC_VAL32(Config_RSS,      10, 1) // enable receive side scaling
+__SINIC_VAL32(Config_RxThread,  9, 1) // enable receive threads
+__SINIC_VAL32(Config_TxThread,  8, 1) // enable transmit thread
+__SINIC_VAL32(Config_Filter,    7, 1) // enable receive filter
+__SINIC_VAL32(Config_Vlan,      6, 1) // enable vlan tagging
+__SINIC_VAL32(Config_Vaddr,     5, 1) // enable virtual addressing
+__SINIC_VAL32(Config_Desc,      4, 1) // enable tx/rx descriptors
+__SINIC_VAL32(Config_Poll,      3, 1) // enable polling
+__SINIC_VAL32(Config_IntEn,     2, 1) // enable interrupts
+__SINIC_VAL32(Config_TxEn,      1, 1) // enable transmit
+__SINIC_VAL32(Config_RxEn,      0, 1) // enable receive
+
+// Command register bits
+__SINIC_VAL32(Command_Intr,  1, 1) // software interrupt
+__SINIC_VAL32(Command_Reset, 0, 1) // reset chip
+
+// Interrupt register bits
+__SINIC_VAL32(Intr_Soft,      8, 1) // software interrupt
+__SINIC_VAL32(Intr_TxLow,     7, 1) // tx fifo dropped below watermark
+__SINIC_VAL32(Intr_TxFull,    6, 1) // tx fifo full
+__SINIC_VAL32(Intr_TxDMA,     5, 1) // tx dma completed w/ interrupt
+__SINIC_VAL32(Intr_TxPacket,  4, 1) // packet transmitted
+__SINIC_VAL32(Intr_RxHigh,    3, 1) // rx fifo above high watermark
+__SINIC_VAL32(Intr_RxEmpty,   2, 1) // rx fifo empty
+__SINIC_VAL32(Intr_RxDMA,     1, 1) // rx dma completed w/ interrupt
+__SINIC_VAL32(Intr_RxPacket,  0, 1) // packet received
+__SINIC_REG32(Intr_All,       0x01ff) // all valid interrupts
+__SINIC_REG32(Intr_NoDelay,   0x01cc) // interrupts that aren't coalesced
+__SINIC_REG32(Intr_Res,      ~0x01ff) // reserved interrupt bits
+
+// RX Data Description
+__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(TxData_Checksum, 62,  1) // do checksum
+__SINIC_VAL64(TxData_Vaddr,    60,  1) // Addr is virtual
+__SINIC_VAL64(TxData_Len,      40, 20) // 0 - 256k
+__SINIC_VAL64(TxData_Addr,      0, 40) // Address 1TB
+
+// RX Done/Busy Information
+__SINIC_VAL64(RxDone_Packets,   32, 16) // number of packets in rx fifo
+__SINIC_VAL64(RxDone_Busy,      31,  1) // receive dma busy copying
+__SINIC_VAL64(RxDone_Complete,  30,  1) // valid data (packet complete)
+__SINIC_VAL64(RxDone_More,      29,  1) // Packet has more data (dma again)
+__SINIC_VAL64(RxDone_Empty,     28,  1) // rx fifo is empty
+__SINIC_VAL64(RxDone_High,      27,  1) // rx fifo is above the watermark
+__SINIC_VAL64(RxDone_NotHigh,   26,  1) // rxfifo never hit the high watermark
+__SINIC_VAL64(RxDone_TcpError,  25,  1) // TCP packet error (bad checksum)
+__SINIC_VAL64(RxDone_UdpError,  24,  1) // UDP packet error (bad checksum)
+__SINIC_VAL64(RxDone_IpError,   23,  1) // IP packet error (bad checksum)
+__SINIC_VAL64(RxDone_TcpPacket, 22,  1) // this is a TCP packet
+__SINIC_VAL64(RxDone_UdpPacket, 21,  1) // this is a UDP packet
+__SINIC_VAL64(RxDone_IpPacket,  20,  1) // this is an IP packet
+__SINIC_VAL64(RxDone_CopyLen,    0, 20) // up to 256k
+
+// TX Done/Busy Information
+__SINIC_VAL64(TxDone_Packets,   32, 16) // number of packets in tx fifo
+__SINIC_VAL64(TxDone_Busy,      31,  1) // transmit dma busy copying
+__SINIC_VAL64(TxDone_Complete,  30,  1) // valid data (packet complete)
+__SINIC_VAL64(TxDone_Full,      29,  1) // tx fifo is full
+__SINIC_VAL64(TxDone_Low,       28,  1) // tx fifo is below the watermark
+__SINIC_VAL64(TxDone_Res0,      27,  1) // reserved
+__SINIC_VAL64(TxDone_Res1,      26,  1) // reserved
+__SINIC_VAL64(TxDone_Res2,      25,  1) // reserved
+__SINIC_VAL64(TxDone_Res3,      24,  1) // reserved
+__SINIC_VAL64(TxDone_Res4,      23,  1) // reserved
+__SINIC_VAL64(TxDone_Res5,      22,  1) // reserved
+__SINIC_VAL64(TxDone_Res6,      21,  1) // reserved
+__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;
+    bool read;
+    bool write;
+    const char *name;
+};
+
+} // namespace Regs
+
+inline const Regs::Info&
+regInfo(Addr daddr)
+{
+    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, "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, "RxWait"       },
+        invalid,
+        { 8, true,  true,  "TxData"       },
+        invalid,
+        { 8, true,  false, "TxDone"       },
+        invalid,
+        { 8, true,  false, "TxWait"       },
+        invalid,
+        { 8, true,  false, "HwAddr"       },
+        invalid,
+        { 8, true,  false, "RxStatus"     },
+        invalid,
+    };
+
+    return info[daddr / 4];
+}
+
+inline bool
+regValid(Addr daddr)
+{
+    if (daddr > Regs::Size)
+        return false;
+
+    if (regInfo(daddr).size == 0)
+        return false;
+
+    return true;
+}
+
+} // namespace Sinic
+
+#endif // __DEV_NET_SINICREG_HH__
diff --git a/src/dev/net/tcp_iface.cc b/src/dev/net/tcp_iface.cc
new file mode 100644 (file)
index 0000000..035ec8f
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * TCP stream socket based interface class implementation for multi gem5 runs.
+ */
+
+#include "dev/net/tcp_iface.hh"
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+
+#include "base/types.hh"
+#include "debug/MultiEthernet.hh"
+
+// MSG_NOSIGNAL does not exists on OS X
+#if defined(__APPLE__) || defined(__MACH__)
+#ifndef MSG_NOSIGNAL
+#define MSG_NOSIGNAL SO_NOSIGPIPE
+#endif
+#endif
+
+using namespace std;
+
+vector<int> TCPIface::sockRegistry;
+
+TCPIface::TCPIface(string server_name, unsigned server_port,
+                   unsigned multi_rank, Tick sync_start, Tick sync_repeat,
+                   EventManager *em) :
+    MultiIface(multi_rank, sync_start, sync_repeat, em)
+{
+    struct addrinfo addr_hint, *addr_results;
+    int ret;
+
+    string port_str = to_string(server_port);
+
+    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    panic_if(sock < 0, "socket() failed: %s", strerror(errno));
+
+    bzero(&addr_hint, sizeof(addr_hint));
+    addr_hint.ai_family = AF_INET;
+    addr_hint.ai_socktype = SOCK_STREAM;
+    addr_hint.ai_protocol = IPPROTO_TCP;
+
+    ret = getaddrinfo(server_name.c_str(), port_str.c_str(),
+                      &addr_hint, &addr_results);
+    panic_if(ret < 0, "getaddrinf() failed: %s", strerror(errno));
+
+    DPRINTF(MultiEthernet, "Connecting to %s:%u\n",
+            server_name.c_str(), port_str.c_str());
+
+    ret = ::connect(sock, (struct sockaddr *)(addr_results->ai_addr),
+                    addr_results->ai_addrlen);
+    panic_if(ret < 0, "connect() failed: %s", strerror(errno));
+
+    freeaddrinfo(addr_results);
+    // add our socket to the static registry
+    sockRegistry.push_back(sock);
+    // let the server know who we are
+    sendTCP(sock, &multi_rank, sizeof(multi_rank));
+}
+
+TCPIface::~TCPIface()
+{
+    int M5_VAR_USED ret;
+
+    ret = close(sock);
+    assert(ret == 0);
+}
+
+void
+TCPIface::sendTCP(int sock, void *buf, unsigned length)
+{
+    ssize_t ret;
+
+    ret = ::send(sock, buf, length, MSG_NOSIGNAL);
+    panic_if(ret < 0, "send() failed: %s", strerror(errno));
+    panic_if(ret != length, "send() failed");
+}
+
+bool
+TCPIface::recvTCP(int sock, void *buf, unsigned length)
+{
+    ssize_t ret;
+
+    ret = ::recv(sock, buf, length,  MSG_WAITALL );
+    if (ret < 0) {
+        if (errno == ECONNRESET || errno == EPIPE)
+            inform("recv(): %s", strerror(errno));
+        else if (ret < 0)
+            panic("recv() failed: %s", strerror(errno));
+    } else if (ret == 0) {
+        inform("recv(): Connection closed");
+    } else if (ret != length)
+        panic("recv() failed");
+
+    return (ret == length);
+}
+
+void
+TCPIface::syncRaw(MultiHeaderPkt::MsgType sync_req, Tick sync_tick)
+{
+    /*
+     * Barrier is simply implemented by point-to-point messages to the server
+     * for now. This method is called by only one TCPIface object.
+     * The server will send back an 'ack' message when it gets the
+     * sync request from all clients.
+     */
+    MultiHeaderPkt::Header header_pkt;
+    header_pkt.msgType = sync_req;
+    header_pkt.sendTick = sync_tick;
+
+    for (auto s : sockRegistry)
+        sendTCP(s, (void *)&header_pkt, sizeof(header_pkt));
+}
+
diff --git a/src/dev/net/tcp_iface.hh b/src/dev/net/tcp_iface.hh
new file mode 100644 (file)
index 0000000..2eb2c1c
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2015 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Gabor Dozsa
+ */
+
+/* @file
+ * TCP stream socket based interface class for multi gem5 runs.
+ *
+ * For a high level description about multi gem5 see comments in
+ * header file multi_iface.hh.
+ *
+ * The TCP subclass of MultiIface uses a separate server process
+ * (see tcp_server.[hh,cc] under directory gem5/util/multi). Each gem5
+ * process connects to the server via a stream socket. The server process
+ * transfers messages and co-ordinates the synchronisation among the gem5
+ * peers.
+ */
+#ifndef __DEV_NET_TCP_IFACE_HH__
+#define __DEV_NET_TCP_IFACE_HH__
+
+
+#include <string>
+
+#include "dev/net/multi_iface.hh"
+
+class EventManager;
+
+class TCPIface : public MultiIface
+{
+  private:
+    /**
+     * The stream socket to connect to the server.
+     */
+    int sock;
+
+    /**
+     * Registry for all sockets to the server opened by this gem5 process.
+     */
+    static std::vector<int> sockRegistry;
+
+  private:
+
+    /**
+     * Send out a message through a TCP stream socket.
+     *
+     * @param sock TCP stream socket.
+     * @param buf Start address of the message.
+     * @param length Size of the message in bytes.
+     */
+    void
+    sendTCP(int sock, void *buf, unsigned length);
+
+    /**
+     * Receive the next incoming message through a TCP stream socket.
+     *
+     * @param sock TCP stream socket.
+     * @param buf Start address of buffer to store the message.
+     * @param length Exact size of the expected message in bytes.
+     */
+    bool recvTCP(int sock, void *buf, unsigned length);
+
+
+  protected:
+
+    virtual void
+    sendRaw(void *buf, unsigned length,
+            const MultiHeaderPkt::AddressType dest_addr=nullptr) override
+    {
+        sendTCP(sock, buf, length);
+    }
+
+    virtual bool recvRaw(void *buf, unsigned length) override
+    {
+        return recvTCP(sock, buf, length);
+    }
+
+    virtual void syncRaw(MultiHeaderPkt::MsgType sync_req,
+                         Tick sync_tick) override;
+
+  public:
+    /**
+     * The ctor creates and connects the stream socket to the server.
+     * @param server_name The name (or IP address) of the host running the
+     * server process.
+     * @param server_port The port number the server listening for new
+     * connections.
+     * @param sync_start The tick for the first multi synchronisation.
+     * @param sync_repeat The frequency of multi synchronisation.
+     * @param em The EventManager object associated with the simulated
+     * Ethernet link.
+     */
+    TCPIface(std::string server_name, unsigned server_port,
+             unsigned multi_rank, Tick sync_start, Tick sync_repeat,
+             EventManager *em);
+
+    ~TCPIface() override;
+};
+
+#endif // __DEV_NET_TCP_IFACE_HH__
diff --git a/src/dev/ns_gige.cc b/src/dev/ns_gige.cc
deleted file mode 100644 (file)
index eb4f0eb..0000000
+++ /dev/null
@@ -1,2481 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- *          Lisa Hsu
- */
-
-/** @file
- * Device module for modelling the National Semiconductor
- * DP83820 ethernet controller.  Does not support priority queueing
- */
-#include <deque>
-#include <memory>
-#include <string>
-
-#include "base/debug.hh"
-#include "base/inet.hh"
-#include "base/types.hh"
-#include "config/the_isa.hh"
-#include "debug/EthernetAll.hh"
-#include "dev/etherlink.hh"
-#include "dev/ns_gige.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "params/NSGigE.hh"
-#include "sim/system.hh"
-
-// clang complains about std::set being overloaded with Packet::set if
-// we open up the entire namespace std
-using std::make_shared;
-using std::min;
-using std::ostream;
-using std::string;
-
-const char *NsRxStateStrings[] =
-{
-    "rxIdle",
-    "rxDescRefr",
-    "rxDescRead",
-    "rxFifoBlock",
-    "rxFragWrite",
-    "rxDescWrite",
-    "rxAdvance"
-};
-
-const char *NsTxStateStrings[] =
-{
-    "txIdle",
-    "txDescRefr",
-    "txDescRead",
-    "txFifoBlock",
-    "txFragRead",
-    "txDescWrite",
-    "txAdvance"
-};
-
-const char *NsDmaState[] =
-{
-    "dmaIdle",
-    "dmaReading",
-    "dmaWriting",
-    "dmaReadWaiting",
-    "dmaWriteWaiting"
-};
-
-using namespace Net;
-using namespace TheISA;
-
-///////////////////////////////////////////////////////////////////////
-//
-// NSGigE PCI Device
-//
-NSGigE::NSGigE(Params *p)
-    : EtherDevBase(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), rxDmaFree(false), txDmaFree(false),
-      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
-      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
-      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
-      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
-      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
-      eepromOpcode(0), eepromAddress(0), eepromData(0),
-      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
-      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
-      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
-      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
-      rxDmaReadEvent(this), rxDmaWriteEvent(this),
-      txDmaReadEvent(this), txDmaWriteEvent(this),
-      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), multicastHashEnable(false),
-      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
-      intrEvent(0), interface(0)
-{
-
-
-    interface = new NSGigEInt(name() + ".int0", this);
-
-    regsReset();
-    memcpy(&rom.perfectMatch, p->hardware_address.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()
-{
-    delete interface;
-}
-
-/**
- * This is to write to the PCI general configuration registers
- */
-Tick
-NSGigE::writeConfig(PacketPtr pkt)
-{
-    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
-    if (offset < PCI_DEVICE_SPECIFIC)
-        PciDevice::writeConfig(pkt);
-    else
-        panic("Device specific PCI config space not implemented!\n");
-
-    switch (offset) {
-        // seems to work fine without all these PCI settings, but i
-        // put in the IO to double check, an assertion will fail if we
-        // need to properly implement it
-      case PCI_COMMAND:
-        if (config.data[offset] & PCI_CMD_IOSE)
-            ioEnable = true;
-        else
-            ioEnable = false;
-        break;
-    }
-
-    return configDelay;
-}
-
-EtherInt*
-NSGigE::getEthPort(const std::string &if_name, int idx)
-{
-    if (if_name == "interface") {
-       if (interface->getPeer())
-           panic("interface already connected to\n");
-       return interface;
-    }
-    return NULL;
-}
-
-/**
- * This reads the device registers, which are detailed in the NS83820
- * spec sheet
- */
-Tick
-NSGigE::read(PacketPtr pkt)
-{
-    assert(ioEnable);
-
-    //The mask is to give you only the offset into the device register file
-    Addr daddr = pkt->getAddr() & 0xfff;
-    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
-            daddr, pkt->getAddr(), pkt->getSize());
-
-
-    // there are some reserved registers, you can see ns_gige_reg.h and
-    // the spec sheet for details
-    if (daddr > LAST && daddr <=  RESERVED) {
-        panic("Accessing reserved register");
-    } else if (daddr > RESERVED && daddr <= 0x3FC) {
-        return readConfig(pkt);
-    } else if (daddr >= MIB_START && daddr <= MIB_END) {
-        // don't implement all the MIB's.  hopefully the kernel
-        // doesn't actually DEPEND upon their values
-        // MIB are just hardware stats keepers
-        pkt->set<uint32_t>(0);
-        pkt->makeAtomicResponse();
-        return pioDelay;
-    } else if (daddr > 0x3FC)
-        panic("Something is messed up!\n");
-
-    assert(pkt->getSize() == sizeof(uint32_t));
-        uint32_t &reg = *pkt->getPtr<uint32_t>();
-        uint16_t rfaddr;
-
-        switch (daddr) {
-          case CR:
-            reg = regs.command;
-            //these are supposed to be cleared on a read
-            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
-            break;
-
-          case CFGR:
-            reg = regs.config;
-            break;
-
-          case MEAR:
-            reg = regs.mear;
-            break;
-
-          case PTSCR:
-            reg = regs.ptscr;
-            break;
-
-          case ISR:
-            reg = regs.isr;
-            devIntrClear(ISR_ALL);
-            break;
-
-          case IMR:
-            reg = regs.imr;
-            break;
-
-          case IER:
-            reg = regs.ier;
-            break;
-
-          case IHR:
-            reg = regs.ihr;
-            break;
-
-          case TXDP:
-            reg = regs.txdp;
-            break;
-
-          case TXDP_HI:
-            reg = regs.txdp_hi;
-            break;
-
-          case TX_CFG:
-            reg = regs.txcfg;
-            break;
-
-          case GPIOR:
-            reg = regs.gpior;
-            break;
-
-          case RXDP:
-            reg = regs.rxdp;
-            break;
-
-          case RXDP_HI:
-            reg = regs.rxdp_hi;
-            break;
-
-          case RX_CFG:
-            reg = regs.rxcfg;
-            break;
-
-          case PQCR:
-            reg = regs.pqcr;
-            break;
-
-          case WCSR:
-            reg = regs.wcsr;
-            break;
-
-          case PCR:
-            reg = regs.pcr;
-            break;
-
-            // see the spec sheet for how RFCR and RFDR work
-            // basically, you write to RFCR to tell the machine
-            // what you want to do next, then you act upon RFDR,
-            // and the device will be prepared b/c of what you
-            // wrote to RFCR
-          case RFCR:
-            reg = regs.rfcr;
-            break;
-
-          case RFDR:
-            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
-            switch (rfaddr) {
-              // Read from perfect match ROM octets
-              case 0x000:
-                reg = rom.perfectMatch[1];
-                reg = reg << 8;
-                reg += rom.perfectMatch[0];
-                break;
-              case 0x002:
-                reg = rom.perfectMatch[3] << 8;
-                reg += rom.perfectMatch[2];
-                break;
-              case 0x004:
-                reg = rom.perfectMatch[5] << 8;
-                reg += rom.perfectMatch[4];
-                break;
-              default:
-                // 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;
-
-          case SRR:
-            reg = regs.srr;
-            break;
-
-          case MIBC:
-            reg = regs.mibc;
-            reg &= ~(MIBC_MIBS | MIBC_ACLR);
-            break;
-
-          case VRCR:
-            reg = regs.vrcr;
-            break;
-
-          case VTCR:
-            reg = regs.vtcr;
-            break;
-
-          case VDR:
-            reg = regs.vdr;
-            break;
-
-          case CCSR:
-            reg = regs.ccsr;
-            break;
-
-          case TBICR:
-            reg = regs.tbicr;
-            break;
-
-          case TBISR:
-            reg = regs.tbisr;
-            break;
-
-          case TANAR:
-            reg = regs.tanar;
-            break;
-
-          case TANLPAR:
-            reg = regs.tanlpar;
-            break;
-
-          case TANER:
-            reg = regs.taner;
-            break;
-
-          case TESR:
-            reg = regs.tesr;
-            break;
-
-          case M5REG:
-            reg = 0;
-            if (params()->rx_thread)
-                reg |= M5REG_RX_THREAD;
-            if (params()->tx_thread)
-                reg |= M5REG_TX_THREAD;
-            if (params()->rss)
-                reg |= M5REG_RSS;
-            break;
-
-          default:
-            panic("reading unimplemented register: addr=%#x", daddr);
-        }
-
-        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
-                daddr, reg, reg);
-
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-Tick
-NSGigE::write(PacketPtr pkt)
-{
-    assert(ioEnable);
-
-    Addr daddr = pkt->getAddr() & 0xfff;
-    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
-            daddr, pkt->getAddr(), pkt->getSize());
-
-    if (daddr > LAST && daddr <=  RESERVED) {
-        panic("Accessing reserved register");
-    } else if (daddr > RESERVED && daddr <= 0x3FC) {
-        return writeConfig(pkt);
-    } else if (daddr > 0x3FC)
-        panic("Something is messed up!\n");
-
-    if (pkt->getSize() == sizeof(uint32_t)) {
-        uint32_t reg = pkt->get<uint32_t>();
-        uint16_t rfaddr;
-
-        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
-
-        switch (daddr) {
-          case CR:
-            regs.command = reg;
-            if (reg & CR_TXD) {
-                txEnable = false;
-            } else if (reg & CR_TXE) {
-                txEnable = true;
-
-                // 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 (rxState == rxIdle)
-                    rxKick();
-            }
-
-            if (reg & CR_TXR)
-                txReset();
-
-            if (reg & CR_RXR)
-                rxReset();
-
-            if (reg & CR_SWI)
-                devIntrPost(ISR_SWI);
-
-            if (reg & CR_RST) {
-                txReset();
-                rxReset();
-
-                regsReset();
-            }
-            break;
-
-          case 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.
-
-// grouped together and #if 0'ed to avoid empty if body and make clang happy
-#if 0
-            if (reg & CFGR_TBI_EN) ;
-            if (reg & CFGR_MODE_1000) ;
-
-            if (reg & CFGR_PINT_DUPSTS ||
-                reg & CFGR_PINT_LNKSTS ||
-                reg & CFGR_PINT_SPDSTS)
-                ;
-
-            if (reg & CFGR_TMRTEST) ;
-            if (reg & CFGR_MRM_DIS) ;
-            if (reg & CFGR_MWI_DIS) ;
-
-            if (reg & CFGR_DATA64_EN) ;
-            if (reg & CFGR_M64ADDR) ;
-            if (reg & CFGR_PHY_RST) ;
-            if (reg & CFGR_PHY_DIS) ;
-
-            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) ;
-
-            if (reg & CFGR_T64ADDR) ;
-            // panic("CFGR_T64ADDR is read only register!\n");
-#endif
-            if (reg & CFGR_AUTO_1000)
-                panic("CFGR_AUTO_1000 not implemented!\n");
-
-            if (reg & CFGR_PCI64_DET)
-                panic("CFGR_PCI64_DET is read only register!\n");
-
-            if (reg & CFGR_EXTSTS_EN)
-                extstsEnable = true;
-            else
-                extstsEnable = false;
-            break;
-
-          case MEAR:
-            // 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
-
-// grouped together and #if 0'ed to avoid empty if body and make clang happy
-#if 0
-            if (reg & MEAR_MDIO) ;
-            if (reg & MEAR_MDDIR) ;
-            if (reg & MEAR_MDC) ;
-#endif
-            break;
-
-          case PTSCR:
-            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
-            // these control BISTs for various parts of chip - we
-            // don't care or do just fake that the BIST is done
-            if (reg & PTSCR_RBIST_EN)
-                regs.ptscr |= PTSCR_RBIST_DONE;
-            if (reg & PTSCR_EEBIST_EN)
-                regs.ptscr &= ~PTSCR_EEBIST_EN;
-            if (reg & PTSCR_EELOAD_EN)
-                regs.ptscr &= ~PTSCR_EELOAD_EN;
-            break;
-
-          case ISR: /* writing to the ISR has no effect */
-            panic("ISR is a read only register!\n");
-
-          case IMR:
-            regs.imr = reg;
-            devIntrChangeMask();
-            break;
-
-          case IER:
-            regs.ier = reg;
-            break;
-
-          case IHR:
-            regs.ihr = reg;
-            /* not going to implement real interrupt holdoff */
-            break;
-
-          case TXDP:
-            regs.txdp = (reg & 0xFFFFFFFC);
-            assert(txState == txIdle);
-            CTDD = false;
-            break;
-
-          case TXDP_HI:
-            regs.txdp_hi = reg;
-            break;
-
-          case TX_CFG:
-            regs.txcfg = reg;
-#if 0
-            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
-                 * sense to do this
-                 */
-            }
-
-            if (reg & TX_CFG_BRST_DIS) ;
-#endif
-
-#if 0
-            /* we handle our own DMA, ignore the kernel's exhortations */
-            if (reg & TX_CFG_MXDMA) ;
-#endif
-
-            // 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
-
-            break;
-
-          case GPIOR:
-            // 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;
-
-          case RXDP:
-            regs.rxdp = reg;
-            CRDD = false;
-            break;
-
-          case RXDP_HI:
-            regs.rxdp_hi = reg;
-            break;
-
-          case RX_CFG:
-            regs.rxcfg = reg;
-#if 0
-            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 & 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 & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
-#endif
-            break;
-
-          case PQCR:
-            /* there is no priority queueing used in the linux 2.6 driver */
-            regs.pqcr = reg;
-            break;
-
-          case WCSR:
-            /* not going to implement wake on LAN */
-            regs.wcsr = reg;
-            break;
-
-          case PCR:
-            /* not going to implement pause control */
-            regs.pcr = reg;
-            break;
-
-          case RFCR:
-            regs.rfcr = reg;
-
-            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
-            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
-            acceptMulticast = (reg & RFCR_AAM) ? true : false;
-            acceptUnicast = (reg & RFCR_AAU) ? true : false;
-            acceptPerfect = (reg & RFCR_APM) ? true : false;
-            acceptArp = (reg & RFCR_AARP) ? true : false;
-            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
-
-#if 0
-            if (reg & RFCR_APAT)
-                panic("RFCR_APAT not implemented!\n");
-#endif
-            if (reg & RFCR_UHEN)
-                panic("Unicast hash filtering not used by drivers!\n");
-
-            if (reg & RFCR_ULM)
-                panic("RFCR_ULM not implemented!\n");
-
-            break;
-
-          case RFDR:
-            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:
-            regs.brar = reg;
-            break;
-
-          case BRDR:
-            panic("the driver never uses BRDR, something is wrong!\n");
-
-          case SRR:
-            panic("SRR is read only register!\n");
-
-          case MIBC:
-            panic("the driver never uses MIBC, something is wrong!\n");
-
-          case VRCR:
-            regs.vrcr = reg;
-            break;
-
-          case VTCR:
-            regs.vtcr = reg;
-            break;
-
-          case VDR:
-            panic("the driver never uses VDR, something is wrong!\n");
-
-          case CCSR:
-            /* not going to implement clockrun stuff */
-            regs.ccsr = reg;
-            break;
-
-          case TBICR:
-            regs.tbicr = reg;
-            if (reg & TBICR_MR_LOOPBACK)
-                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
-
-            if (reg & TBICR_MR_AN_ENABLE) {
-                regs.tanlpar = regs.tanar;
-                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
-            }
-
-#if 0
-            if (reg & TBICR_MR_RESTART_AN) ;
-#endif
-
-            break;
-
-          case TBISR:
-            panic("TBISR is read only register!\n");
-
-          case TANAR:
-            // 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
-
-            break;
-
-          case TANLPAR:
-            panic("this should only be written to by the fake phy!\n");
-
-          case TANER:
-            panic("TANER is read only register!\n");
-
-          case TESR:
-            regs.tesr = reg;
-            break;
-
-          default:
-            panic("invalid register access daddr=%#x", daddr);
-        }
-    } else {
-        panic("Invalid Request Size");
-    }
-    pkt->makeAtomicResponse();
-    return pioDelay;
-}
-
-void
-NSGigE::devIntrPost(uint32_t interrupts)
-{
-    if (interrupts & ISR_RESERVE)
-        panic("Cannot set a reserved interrupt");
-
-    if (interrupts & ISR_NOIMPL)
-        warn("interrupt not implemented %#x\n", interrupts);
-
-    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) == 0)
-            when += intrDelay;
-        postedInterrupts++;
-        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++;
-    }
-
-    interrupts &= ~ISR_NOIMPL;
-    regs.isr &= ~interrupts;
-
-    DPRINTF(EthernetIntr,
-            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
-            interrupts, regs.isr, regs.imr);
-
-    if (!(regs.isr & regs.imr))
-        cpuIntrClear();
-}
-
-void
-NSGigE::devIntrChangeMask()
-{
-    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
-            regs.isr, regs.imr, regs.isr & regs.imr);
-
-    if (regs.isr & regs.imr)
-        cpuIntrPost(curTick());
-    else
-        cpuIntrClear();
-}
-
-void
-NSGigE::cpuIntrPost(Tick when)
-{
-    // If the interrupt you want to post is later than an interrupt
-    // already scheduled, just let it post in the coming one and don't
-    // schedule another.
-    // HOWEVER, must be sure that the scheduled intrTick is in the
-    // future (this was formerly the source of a bug)
-    /**
-     * @todo this warning should be removed and the intrTick code should
-     * be fixed.
-     */
-    assert(when >= curTick());
-    assert(intrTick >= curTick() || intrTick == 0);
-    if (when > intrTick && intrTick != 0) {
-        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
-                intrTick);
-        return;
-    }
-
-    intrTick = when;
-    if (intrTick < curTick()) {
-        Debug::breakpoint();
-        intrTick = curTick();
-    }
-
-    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
-            intrTick);
-
-    if (intrEvent)
-        intrEvent->squash();
-    intrEvent = new IntrEvent(this, true);
-    schedule(intrEvent, intrTick);
-}
-
-void
-NSGigE::cpuInterrupt()
-{
-    assert(intrTick == curTick());
-
-    // Whether or not there's a pending interrupt, we don't care about
-    // it anymore
-    intrEvent = 0;
-    intrTick = 0;
-
-    // Don't send an interrupt if there's already one
-    if (cpuPendingIntr) {
-        DPRINTF(EthernetIntr,
-                "would send an interrupt now, but there's already pending\n");
-    } else {
-        // Send interrupt
-        cpuPendingIntr = true;
-
-        DPRINTF(EthernetIntr, "posting interrupt\n");
-        intrPost();
-    }
-}
-
-void
-NSGigE::cpuIntrClear()
-{
-    if (!cpuPendingIntr)
-        return;
-
-    if (intrEvent) {
-        intrEvent->squash();
-        intrEvent = 0;
-    }
-
-    intrTick = 0;
-
-    cpuPendingIntr = false;
-
-    DPRINTF(EthernetIntr, "clearing interrupt\n");
-    intrClear();
-}
-
-bool
-NSGigE::cpuIntrPending() const
-{ return cpuPendingIntr; }
-
-void
-NSGigE::txReset()
-{
-
-    DPRINTF(Ethernet, "transmit reset\n");
-
-    CTDD = false;
-    txEnable = false;;
-    txFragPtr = 0;
-    assert(txDescCnt == 0);
-    txFifo.clear();
-    txState = txIdle;
-    assert(txDmaState == dmaIdle);
-}
-
-void
-NSGigE::rxReset()
-{
-    DPRINTF(Ethernet, "receive reset\n");
-
-    CRDD = false;
-    assert(rxPktBytes == 0);
-    rxEnable = false;
-    rxFragPtr = 0;
-    assert(rxDescCnt == 0);
-    assert(rxDmaState == dmaIdle);
-    rxFifo.clear();
-    rxState = rxIdle;
-}
-
-void
-NSGigE::regsReset()
-{
-    memset(&regs, 0, sizeof(regs));
-    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
-    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
-    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;
-    acceptMulticast = false;
-    acceptUnicast = false;
-    acceptPerfect = false;
-    acceptArp = false;
-}
-
-bool
-NSGigE::doRxDmaRead()
-{
-    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
-    rxDmaState = dmaReading;
-
-    if (dmaPending() || drainState() != DrainState::Running)
-        rxDmaState = dmaReadWaiting;
-    else
-        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
-
-    return true;
-}
-
-void
-NSGigE::rxDmaReadDone()
-{
-    assert(rxDmaState == dmaReading);
-    rxDmaState = dmaIdle;
-
-    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
-            rxDmaAddr, rxDmaLen);
-    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
-
-    // If the transmit state machine has a pending DMA, let it go first
-    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
-        txKick();
-
-    rxKick();
-}
-
-bool
-NSGigE::doRxDmaWrite()
-{
-    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
-    rxDmaState = dmaWriting;
-
-    if (dmaPending() || drainState() != DrainState::Running)
-        rxDmaState = dmaWriteWaiting;
-    else
-        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
-    return true;
-}
-
-void
-NSGigE::rxDmaWriteDone()
-{
-    assert(rxDmaState == dmaWriting);
-    rxDmaState = dmaIdle;
-
-    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
-            rxDmaAddr, rxDmaLen);
-    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
-
-    // If the transmit state machine has a pending DMA, let it go first
-    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
-        txKick();
-
-    rxKick();
-}
-
-void
-NSGigE::rxKick()
-{
-    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
-
-    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 (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 = clockEdge(Cycles(1));
-
-    switch(rxDmaState) {
-      case dmaReadWaiting:
-        if (doRxDmaRead())
-            goto exit;
-        break;
-      case dmaWriteWaiting:
-        if (doRxDmaWrite())
-            goto exit;
-        break;
-      default:
-        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
-    // label "next".  however, if you have intermediate work, like DMA
-    // so that you can't go to the next state yet, you go to exit and
-    // exit the loop.  however, when the DMA is done it will trigger
-    // an event and come back to this loop.
-    switch (rxState) {
-      case rxIdle:
-        if (!rxEnable) {
-            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
-            goto exit;
-        }
-
-        if (CRDD) {
-            rxState = rxDescRefr;
-
-            rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData =
-                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
-            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
-            rxDmaFree = dmaDescFree;
-
-            descDmaReads++;
-            descDmaRdBytes += rxDmaLen;
-
-            if (doRxDmaRead())
-                goto exit;
-        } else {
-            rxState = rxDescRead;
-
-            rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
-            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
-            rxDmaFree = dmaDescFree;
-
-            descDmaReads++;
-            descDmaRdBytes += rxDmaLen;
-
-            if (doRxDmaRead())
-                goto exit;
-        }
-        break;
-
-      case rxDescRefr:
-        if (rxDmaState != dmaIdle)
-            goto exit;
-
-        rxState = rxAdvance;
-        break;
-
-     case rxDescRead:
-        if (rxDmaState != dmaIdle)
-            goto exit;
-
-        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
-                regs.rxdp & 0x3fffffff);
-        DPRINTF(EthernetDesc,
-                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
-                link, bufptr, cmdsts, extsts);
-
-        if (cmdsts & CMDSTS_OWN) {
-            devIntrPost(ISR_RXIDLE);
-            rxState = rxIdle;
-            goto exit;
-        } else {
-            rxState = rxFifoBlock;
-            rxFragPtr = bufptr;
-            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
-        }
-        break;
-
-      case rxFifoBlock:
-        if (!rxPacket) {
-            /**
-             * @todo in reality, we should be able to start processing
-             * the packet as it arrives, and not have to wait for the
-             * full packet ot be in the receive fifo.
-             */
-            if (rxFifo.empty())
-                goto exit;
-
-            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
-
-            // If we don't have a packet, grab a new one from the fifo.
-            rxPacket = rxFifo.front();
-            rxPktBytes = rxPacket->length;
-            rxPacketBufPtr = rxPacket->data;
-
-#if TRACING_ON
-            if (DTRACE(Ethernet)) {
-                IpPtr ip(rxPacket);
-                if (ip) {
-                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
-                    TcpPtr tcp(ip);
-                    if (tcp) {
-                        DPRINTF(Ethernet,
-                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
-                                tcp->sport(), tcp->dport(), tcp->seq(),
-                                tcp->ack());
-                    }
-                }
-            }
-#endif
-
-            // sanity check - i think the driver behaves like this
-            assert(rxDescCnt >= rxPktBytes);
-            rxFifo.pop();
-        }
-
-
-        // dont' need the && rxDescCnt > 0 if driver sanity check
-        // above holds
-        if (rxPktBytes > 0) {
-            rxState = rxFragWrite;
-            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
-            // check holds
-            rxXferLen = rxPktBytes;
-
-            rxDmaAddr = rxFragPtr & 0x3fffffff;
-            rxDmaData = rxPacketBufPtr;
-            rxDmaLen = rxXferLen;
-            rxDmaFree = dmaDataFree;
-
-            if (doRxDmaWrite())
-                goto exit;
-
-        } else {
-            rxState = rxDescWrite;
-
-            //if (rxPktBytes == 0) {  /* packet is done */
-            assert(rxPktBytes == 0);
-            DPRINTF(EthernetSM, "done with receiving packet\n");
-
-            cmdsts |= CMDSTS_OWN;
-            cmdsts &= ~CMDSTS_MORE;
-            cmdsts |= CMDSTS_OK;
-            cmdsts &= 0xffff0000;
-            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
-
-#if 0
-            /*
-             * all the driver uses these are for its own stats keeping
-             * which we don't care about, aren't necessary for
-             * functionality and doing this would just slow us down.
-             * if they end up using this in a later version for
-             * functional purposes, just undef
-             */
-            if (rxFilterEnable) {
-                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
-
-            IpPtr ip(rxPacket);
-            if (extstsEnable && ip) {
-                extsts |= EXTSTS_IPPKT;
-                rxIpChecksums++;
-                if (cksum(ip) != 0) {
-                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
-                    extsts |= EXTSTS_IPERR;
-                }
-                TcpPtr tcp(ip);
-                UdpPtr udp(ip);
-                if (tcp) {
-                    extsts |= EXTSTS_TCPPKT;
-                    rxTcpChecksums++;
-                    if (cksum(tcp) != 0) {
-                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
-                        extsts |= EXTSTS_TCPERR;
-
-                    }
-                } else if (udp) {
-                    extsts |= EXTSTS_UDPPKT;
-                    rxUdpChecksums++;
-                    if (cksum(udp) != 0) {
-                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
-                        extsts |= EXTSTS_UDPERR;
-                    }
-                }
-            }
-            rxPacket = 0;
-
-            /*
-             * the driver seems to always receive into desc buffers
-             * of size 1514, so you never have a pkt that is split
-             * into multiple descriptors on the receive side, so
-             * i don't implement that case, hence the assert above.
-             */
-
-            DPRINTF(EthernetDesc,
-                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
-                    regs.rxdp & 0x3fffffff);
-            DPRINTF(EthernetDesc,
-                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
-                    link, bufptr, cmdsts, 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++;
-            descDmaWrBytes += rxDmaLen;
-
-            if (doRxDmaWrite())
-                goto exit;
-        }
-        break;
-
-      case rxFragWrite:
-        if (rxDmaState != dmaIdle)
-            goto exit;
-
-        rxPacketBufPtr += rxXferLen;
-        rxFragPtr += rxXferLen;
-        rxPktBytes -= rxXferLen;
-
-        rxState = rxFifoBlock;
-        break;
-
-      case rxDescWrite:
-        if (rxDmaState != dmaIdle)
-            goto exit;
-
-        assert(cmdsts & CMDSTS_OWN);
-
-        assert(rxPacket == 0);
-        devIntrPost(ISR_RXOK);
-
-        if (cmdsts & CMDSTS_INTR)
-            devIntrPost(ISR_RXDESC);
-
-        if (!rxEnable) {
-            DPRINTF(EthernetSM, "Halting the RX state machine\n");
-            rxState = rxIdle;
-            goto exit;
-        } else
-            rxState = rxAdvance;
-        break;
-
-      case rxAdvance:
-        if (link == 0) {
-            devIntrPost(ISR_RXIDLE);
-            rxState = rxIdle;
-            CRDD = true;
-            goto exit;
-        } else {
-            if (rxDmaState != dmaIdle)
-                goto exit;
-            rxState = rxDescRead;
-            regs.rxdp = link;
-            CRDD = false;
-
-            rxDmaAddr = regs.rxdp & 0x3fffffff;
-            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
-            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
-            rxDmaFree = dmaDescFree;
-
-            if (doRxDmaRead())
-                goto exit;
-        }
-        break;
-
-      default:
-        panic("Invalid rxState!");
-    }
-
-    DPRINTF(EthernetSM, "entering next rxState=%s\n",
-            NsRxStateStrings[rxState]);
-    goto next;
-
-  exit:
-    /**
-     * @todo do we want to schedule a future kick?
-     */
-    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
-            NsRxStateStrings[rxState]);
-
-    if (!rxKickEvent.scheduled())
-        schedule(rxKickEvent, rxKickTick);
-}
-
-void
-NSGigE::transmit()
-{
-    if (txFifo.empty()) {
-        DPRINTF(Ethernet, "nothing to transmit\n");
-        return;
-    }
-
-    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
-            txFifo.size());
-    if (interface->sendPacket(txFifo.front())) {
-#if TRACING_ON
-        if (DTRACE(Ethernet)) {
-            IpPtr ip(txFifo.front());
-            if (ip) {
-                DPRINTF(Ethernet, "ID is %d\n", ip->id());
-                TcpPtr tcp(ip);
-                if (tcp) {
-                    DPRINTF(Ethernet,
-                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
-                            tcp->sport(), tcp->dport(), tcp->seq(),
-                            tcp->ack());
-                }
-            }
-        }
-#endif
-
-        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
-        txBytes += txFifo.front()->length;
-        txPackets++;
-
-        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
-                txFifo.avail());
-        txFifo.pop();
-
-        /*
-         * normally do a writeback of the descriptor here, and ONLY
-         * after that is done, send this interrupt.  but since our
-         * stuff never actually fails, just do this interrupt here,
-         * otherwise the code has to stray from this nice format.
-         * besides, it's functionally the same.
-         */
-        devIntrPost(ISR_TXOK);
-    }
-
-   if (!txFifo.empty() && !txEvent.scheduled()) {
-       DPRINTF(Ethernet, "reschedule transmit\n");
-       schedule(txEvent, curTick() + retryTime);
-   }
-}
-
-bool
-NSGigE::doTxDmaRead()
-{
-    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
-    txDmaState = dmaReading;
-
-    if (dmaPending() || drainState() != DrainState::Running)
-        txDmaState = dmaReadWaiting;
-    else
-        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
-
-    return true;
-}
-
-void
-NSGigE::txDmaReadDone()
-{
-    assert(txDmaState == dmaReading);
-    txDmaState = dmaIdle;
-
-    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
-            txDmaAddr, txDmaLen);
-    DDUMP(EthernetDMA, txDmaData, txDmaLen);
-
-    // If the receive state machine  has a pending DMA, let it go first
-    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
-        rxKick();
-
-    txKick();
-}
-
-bool
-NSGigE::doTxDmaWrite()
-{
-    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
-    txDmaState = dmaWriting;
-
-    if (dmaPending() || drainState() != DrainState::Running)
-        txDmaState = dmaWriteWaiting;
-    else
-        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
-    return true;
-}
-
-void
-NSGigE::txDmaWriteDone()
-{
-    assert(txDmaState == dmaWriting);
-    txDmaState = dmaIdle;
-
-    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
-            txDmaAddr, txDmaLen);
-    DDUMP(EthernetDMA, txDmaData, txDmaLen);
-
-    // If the receive state machine  has a pending DMA, let it go first
-    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
-        rxKick();
-
-    txKick();
-}
-
-void
-NSGigE::txKick()
-{
-    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
-
-    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
-            NsTxStateStrings[txState], is64bit ? 64 : 32);
-
-    Addr link, bufptr;
-    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
-    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
-
-  next:
-    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 = clockEdge(Cycles(1));
-
-    switch(txDmaState) {
-      case dmaReadWaiting:
-        if (doTxDmaRead())
-            goto exit;
-        break;
-      case dmaWriteWaiting:
-        if (doTxDmaWrite())
-            goto exit;
-        break;
-      default:
-        break;
-    }
-
-    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
-    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
-    switch (txState) {
-      case txIdle:
-        if (!txEnable) {
-            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
-            goto exit;
-        }
-
-        if (CTDD) {
-            txState = txDescRefr;
-
-            txDmaAddr = regs.txdp & 0x3fffffff;
-            txDmaData =
-                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
-            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
-            txDmaFree = dmaDescFree;
-
-            descDmaReads++;
-            descDmaRdBytes += txDmaLen;
-
-            if (doTxDmaRead())
-                goto exit;
-
-        } else {
-            txState = txDescRead;
-
-            txDmaAddr = regs.txdp & 0x3fffffff;
-            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
-            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
-            txDmaFree = dmaDescFree;
-
-            descDmaReads++;
-            descDmaRdBytes += txDmaLen;
-
-            if (doTxDmaRead())
-                goto exit;
-        }
-        break;
-
-      case txDescRefr:
-        if (txDmaState != dmaIdle)
-            goto exit;
-
-        txState = txAdvance;
-        break;
-
-      case txDescRead:
-        if (txDmaState != dmaIdle)
-            goto exit;
-
-        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
-                regs.txdp & 0x3fffffff);
-        DPRINTF(EthernetDesc,
-                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
-                link, bufptr, cmdsts, extsts);
-
-        if (cmdsts & CMDSTS_OWN) {
-            txState = txFifoBlock;
-            txFragPtr = bufptr;
-            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
-        } else {
-            devIntrPost(ISR_TXIDLE);
-            txState = txIdle;
-            goto exit;
-        }
-        break;
-
-      case txFifoBlock:
-        if (!txPacket) {
-            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
-            txPacket = make_shared<EthPacketData>(16384);
-            txPacketBufPtr = txPacket->data;
-        }
-
-        if (txDescCnt == 0) {
-            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
-            if (cmdsts & CMDSTS_MORE) {
-                DPRINTF(EthernetSM, "there are more descriptors to come\n");
-                txState = txDescWrite;
-
-                cmdsts &= ~CMDSTS_OWN;
-
-                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())
-                    goto exit;
-
-            } else { /* this packet is totally done */
-                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) {
-                    IpPtr ip(txPacket);
-                    if (extsts & EXTSTS_UDPPKT) {
-                        UdpPtr udp(ip);
-                        if (udp) {
-                            udp->sum(0);
-                            udp->sum(cksum(udp));
-                            txUdpChecksums++;
-                        } else {
-                            Debug::breakpoint();
-                            warn_once("UDPPKT set, but not UDP!\n");
-                        }
-                    } else if (extsts & EXTSTS_TCPPKT) {
-                        TcpPtr tcp(ip);
-                        if (tcp) {
-                            tcp->sum(0);
-                            tcp->sum(cksum(tcp));
-                            txTcpChecksums++;
-                        } else {
-                            Debug::breakpoint();
-                            warn_once("TCPPKT set, but not UDP!\n");
-                        }
-                    }
-                    if (extsts & EXTSTS_IPPKT) {
-                        if (ip) {
-                            ip->sum(0);
-                            ip->sum(cksum(ip));
-                            txIpChecksums++;
-                        } else {
-                            Debug::breakpoint();
-                            warn_once("IPPKT set, but not UDP!\n");
-                        }
-                    }
-                }
-
-                txPacket->length = txPacketBufPtr - txPacket->data;
-                // this is just because the receive can't handle a
-                // packet bigger want to make sure
-                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
-                 * functionally shouldn't be any different.  normally,
-                 * the chip will wait til the transmit has occurred
-                 * before writing back the descriptor because it has
-                 * to wait to see that it was successfully transmitted
-                 * to decide whether to set CMDSTS_OK or not.
-                 * however, in the simulator since it is always
-                 * successfully transmitted, and writing it exactly to
-                 * spec would complicate the code, we just do it here
-                 */
-
-                cmdsts &= ~CMDSTS_OWN;
-                cmdsts |= CMDSTS_OK;
-
-                DPRINTF(EthernetDesc,
-                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
-                        cmdsts, 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;
-
-                transmit();
-                txPacket = 0;
-
-                if (!txEnable) {
-                    DPRINTF(EthernetSM, "halting TX state machine\n");
-                    txState = txIdle;
-                    goto exit;
-                } else
-                    txState = txAdvance;
-
-                if (doTxDmaWrite())
-                    goto exit;
-            }
-        } else {
-            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
-            if (!txFifo.full()) {
-                txState = txFragRead;
-
-                /*
-                 * The number of bytes transferred is either whatever
-                 * is left in the descriptor (txDescCnt), or if there
-                 * is not enough room in the fifo, just whatever room
-                 * is left in the fifo
-                 */
-                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
-
-                txDmaAddr = txFragPtr & 0x3fffffff;
-                txDmaData = txPacketBufPtr;
-                txDmaLen = txXferLen;
-                txDmaFree = dmaDataFree;
-
-                if (doTxDmaRead())
-                    goto exit;
-            } else {
-                txState = txFifoBlock;
-                transmit();
-
-                goto exit;
-            }
-
-        }
-        break;
-
-      case txFragRead:
-        if (txDmaState != dmaIdle)
-            goto exit;
-
-        txPacketBufPtr += txXferLen;
-        txFragPtr += txXferLen;
-        txDescCnt -= txXferLen;
-        txFifo.reserve(txXferLen);
-
-        txState = txFifoBlock;
-        break;
-
-      case txDescWrite:
-        if (txDmaState != dmaIdle)
-            goto exit;
-
-        if (cmdsts & CMDSTS_INTR)
-            devIntrPost(ISR_TXDESC);
-
-        if (!txEnable) {
-            DPRINTF(EthernetSM, "halting TX state machine\n");
-            txState = txIdle;
-            goto exit;
-        } else
-            txState = txAdvance;
-        break;
-
-      case txAdvance:
-        if (link == 0) {
-            devIntrPost(ISR_TXIDLE);
-            txState = txIdle;
-            goto exit;
-        } else {
-            if (txDmaState != dmaIdle)
-                goto exit;
-            txState = txDescRead;
-            regs.txdp = link;
-            CTDD = false;
-
-            txDmaAddr = link & 0x3fffffff;
-            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
-            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
-            txDmaFree = dmaDescFree;
-
-            if (doTxDmaRead())
-                goto exit;
-        }
-        break;
-
-      default:
-        panic("invalid state");
-    }
-
-    DPRINTF(EthernetSM, "entering next txState=%s\n",
-            NsTxStateStrings[txState]);
-    goto next;
-
-  exit:
-    /**
-     * @todo do we want to schedule a future kick?
-     */
-    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
-            NsTxStateStrings[txState]);
-
-    if (!txKickEvent.scheduled())
-        schedule(txKickEvent, 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
-NSGigE::transferDone()
-{
-    if (txFifo.empty()) {
-        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
-        return;
-    }
-
-    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
-
-    reschedule(txEvent, clockEdge(Cycles(1)), true);
-}
-
-bool
-NSGigE::rxFilter(const EthPacketPtr &packet)
-{
-    EthPtr eth = packet;
-    bool drop = true;
-    string type;
-
-    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 && dst == rom.perfectMatch)
-            drop = false;
-
-        if (acceptArp && eth->type() == ETH_TYPE_ARP)
-            drop = false;
-
-    } else if (dst.broadcast()) {
-        // if we're accepting broadcasts
-        if (acceptBroadcast)
-            drop = false;
-
-    } 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) {
-        DPRINTF(Ethernet, "rxFilter drop\n");
-        DDUMP(EthernetData, packet->data, packet->length);
-    }
-
-    return drop;
-}
-
-bool
-NSGigE::recvPacket(EthPacketPtr packet)
-{
-    rxBytes += packet->length;
-    rxPackets++;
-
-    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
-            rxFifo.avail());
-
-    if (!rxEnable) {
-        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
-        return true;
-    }
-
-    if (!rxFilterEnable) {
-        DPRINTF(Ethernet,
-            "receive packet filtering disabled . . . packet dropped\n");
-        return true;
-    }
-
-    if (rxFilter(packet)) {
-        DPRINTF(Ethernet, "packet filtered...dropped\n");
-        return true;
-    }
-
-    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(packet);
-
-    rxKick();
-    return true;
-}
-
-
-void
-NSGigE::drainResume()
-{
-    Drainable::drainResume();
-
-    // During drain we could have left the state machines in a waiting state and
-    // they wouldn't get out until some other event occured to kick them.
-    // This way they'll get out immediately
-    txKick();
-    rxKick();
-}
-
-
-//=====================================================================
-//
-//
-void
-NSGigE::serialize(CheckpointOut &cp) const
-{
-    // Serialize the PciDevice base class
-    PciDevice::serialize(cp);
-
-    /*
-     * Finalize any DMA events now.
-     */
-    // @todo will mem system save pending dma?
-
-    /*
-     * Serialize the device registers
-     */
-    SERIALIZE_SCALAR(regs.command);
-    SERIALIZE_SCALAR(regs.config);
-    SERIALIZE_SCALAR(regs.mear);
-    SERIALIZE_SCALAR(regs.ptscr);
-    SERIALIZE_SCALAR(regs.isr);
-    SERIALIZE_SCALAR(regs.imr);
-    SERIALIZE_SCALAR(regs.ier);
-    SERIALIZE_SCALAR(regs.ihr);
-    SERIALIZE_SCALAR(regs.txdp);
-    SERIALIZE_SCALAR(regs.txdp_hi);
-    SERIALIZE_SCALAR(regs.txcfg);
-    SERIALIZE_SCALAR(regs.gpior);
-    SERIALIZE_SCALAR(regs.rxdp);
-    SERIALIZE_SCALAR(regs.rxdp_hi);
-    SERIALIZE_SCALAR(regs.rxcfg);
-    SERIALIZE_SCALAR(regs.pqcr);
-    SERIALIZE_SCALAR(regs.wcsr);
-    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);
-    SERIALIZE_SCALAR(regs.vtcr);
-    SERIALIZE_SCALAR(regs.vdr);
-    SERIALIZE_SCALAR(regs.ccsr);
-    SERIALIZE_SCALAR(regs.tbicr);
-    SERIALIZE_SCALAR(regs.tbisr);
-    SERIALIZE_SCALAR(regs.tanar);
-    SERIALIZE_SCALAR(regs.tanlpar);
-    SERIALIZE_SCALAR(regs.taner);
-    SERIALIZE_SCALAR(regs.tesr);
-
-    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
-    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
-
-    SERIALIZE_SCALAR(ioEnable);
-
-    /*
-     * Serialize the data Fifos
-     */
-    rxFifo.serialize("rxFifo", cp);
-    txFifo.serialize("txFifo", cp);
-
-    /*
-     * Serialize the various helper variables
-     */
-    bool txPacketExists = txPacket != nullptr;
-    SERIALIZE_SCALAR(txPacketExists);
-    if (txPacketExists) {
-        txPacket->length = txPacketBufPtr - txPacket->data;
-        txPacket->serialize("txPacket", cp);
-        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
-        SERIALIZE_SCALAR(txPktBufPtr);
-    }
-
-    bool rxPacketExists = rxPacket != nullptr;
-    SERIALIZE_SCALAR(rxPacketExists);
-    if (rxPacketExists) {
-        rxPacket->serialize("rxPacket", cp);
-        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
-        SERIALIZE_SCALAR(rxPktBufPtr);
-    }
-
-    SERIALIZE_SCALAR(txXferLen);
-    SERIALIZE_SCALAR(rxXferLen);
-
-    /*
-     * Serialize Cached Descriptors
-     */
-    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
-     */
-    int txState = this->txState;
-    SERIALIZE_SCALAR(txState);
-    SERIALIZE_SCALAR(txEnable);
-    SERIALIZE_SCALAR(CTDD);
-    SERIALIZE_SCALAR(txFragPtr);
-    SERIALIZE_SCALAR(txDescCnt);
-    int txDmaState = this->txDmaState;
-    SERIALIZE_SCALAR(txDmaState);
-    SERIALIZE_SCALAR(txKickTick);
-
-    /*
-     * Serialize rx state machine
-     */
-    int rxState = this->rxState;
-    SERIALIZE_SCALAR(rxState);
-    SERIALIZE_SCALAR(rxEnable);
-    SERIALIZE_SCALAR(CRDD);
-    SERIALIZE_SCALAR(rxPktBytes);
-    SERIALIZE_SCALAR(rxFragPtr);
-    SERIALIZE_SCALAR(rxDescCnt);
-    int rxDmaState = this->rxDmaState;
-    SERIALIZE_SCALAR(rxDmaState);
-    SERIALIZE_SCALAR(rxKickTick);
-
-    /*
-     * 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
-     * reschedule it later
-     */
-    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
-    SERIALIZE_SCALAR(transmitTick);
-
-    /*
-     * receive address filter settings
-     */
-    SERIALIZE_SCALAR(rxFilterEnable);
-    SERIALIZE_SCALAR(acceptBroadcast);
-    SERIALIZE_SCALAR(acceptMulticast);
-    SERIALIZE_SCALAR(acceptUnicast);
-    SERIALIZE_SCALAR(acceptPerfect);
-    SERIALIZE_SCALAR(acceptArp);
-    SERIALIZE_SCALAR(multicastHashEnable);
-
-    /*
-     * Keep track of pending interrupt status.
-     */
-    SERIALIZE_SCALAR(intrTick);
-    SERIALIZE_SCALAR(cpuPendingIntr);
-    Tick intrEventTick = 0;
-    if (intrEvent)
-        intrEventTick = intrEvent->when();
-    SERIALIZE_SCALAR(intrEventTick);
-
-}
-
-void
-NSGigE::unserialize(CheckpointIn &cp)
-{
-    // Unserialize the PciDevice base class
-    PciDevice::unserialize(cp);
-
-    UNSERIALIZE_SCALAR(regs.command);
-    UNSERIALIZE_SCALAR(regs.config);
-    UNSERIALIZE_SCALAR(regs.mear);
-    UNSERIALIZE_SCALAR(regs.ptscr);
-    UNSERIALIZE_SCALAR(regs.isr);
-    UNSERIALIZE_SCALAR(regs.imr);
-    UNSERIALIZE_SCALAR(regs.ier);
-    UNSERIALIZE_SCALAR(regs.ihr);
-    UNSERIALIZE_SCALAR(regs.txdp);
-    UNSERIALIZE_SCALAR(regs.txdp_hi);
-    UNSERIALIZE_SCALAR(regs.txcfg);
-    UNSERIALIZE_SCALAR(regs.gpior);
-    UNSERIALIZE_SCALAR(regs.rxdp);
-    UNSERIALIZE_SCALAR(regs.rxdp_hi);
-    UNSERIALIZE_SCALAR(regs.rxcfg);
-    UNSERIALIZE_SCALAR(regs.pqcr);
-    UNSERIALIZE_SCALAR(regs.wcsr);
-    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);
-    UNSERIALIZE_SCALAR(regs.vtcr);
-    UNSERIALIZE_SCALAR(regs.vdr);
-    UNSERIALIZE_SCALAR(regs.ccsr);
-    UNSERIALIZE_SCALAR(regs.tbicr);
-    UNSERIALIZE_SCALAR(regs.tbisr);
-    UNSERIALIZE_SCALAR(regs.tanar);
-    UNSERIALIZE_SCALAR(regs.tanlpar);
-    UNSERIALIZE_SCALAR(regs.taner);
-    UNSERIALIZE_SCALAR(regs.tesr);
-
-    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
-    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
-
-    UNSERIALIZE_SCALAR(ioEnable);
-
-    /*
-     * unserialize the data fifos
-     */
-    rxFifo.unserialize("rxFifo", cp);
-    txFifo.unserialize("txFifo", cp);
-
-    /*
-     * unserialize the various helper variables
-     */
-    bool txPacketExists;
-    UNSERIALIZE_SCALAR(txPacketExists);
-    if (txPacketExists) {
-        txPacket = make_shared<EthPacketData>(16384);
-        txPacket->unserialize("txPacket", cp);
-        uint32_t txPktBufPtr;
-        UNSERIALIZE_SCALAR(txPktBufPtr);
-        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
-    } else
-        txPacket = 0;
-
-    bool rxPacketExists;
-    UNSERIALIZE_SCALAR(rxPacketExists);
-    rxPacket = 0;
-    if (rxPacketExists) {
-        rxPacket = make_shared<EthPacketData>(16384);
-        rxPacket->unserialize("rxPacket", cp);
-        uint32_t rxPktBufPtr;
-        UNSERIALIZE_SCALAR(rxPktBufPtr);
-        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
-    } else
-        rxPacket = 0;
-
-    UNSERIALIZE_SCALAR(txXferLen);
-    UNSERIALIZE_SCALAR(rxXferLen);
-
-    /*
-     * Unserialize Cached Descriptors
-     */
-    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
-     */
-    int txState;
-    UNSERIALIZE_SCALAR(txState);
-    this->txState = (TxState) txState;
-    UNSERIALIZE_SCALAR(txEnable);
-    UNSERIALIZE_SCALAR(CTDD);
-    UNSERIALIZE_SCALAR(txFragPtr);
-    UNSERIALIZE_SCALAR(txDescCnt);
-    int txDmaState;
-    UNSERIALIZE_SCALAR(txDmaState);
-    this->txDmaState = (DmaState) txDmaState;
-    UNSERIALIZE_SCALAR(txKickTick);
-    if (txKickTick)
-        schedule(txKickEvent, txKickTick);
-
-    /*
-     * unserialize rx state machine
-     */
-    int rxState;
-    UNSERIALIZE_SCALAR(rxState);
-    this->rxState = (RxState) rxState;
-    UNSERIALIZE_SCALAR(rxEnable);
-    UNSERIALIZE_SCALAR(CRDD);
-    UNSERIALIZE_SCALAR(rxPktBytes);
-    UNSERIALIZE_SCALAR(rxFragPtr);
-    UNSERIALIZE_SCALAR(rxDescCnt);
-    int rxDmaState;
-    UNSERIALIZE_SCALAR(rxDmaState);
-    this->rxDmaState = (DmaState) rxDmaState;
-    UNSERIALIZE_SCALAR(rxKickTick);
-    if (rxKickTick)
-        schedule(rxKickEvent, rxKickTick);
-
-    /*
-     * 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;
-    UNSERIALIZE_SCALAR(transmitTick);
-    if (transmitTick)
-        schedule(txEvent, curTick() + transmitTick);
-
-    /*
-     * unserialize receive address filter settings
-     */
-    UNSERIALIZE_SCALAR(rxFilterEnable);
-    UNSERIALIZE_SCALAR(acceptBroadcast);
-    UNSERIALIZE_SCALAR(acceptMulticast);
-    UNSERIALIZE_SCALAR(acceptUnicast);
-    UNSERIALIZE_SCALAR(acceptPerfect);
-    UNSERIALIZE_SCALAR(acceptArp);
-    UNSERIALIZE_SCALAR(multicastHashEnable);
-
-    /*
-     * Keep track of pending interrupt status.
-     */
-    UNSERIALIZE_SCALAR(intrTick);
-    UNSERIALIZE_SCALAR(cpuPendingIntr);
-    Tick intrEventTick;
-    UNSERIALIZE_SCALAR(intrEventTick);
-    if (intrEventTick) {
-        intrEvent = new IntrEvent(this, true);
-        schedule(intrEvent, intrEventTick);
-    }
-}
-
-NSGigE *
-NSGigEParams::create()
-{
-    return new NSGigE(this);
-}
diff --git a/src/dev/ns_gige.hh b/src/dev/ns_gige.hh
deleted file mode 100644 (file)
index 33a76ab..0000000
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- *          Lisa Hsu
- */
-
-/** @file
- * Device module for modelling the National Semiconductor
- * DP83820 ethernet controller
- */
-
-#ifndef __DEV_NS_GIGE_HH__
-#define __DEV_NS_GIGE_HH__
-
-#include "base/inet.hh"
-#include "dev/etherdevice.hh"
-#include "dev/etherint.hh"
-#include "dev/etherpkt.hh"
-#include "dev/io_device.hh"
-#include "dev/ns_gige_reg.h"
-#include "dev/pktfifo.hh"
-#include "params/NSGigE.hh"
-#include "sim/eventq.hh"
-
-// Hash filtering constants
-const uint16_t FHASH_ADDR  = 0x100;
-const uint16_t FHASH_SIZE  = 0x100;
-
-// EEPROM constants
-const uint8_t  EEPROM_READ = 0x2;
-const uint8_t  EEPROM_SIZE = 64; // Size in words of NSC93C46 EEPROM
-const uint8_t  EEPROM_PMATCH2_ADDR = 0xA; // EEPROM Address of PMATCH word 2
-const uint8_t  EEPROM_PMATCH1_ADDR = 0xB; // EEPROM Address of PMATCH word 1
-const uint8_t  EEPROM_PMATCH0_ADDR = 0xC; // EEPROM Address of PMATCH word 0
-
-/**
- * Ethernet device registers
- */
-struct dp_regs {
-    uint32_t    command;
-    uint32_t    config;
-    uint32_t    mear;
-    uint32_t    ptscr;
-    uint32_t    isr;
-    uint32_t    imr;
-    uint32_t    ier;
-    uint32_t    ihr;
-    uint32_t    txdp;
-    uint32_t    txdp_hi;
-    uint32_t    txcfg;
-    uint32_t    gpior;
-    uint32_t    rxdp;
-    uint32_t    rxdp_hi;
-    uint32_t    rxcfg;
-    uint32_t    pqcr;
-    uint32_t    wcsr;
-    uint32_t    pcr;
-    uint32_t    rfcr;
-    uint32_t    rfdr;
-    uint32_t    brar;
-    uint32_t    brdr;
-    uint32_t    srr;
-    uint32_t    mibc;
-    uint32_t    vrcr;
-    uint32_t    vtcr;
-    uint32_t    vdr;
-    uint32_t    ccsr;
-    uint32_t    tbicr;
-    uint32_t    tbisr;
-    uint32_t    tanar;
-    uint32_t    tanlpar;
-    uint32_t    taner;
-    uint32_t    tesr;
-};
-
-struct dp_rom {
-    /**
-     * for perfect match memory.
-     * the linux driver doesn't use any other ROM
-     */
-    uint8_t perfectMatch[ETH_ADDR_LEN];
-
-    /**
-     * for hash table memory.
-     * used by the freebsd driver
-     */
-    uint8_t filterHash[FHASH_SIZE];
-};
-
-class NSGigEInt;
-class Packet;
-
-/**
- * NS DP83820 Ethernet device model
- */
-class NSGigE : public EtherDevBase
-{
-  public:
-    /** Transmit State Machine states */
-    enum TxState
-    {
-        txIdle,
-        txDescRefr,
-        txDescRead,
-        txFifoBlock,
-        txFragRead,
-        txDescWrite,
-        txAdvance
-    };
-
-    /** Receive State Machine States */
-    enum RxState
-    {
-        rxIdle,
-        rxDescRefr,
-        rxDescRead,
-        rxFifoBlock,
-        rxFragWrite,
-        rxDescWrite,
-        rxAdvance
-    };
-
-    enum DmaState
-    {
-        dmaIdle,
-        dmaReading,
-        dmaWriting,
-        dmaReadWaiting,
-        dmaWriteWaiting
-    };
-
-    /** EEPROM State Machine States */
-    enum EEPROMState
-    {
-        eepromStart,
-        eepromGetOpcode,
-        eepromGetAddress,
-        eepromRead
-    };
-
-  protected:
-    /** device register file */
-    dp_regs regs;
-    dp_rom rom;
-
-    /** pci settings */
-    bool ioEnable;
-#if 0
-    bool memEnable;
-    bool bmEnable;
-#endif
-
-    /*** BASIC STRUCTURES FOR TX/RX ***/
-    /* Data FIFOs */
-    PacketFifo txFifo;
-    PacketFifo rxFifo;
-
-    /** various helper vars */
-    EthPacketPtr txPacket;
-    EthPacketPtr rxPacket;
-    uint8_t *txPacketBufPtr;
-    uint8_t *rxPacketBufPtr;
-    uint32_t txXferLen;
-    uint32_t rxXferLen;
-    bool rxDmaFree;
-    bool txDmaFree;
-
-    /** DescCaches */
-    ns_desc32 txDesc32;
-    ns_desc32 rxDesc32;
-    ns_desc64 txDesc64;
-    ns_desc64 rxDesc64;
-
-    /* tx State Machine */
-    TxState txState;
-    bool txEnable;
-
-    /** Current Transmit Descriptor Done */
-    bool CTDD;
-    /** halt the tx state machine after next packet */
-    bool txHalt;
-    /** ptr to the next byte in the current fragment */
-    Addr txFragPtr;
-    /** count of bytes remaining in the current descriptor */
-    uint32_t txDescCnt;
-    DmaState txDmaState;
-
-    /** rx State Machine */
-    RxState rxState;
-    bool rxEnable;
-
-    /** Current Receive Descriptor Done */
-    bool CRDD;
-    /** num of bytes in the current packet being drained from rxDataFifo */
-    uint32_t rxPktBytes;
-    /** halt the rx state machine after current packet */
-    bool rxHalt;
-    /** ptr to the next byte in current fragment */
-    Addr rxFragPtr;
-    /** count of bytes remaining in the current descriptor */
-    uint32_t rxDescCnt;
-    DmaState rxDmaState;
-
-    bool extstsEnable;
-
-    /** EEPROM State Machine */
-    EEPROMState eepromState;
-    bool eepromClk;
-    uint8_t eepromBitsToRx;
-    uint8_t eepromOpcode;
-    uint8_t eepromAddress;
-    uint16_t eepromData;
-
-  protected:
-    Tick dmaReadDelay;
-    Tick dmaWriteDelay;
-
-    Tick dmaReadFactor;
-    Tick dmaWriteFactor;
-
-    void *rxDmaData;
-    Addr  rxDmaAddr;
-    int   rxDmaLen;
-    bool  doRxDmaRead();
-    bool  doRxDmaWrite();
-
-    void *txDmaData;
-    Addr  txDmaAddr;
-    int   txDmaLen;
-    bool  doTxDmaRead();
-    bool  doTxDmaWrite();
-
-    void rxDmaReadDone();
-    friend class EventWrapper<NSGigE, &NSGigE::rxDmaReadDone>;
-    EventWrapper<NSGigE, &NSGigE::rxDmaReadDone> rxDmaReadEvent;
-
-    void rxDmaWriteDone();
-    friend class EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone>;
-    EventWrapper<NSGigE, &NSGigE::rxDmaWriteDone> rxDmaWriteEvent;
-
-    void txDmaReadDone();
-    friend class EventWrapper<NSGigE, &NSGigE::txDmaReadDone>;
-    EventWrapper<NSGigE, &NSGigE::txDmaReadDone> txDmaReadEvent;
-
-    void txDmaWriteDone();
-    friend class EventWrapper<NSGigE, &NSGigE::txDmaWriteDone>;
-    EventWrapper<NSGigE, &NSGigE::txDmaWriteDone> txDmaWriteEvent;
-
-    bool dmaDescFree;
-    bool dmaDataFree;
-
-  protected:
-    Tick txDelay;
-    Tick rxDelay;
-
-    void txReset();
-    void rxReset();
-    void regsReset();
-
-    void rxKick();
-    Tick rxKickTick;
-    typedef EventWrapper<NSGigE, &NSGigE::rxKick> RxKickEvent;
-    friend void RxKickEvent::process();
-    RxKickEvent rxKickEvent;
-
-    void txKick();
-    Tick txKickTick;
-    typedef EventWrapper<NSGigE, &NSGigE::txKick> TxKickEvent;
-    friend void TxKickEvent::process();
-    TxKickEvent txKickEvent;
-
-    void eepromKick();
-
-    /**
-     * Retransmit event
-     */
-    void transmit();
-    void txEventTransmit()
-    {
-        transmit();
-        if (txState == txFifoBlock)
-            txKick();
-    }
-    typedef EventWrapper<NSGigE, &NSGigE::txEventTransmit> TxEvent;
-    friend void TxEvent::process();
-    TxEvent txEvent;
-
-    void txDump() const;
-    void rxDump() const;
-
-    /**
-     * receive address filter
-     */
-    bool rxFilterEnable;
-    bool rxFilter(const EthPacketPtr &packet);
-    bool acceptBroadcast;
-    bool acceptMulticast;
-    bool acceptUnicast;
-    bool acceptPerfect;
-    bool acceptArp;
-    bool multicastHashEnable;
-
-    /**
-     * Interrupt management
-     */
-    void devIntrPost(uint32_t interrupts);
-    void devIntrClear(uint32_t interrupts);
-    void devIntrChangeMask();
-
-    Tick intrDelay;
-    Tick intrTick;
-    bool cpuPendingIntr;
-    void cpuIntrPost(Tick when);
-    void cpuInterrupt();
-    void cpuIntrClear();
-
-    typedef EventWrapper<NSGigE, &NSGigE::cpuInterrupt> IntrEvent;
-    friend void IntrEvent::process();
-    IntrEvent *intrEvent;
-    NSGigEInt *interface;
-
-  public:
-    typedef NSGigEParams Params;
-    const Params *params() const {
-        return dynamic_cast<const Params *>(_params);
-    }
-
-    NSGigE(Params *params);
-    ~NSGigE();
-
-    EtherInt *getEthPort(const std::string &if_name, int idx) override;
-
-    Tick writeConfig(PacketPtr pkt) override;
-
-    Tick read(PacketPtr pkt) override;
-    Tick write(PacketPtr pkt) override;
-
-    bool cpuIntrPending() const;
-    void cpuIntrAck() { cpuIntrClear(); }
-
-    bool recvPacket(EthPacketPtr packet);
-    void transferDone();
-
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-
-    void drainResume() override;
-};
-
-/*
- * Ethernet Interface for an Ethernet Device
- */
-class NSGigEInt : public EtherInt
-{
-  private:
-    NSGigE *dev;
-
-  public:
-    NSGigEInt(const std::string &name, NSGigE *d)
-        : EtherInt(name), dev(d)
-    { }
-
-    virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
-    virtual void sendDone() { dev->transferDone(); }
-};
-
-#endif // __DEV_NS_GIGE_HH__
diff --git a/src/dev/ns_gige_reg.h b/src/dev/ns_gige_reg.h
deleted file mode 100644 (file)
index c37c06a..0000000
+++ /dev/null
@@ -1,401 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Lisa Hsu
- */
-
-/** @file
- * Ethernet device register definitions for the National
- * Semiconductor DP83820 Ethernet controller
- */
-
-#ifndef __DEV_NS_GIGE_REG_H__
-#define __DEV_NS_GIGE_REG_H__
-
-/* Device Register Address Map */
-enum DeviceRegisterAddress {
-    CR =                0x00,
-    CFGR =              0x04,
-    MEAR =              0x08,
-    PTSCR =             0x0c,
-    ISR =               0x10,
-    IMR =               0x14,
-    IER =               0x18,
-    IHR =               0x1c,
-    TXDP =              0x20,
-    TXDP_HI =           0x24,
-    TX_CFG =            0x28,
-    GPIOR =             0x2c,
-    RXDP =              0x30,
-    RXDP_HI =           0x34,
-    RX_CFG =            0x38,
-    PQCR =              0x3c,
-    WCSR =              0x40,
-    PCR =               0x44,
-    RFCR =              0x48,
-    RFDR =              0x4c,
-    BRAR =              0x50,
-    BRDR =              0x54,
-    SRR =               0x58,
-    MIBC =              0x5c,
-    MIB_START =         0x60,
-    MIB_END =           0x88,
-    VRCR =              0xbc,
-    VTCR =              0xc0,
-    VDR =               0xc4,
-    CCSR =              0xcc,
-    TBICR =             0xe0,
-    TBISR =             0xe4,
-    TANAR =             0xe8,
-    TANLPAR =           0xec,
-    TANER =             0xf0,
-    TESR =              0xf4,
-    M5REG =             0xf8,
-    LAST =              0xf8,
-    RESERVED =          0xfc
-};
-
-/* Chip Command Register */
-enum ChipCommandRegister {
-     CR_TXE =           0x00000001,
-     CR_TXD =           0x00000002,
-     CR_RXE =           0x00000004,
-     CR_RXD =           0x00000008,
-     CR_TXR =           0x00000010,
-     CR_RXR =           0x00000020,
-     CR_SWI =           0x00000080,
-     CR_RST =           0x00000100
-};
-
-/* configuration register */
-enum ConfigurationRegisters {
-     CFGR_LNKSTS =      0x80000000,
-     CFGR_SPDSTS =      0x60000000,
-     CFGR_SPDSTS1 =     0x40000000,
-     CFGR_SPDSTS0 =     0x20000000,
-     CFGR_DUPSTS =      0x10000000,
-     CFGR_TBI_EN =      0x01000000,
-     CFGR_RESERVED =    0x0e000000,
-     CFGR_MODE_1000 =   0x00400000,
-     CFGR_AUTO_1000 =   0x00200000,
-     CFGR_PINT_CTL =    0x001c0000,
-     CFGR_PINT_DUPSTS = 0x00100000,
-     CFGR_PINT_LNKSTS = 0x00080000,
-     CFGR_PINT_SPDSTS = 0x00040000,
-     CFGR_TMRTEST =     0x00020000,
-     CFGR_MRM_DIS =     0x00010000,
-     CFGR_MWI_DIS =     0x00008000,
-     CFGR_T64ADDR =     0x00004000,
-     CFGR_PCI64_DET =   0x00002000,
-     CFGR_DATA64_EN =   0x00001000,
-     CFGR_M64ADDR =     0x00000800,
-     CFGR_PHY_RST =     0x00000400,
-     CFGR_PHY_DIS =     0x00000200,
-     CFGR_EXTSTS_EN =   0x00000100,
-     CFGR_REQALG =      0x00000080,
-     CFGR_SB =          0x00000040,
-     CFGR_POW =         0x00000020,
-     CFGR_EXD =         0x00000010,
-     CFGR_PESEL =       0x00000008,
-     CFGR_BROM_DIS =    0x00000004,
-     CFGR_EXT_125 =     0x00000002,
-     CFGR_BEM =         0x00000001
-};
-
-/* EEPROM access register */
-enum EEPROMAccessRegister {
-     MEAR_EEDI =        0x00000001,
-     MEAR_EEDO =        0x00000002,
-     MEAR_EECLK =       0x00000004,
-     MEAR_EESEL =       0x00000008,
-     MEAR_MDIO =        0x00000010,
-     MEAR_MDDIR =       0x00000020,
-     MEAR_MDC =         0x00000040,
-};
-
-/* PCI test control register */
-enum PCITestControlRegister {
-     PTSCR_EEBIST_FAIL =        0x00000001,
-     PTSCR_EEBIST_EN =          0x00000002,
-     PTSCR_EELOAD_EN =          0x00000004,
-     PTSCR_RBIST_FAIL =         0x000001b8,
-     PTSCR_RBIST_DONE =         0x00000200,
-     PTSCR_RBIST_EN =           0x00000400,
-     PTSCR_RBIST_RST =          0x00002000,
-     PTSCR_RBIST_RDONLY =       0x000003f9
-};
-
-/* interrupt status register */
-enum InterruptStatusRegister {
-     ISR_RESERVE =      0x80000000,
-     ISR_TXDESC3 =      0x40000000,
-     ISR_TXDESC2 =      0x20000000,
-     ISR_TXDESC1 =      0x10000000,
-     ISR_TXDESC0 =      0x08000000,
-     ISR_RXDESC3 =      0x04000000,
-     ISR_RXDESC2 =      0x02000000,
-     ISR_RXDESC1 =      0x01000000,
-     ISR_RXDESC0 =      0x00800000,
-     ISR_TXRCMP =       0x00400000,
-     ISR_RXRCMP =       0x00200000,
-     ISR_DPERR =        0x00100000,
-     ISR_SSERR =        0x00080000,
-     ISR_RMABT =        0x00040000,
-     ISR_RTAB =         0x00020000,
-     ISR_RXSOVR =       0x00010000,
-     ISR_HIBINT =       0x00008000,
-     ISR_PHY =          0x00004000,
-     ISR_PME =          0x00002000,
-     ISR_SWI =          0x00001000,
-     ISR_MIB =          0x00000800,
-     ISR_TXURN =        0x00000400,
-     ISR_TXIDLE =       0x00000200,
-     ISR_TXERR =        0x00000100,
-     ISR_TXDESC =       0x00000080,
-     ISR_TXOK =         0x00000040,
-     ISR_RXORN =        0x00000020,
-     ISR_RXIDLE =       0x00000010,
-     ISR_RXEARLY =      0x00000008,
-     ISR_RXERR =        0x00000004,
-     ISR_RXDESC =       0x00000002,
-     ISR_RXOK =         0x00000001,
-     ISR_ALL =          0x7FFFFFFF,
-     ISR_DELAY =        (ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|
-                         ISR_RXIDLE|ISR_RXDESC|ISR_RXOK),
-     ISR_NODELAY =      (ISR_ALL & ~ISR_DELAY),
-     ISR_IMPL =         (ISR_SWI|ISR_TXIDLE|ISR_TXDESC|ISR_TXOK|ISR_RXORN|
-                         ISR_RXIDLE|ISR_RXDESC|ISR_RXOK),
-     ISR_NOIMPL =       (ISR_ALL & ~ISR_IMPL)
-};
-
-/* transmit configuration register */
-enum TransmitConfigurationRegister {
-     TX_CFG_CSI =       0x80000000,
-     TX_CFG_HBI =       0x40000000,
-     TX_CFG_MLB =       0x20000000,
-     TX_CFG_ATP =       0x10000000,
-     TX_CFG_ECRETRY =   0x00800000,
-     TX_CFG_BRST_DIS =  0x00080000,
-     TX_CFG_MXDMA1024 = 0x00000000,
-     TX_CFG_MXDMA512 =  0x00700000,
-     TX_CFG_MXDMA256 =  0x00600000,
-     TX_CFG_MXDMA128 =  0x00500000,
-     TX_CFG_MXDMA64 =   0x00400000,
-     TX_CFG_MXDMA32 =   0x00300000,
-     TX_CFG_MXDMA16 =   0x00200000,
-     TX_CFG_MXDMA8 =    0x00100000,
-     TX_CFG_MXDMA =     0x00700000,
-
-     TX_CFG_FLTH_MASK = 0x0000ff00,
-     TX_CFG_DRTH_MASK = 0x000000ff
-};
-
-/*general purpose I/O control register */
-enum GeneralPurposeIOControlRegister {
-     GPIOR_UNUSED =     0xffff8000,
-     GPIOR_GP5_IN =     0x00004000,
-     GPIOR_GP4_IN =     0x00002000,
-     GPIOR_GP3_IN =     0x00001000,
-     GPIOR_GP2_IN =     0x00000800,
-     GPIOR_GP1_IN =     0x00000400,
-     GPIOR_GP5_OE =     0x00000200,
-     GPIOR_GP4_OE =     0x00000100,
-     GPIOR_GP3_OE =     0x00000080,
-     GPIOR_GP2_OE =     0x00000040,
-     GPIOR_GP1_OE =     0x00000020,
-     GPIOR_GP5_OUT =    0x00000010,
-     GPIOR_GP4_OUT =    0x00000008,
-     GPIOR_GP3_OUT =    0x00000004,
-     GPIOR_GP2_OUT =    0x00000002,
-     GPIOR_GP1_OUT =    0x00000001
-};
-
-/* receive configuration register */
-enum ReceiveConfigurationRegister {
-     RX_CFG_AEP =       0x80000000,
-     RX_CFG_ARP =       0x40000000,
-     RX_CFG_STRIPCRC =  0x20000000,
-     RX_CFG_RX_FD =     0x10000000,
-     RX_CFG_ALP =       0x08000000,
-     RX_CFG_AIRL =      0x04000000,
-     RX_CFG_MXDMA512 =  0x00700000,
-     RX_CFG_MXDMA =     0x00700000,
-     RX_CFG_DRTH =      0x0000003e,
-     RX_CFG_DRTH0 =     0x00000002
-};
-
-/* pause control status register */
-enum PauseControlStatusRegister {
-     PCR_PSEN =         (1 << 31),
-     PCR_PS_MCAST =     (1 << 30),
-     PCR_PS_DA =        (1 << 29),
-     PCR_STHI_8 =       (3 << 23),
-     PCR_STLO_4 =       (1 << 23),
-     PCR_FFHI_8K =      (3 << 21),
-     PCR_FFLO_4K =      (1 << 21),
-     PCR_PAUSE_CNT =    0xFFFE
-};
-
-/*receive filter/match control register */
-enum ReceiveFilterMatchControlRegister {
-     RFCR_RFEN =        0x80000000,
-     RFCR_AAB =         0x40000000,
-     RFCR_AAM =         0x20000000,
-     RFCR_AAU =         0x10000000,
-     RFCR_APM =         0x08000000,
-     RFCR_APAT =        0x07800000,
-     RFCR_APAT3 =       0x04000000,
-     RFCR_APAT2 =       0x02000000,
-     RFCR_APAT1 =       0x01000000,
-     RFCR_APAT0 =       0x00800000,
-     RFCR_AARP =        0x00400000,
-     RFCR_MHEN =        0x00200000,
-     RFCR_UHEN =        0x00100000,
-     RFCR_ULM =         0x00080000,
-     RFCR_RFADDR =      0x000003ff
-};
-
-/* receive filter/match data register */
-enum ReceiveFilterMatchDataRegister {
-     RFDR_BMASK =       0x00030000,
-     RFDR_RFDATA0 =     0x000000ff,
-     RFDR_RFDATA1 =     0x0000ff00
-};
-
-/* management information base control register */
-enum ManagementInformationBaseControlRegister {
-     MIBC_MIBS =        0x00000008,
-     MIBC_ACLR =        0x00000004,
-     MIBC_FRZ =         0x00000002,
-     MIBC_WRN =         0x00000001
-};
-
-/* VLAN/IP receive control register */
-enum VLANIPReceiveControlRegister {
-     VRCR_RUDPE =       0x00000080,
-     VRCR_RTCPE =       0x00000040,
-     VRCR_RIPE =        0x00000020,
-     VRCR_IPEN =        0x00000010,
-     VRCR_DUTF =        0x00000008,
-     VRCR_DVTF =        0x00000004,
-     VRCR_VTREN =       0x00000002,
-     VRCR_VTDEN =       0x00000001
-};
-
-/* VLAN/IP transmit control register */
-enum VLANIPTransmitControlRegister {
-     VTCR_PPCHK =       0x00000008,
-     VTCR_GCHK =        0x00000004,
-     VTCR_VPPTI =       0x00000002,
-     VTCR_VGTI =        0x00000001
-};
-
-/* Clockrun Control/Status Register */
-enum ClockrunControlStatusRegister {
-     CCSR_CLKRUN_EN =   0x00000001
-};
-
-/* TBI control register */
-enum TBIControlRegister {
-     TBICR_MR_LOOPBACK =        0x00004000,
-     TBICR_MR_AN_ENABLE =       0x00001000,
-     TBICR_MR_RESTART_AN =      0x00000200
-};
-
-/* TBI status register */
-enum TBIStatusRegister {
-     TBISR_MR_LINK_STATUS =     0x00000020,
-     TBISR_MR_AN_COMPLETE =     0x00000004
-};
-
-/* TBI auto-negotiation advertisement register */
-enum TBIAutoNegotiationAdvertisementRegister {
-     TANAR_NP =         0x00008000,
-     TANAR_RF2 =        0x00002000,
-     TANAR_RF1 =        0x00001000,
-     TANAR_PS2 =        0x00000100,
-     TANAR_PS1 =        0x00000080,
-     TANAR_HALF_DUP =   0x00000040,
-     TANAR_FULL_DUP =   0x00000020,
-     TANAR_UNUSED =     0x00000E1F
-};
-
-/* M5 control register */
-enum M5ControlRegister {
-     M5REG_RESERVED =   0xfffffffc,
-     M5REG_RSS =        0x00000004,
-     M5REG_RX_THREAD =  0x00000002,
-     M5REG_TX_THREAD =  0x00000001
-};
-
-struct ns_desc32 {
-    uint32_t link;    /* link field to next descriptor in linked list */
-    uint32_t bufptr;  /* pointer to the first fragment or buffer */
-    uint32_t cmdsts;  /* command/status field */
-    uint32_t extsts;  /* extended status field for VLAN and IP info */
-};
-
-struct ns_desc64 {
-    uint64_t link;    /* link field to next descriptor in linked list */
-    uint64_t bufptr;  /* pointer to the first fragment or buffer */
-    uint32_t cmdsts;  /* command/status field */
-    uint32_t extsts;  /* extended status field for VLAN and IP info */
-};
-
-/* cmdsts flags for descriptors */
-enum CMDSTSFlatsForDescriptors {
-     CMDSTS_OWN =       0x80000000,
-     CMDSTS_MORE =      0x40000000,
-     CMDSTS_INTR =      0x20000000,
-     CMDSTS_ERR =       0x10000000,
-     CMDSTS_OK =        0x08000000,
-     CMDSTS_LEN_MASK =  0x0000ffff,
-
-     CMDSTS_DEST_MASK = 0x01800000,
-     CMDSTS_DEST_SELF = 0x00800000,
-     CMDSTS_DEST_MULTI = 0x01000000
-};
-
-/* extended flags for descriptors */
-enum ExtendedFlagsForDescriptors {
-     EXTSTS_UDPERR =    0x00400000,
-     EXTSTS_UDPPKT =    0x00200000,
-     EXTSTS_TCPERR =    0x00100000,
-     EXTSTS_TCPPKT =    0x00080000,
-     EXTSTS_IPERR =     0x00040000,
-     EXTSTS_IPPKT =     0x00020000
-};
-
-/* speed status */
-static inline int
-SPDSTS_POLARITY(int lnksts)
-{
-    return (CFGR_SPDSTS1 | CFGR_SPDSTS0 | CFGR_DUPSTS |
-            (lnksts ? CFGR_LNKSTS : 0));
-}
-
-#endif /* __DEV_NS_GIGE_REG_H__ */
diff --git a/src/dev/pktfifo.cc b/src/dev/pktfifo.cc
deleted file mode 100644 (file)
index fb2564b..0000000
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#include "base/misc.hh"
-#include "dev/pktfifo.hh"
-
-using namespace std;
-
-bool
-PacketFifo::copyout(void *dest, unsigned offset, unsigned len)
-{
-    char *data = (char *)dest;
-    if (offset + len >= size())
-        return false;
-
-    iterator i = fifo.begin();
-    iterator end = fifo.end();
-    while (len > 0) {
-        EthPacketPtr &pkt = i->packet;
-        while (offset >= pkt->length) {
-            offset -= pkt->length;
-            ++i;
-        }
-
-        if (i == end)
-            panic("invalid fifo");
-
-        unsigned size = min(pkt->length - offset, len);
-        memcpy(data, pkt->data, size);
-        offset = 0;
-        len -= size;
-        data += size;
-        ++i;
-    }
-
-    return true;
-}
-
-
-void
-PacketFifoEntry::serialize(const string &base, CheckpointOut &cp) const
-{
-    packet->serialize(base + ".packet", cp);
-    paramOut(cp, base + ".slack", slack);
-    paramOut(cp, base + ".number", number);
-    paramOut(cp, base + ".priv", priv);
-}
-
-void
-PacketFifoEntry::unserialize(const string &base, CheckpointIn &cp)
-{
-    packet = make_shared<EthPacketData>(16384);
-    packet->unserialize(base + ".packet", cp);
-    paramIn(cp, base + ".slack", slack);
-    paramIn(cp, base + ".number", number);
-    paramIn(cp, base + ".priv", priv);
-}
-
-void
-PacketFifo::serialize(const string &base, CheckpointOut &cp) const
-{
-    paramOut(cp, base + ".size", _size);
-    paramOut(cp, base + ".maxsize", _maxsize);
-    paramOut(cp, base + ".reserved", _reserved);
-    paramOut(cp, base + ".packets", fifo.size());
-
-    int i = 0;
-    for (const auto &entry : fifo)
-        entry.serialize(csprintf("%s.entry%d", base, i++), cp);
-}
-
-void
-PacketFifo::unserialize(const string &base, CheckpointIn &cp)
-{
-    paramIn(cp, base + ".size", _size);
-//  paramIn(cp, base + ".maxsize", _maxsize);
-    paramIn(cp, base + ".reserved", _reserved);
-    int fifosize;
-    paramIn(cp, base + ".packets", fifosize);
-
-    fifo.clear();
-
-    for (int i = 0; i < fifosize; ++i) {
-        PacketFifoEntry entry;
-        entry.unserialize(csprintf("%s.entry%d", base, i), cp);
-        fifo.push_back(entry);
-    }
-}
diff --git a/src/dev/pktfifo.hh b/src/dev/pktfifo.hh
deleted file mode 100644 (file)
index ea58030..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#ifndef __DEV_PKTFIFO_HH__
-#define __DEV_PKTFIFO_HH__
-
-#include <iosfwd>
-#include <list>
-#include <string>
-
-#include "dev/etherpkt.hh"
-#include "sim/serialize.hh"
-
-class Checkpoint;
-
-struct PacketFifoEntry
-{
-    EthPacketPtr packet;
-    uint64_t number;
-    unsigned slack;
-    int priv;
-
-    PacketFifoEntry()
-    {
-        clear();
-    }
-
-    PacketFifoEntry(const PacketFifoEntry &s)
-        : packet(s.packet), number(s.number), slack(s.slack), priv(s.priv)
-    {
-    }
-
-    PacketFifoEntry(EthPacketPtr p, uint64_t n)
-        : packet(p), number(n), slack(0), priv(-1)
-    {
-    }
-
-    void clear()
-    {
-        packet = NULL;
-        number = 0;
-        slack = 0;
-        priv = -1;
-    }
-
-    void serialize(const std::string &base, CheckpointOut &cp) const;
-    void unserialize(const std::string &base, CheckpointIn &cp);
-};
-
-class PacketFifo
-{
-  public:
-
-    typedef std::list<PacketFifoEntry> fifo_list;
-    typedef fifo_list::iterator iterator;
-    typedef fifo_list::const_iterator const_iterator;
-
-  protected:
-    std::list<PacketFifoEntry> fifo;
-    uint64_t _counter;
-    unsigned _maxsize;
-    unsigned _size;
-    unsigned _reserved;
-
-  public:
-    explicit PacketFifo(int max)
-        : _counter(0), _maxsize(max), _size(0), _reserved(0) {}
-    virtual ~PacketFifo() {}
-
-    unsigned packets() const { return fifo.size(); }
-    unsigned maxsize() const { return _maxsize; }
-    unsigned size() const { return _size; }
-    unsigned reserved() const { return _reserved; }
-    unsigned avail() const { return _maxsize - _size - _reserved; }
-    bool empty() const { return size() <= 0; }
-    bool full() const { return avail() <= 0; }
-
-    unsigned
-    reserve(unsigned len = 0)
-    {
-        _reserved += len;
-        assert(avail() >= 0);
-        return _reserved;
-    }
-
-    iterator begin() { return fifo.begin(); }
-    iterator end() { return fifo.end(); }
-
-    const_iterator begin() const { return fifo.begin(); }
-    const_iterator end() const { return fifo.end(); }
-
-    EthPacketPtr front() { return fifo.begin()->packet; }
-
-    bool push(EthPacketPtr ptr)
-    {
-        assert(ptr->length);
-        assert(_reserved <= ptr->length);
-        if (avail() < ptr->length - _reserved)
-            return false;
-
-        _size += ptr->length;
-
-        PacketFifoEntry entry;
-        entry.packet = ptr;
-        entry.number = _counter++;
-        fifo.push_back(entry);
-        _reserved = 0;
-        return true;
-    }
-
-    void pop()
-    {
-        if (empty())
-            return;
-
-        iterator entry = fifo.begin();
-        _size -= entry->packet->length;
-        _size -= entry->slack;
-        entry->packet = NULL;
-        fifo.pop_front();
-    }
-
-    void clear()
-    {
-        for (iterator i = begin(); i != end(); ++i)
-            i->clear();
-        fifo.clear();
-        _size = 0;
-        _reserved = 0;
-    }
-
-    void remove(iterator i)
-    {
-        if (i != fifo.begin()) {
-            iterator prev = i;
-            --prev;
-            assert(prev != fifo.end());
-            prev->slack += i->packet->length;
-            prev->slack += i->slack;
-        } else {
-            _size -= i->packet->length;
-            _size -= i->slack;
-        }
-
-        i->clear();
-        fifo.erase(i);
-    }
-
-    bool copyout(void *dest, unsigned offset, unsigned len);
-
-    int countPacketsBefore(const_iterator i) const
-    {
-        if (i == fifo.end())
-            return 0;
-        return i->number - fifo.begin()->number;
-    }
-
-    int countPacketsAfter(const_iterator i) const
-    {
-        auto end = fifo.end();
-        if (i == end)
-            return 0;
-        return (--end)->number - i->number;
-    }
-
-    void check() const
-    {
-        unsigned total = 0;
-        for (auto i = begin(); i != end(); ++i)
-            total += i->packet->length + i->slack;
-
-        if (total != _size)
-            panic("total (%d) is not == to size (%d)\n", total, _size);
-    }
-
-/**
- * Serialization stuff
- */
-  public:
-    void serialize(const std::string &base, CheckpointOut &cp) const;
-    void unserialize(const std::string &base, CheckpointIn &cp);
-};
-
-#endif // __DEV_PKTFIFO_HH__
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
deleted file mode 100644 (file)
index 18642ef..0000000
+++ /dev/null
@@ -1,1561 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#include <deque>
-#include <limits>
-#include <string>
-
-#ifdef SINIC_VTOPHYS
-#include "arch/vtophys.hh"
-#endif
-#include "base/compiler.hh"
-#include "base/debug.hh"
-#include "base/inet.hh"
-#include "base/types.hh"
-#include "config/the_isa.hh"
-#include "debug/EthernetAll.hh"
-#include "dev/etherlink.hh"
-#include "dev/sinic.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "sim/eventq.hh"
-#include "sim/stats.hh"
-
-using namespace std;
-using namespace Net;
-using namespace TheISA;
-
-namespace Sinic {
-
-const char *RxStateStrings[] =
-{
-    "rxIdle",
-    "rxFifoBlock",
-    "rxBeginCopy",
-    "rxCopy",
-    "rxCopyDone"
-};
-
-const char *TxStateStrings[] =
-{
-    "txIdle",
-    "txFifoBlock",
-    "txBeginCopy",
-    "txCopy",
-    "txCopyDone"
-};
-
-
-///////////////////////////////////////////////////////////////////////
-//
-// Sinic PCI Device
-//
-Base::Base(const Params *p)
-    : EtherDevBase(p), rxEnable(false), txEnable(false),
-      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
-      cpuPendingIntr(false), intrEvent(0), interface(NULL)
-{
-}
-
-Device::Device(const Params *p)
-    : Base(p), rxUnique(0), txUnique(0),
-      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
-      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
-      rxKickTick(0), txKickTick(0),
-      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
-      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
-      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
-{
-    interface = new Interface(name() + ".int0", this);
-    reset();
-
-}
-
-Device::~Device()
-{}
-
-void
-Device::regStats()
-{
-    Base::regStats();
-
-    _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()
-{
-    Base::resetStats();
-
-    _maxVnicDistance = 0;
-}
-
-EtherInt*
-Device::getEthPort(const std::string &if_name, int idx)
-{
-    if (if_name == "interface") {
-        if (interface->getPeer())
-            panic("interface already connected to\n");
-
-        return interface;
-    }
-    return NULL;
-}
-
-
-void
-Device::prepareIO(ContextID cpu, int index)
-{
-    int size = virtualRegs.size();
-    if (index > size)
-        panic("Trying to access a vnic that doesn't exist %d > %d\n",
-              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(ContextID cpu, int index)
-{
-    using namespace Regs;
-    prepareIO(cpu, index);
-
-    VirtualReg &vnic = virtualRegs[index];
-
-    // update rx registers
-    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.RxFifoHigh);
-    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
-    regs.RxData = vnic.RxData;
-    regs.RxDone = rxdone;
-    regs.RxWait = rxdone;
-
-    // update tx regsiters
-    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.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
-Device::prepareWrite(ContextID cpu, int index)
-{
-    prepareIO(cpu, index);
-}
-
-/**
- * I/O read of device register
- */
-Tick
-Device::read(PacketPtr pkt)
-{
-    assert(config.command & PCI_CMD_MSE);
-    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
-
-    ContextID cpu = pkt->req->contextId();
-    Addr daddr = pkt->getAddr() - BARAddrs[0];
-    Addr index = daddr >> Regs::VirtualShift;
-    Addr raddr = daddr & Regs::VirtualMask;
-
-    if (!regValid(raddr))
-        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
-              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
-    const Regs::Info &info = regInfo(raddr);
-    if (!info.read)
-        panic("read %s (write only): "
-              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
-              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
-        panic("read %s (invalid size): "
-              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
-              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
-    prepareRead(cpu, index);
-
-    uint64_t value M5_VAR_USED = 0;
-    if (pkt->getSize() == 4) {
-        uint32_t reg = regData32(raddr);
-        pkt->set(reg);
-        value = reg;
-    }
-
-    if (pkt->getSize() == 8) {
-        uint64_t reg = regData64(raddr);
-        pkt->set(reg);
-        value = reg;
-    }
-
-    DPRINTF(EthernetPIO,
-            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
-            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
-
-    // reading the interrupt status register has the side effect of
-    // clearing it
-    if (raddr == Regs::IntrStatus)
-        devIntrClear();
-
-    return pioDelay;
-}
-
-/**
- * IPR read of device register
-
-    Fault
-Device::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
-{
-    if (!regValid(daddr))
-        panic("invalid address: da=%#x", daddr);
-
-    const Regs::Info &info = regInfo(daddr);
-    if (!info.read)
-        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
-
-    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
-            info.name, cpu, daddr);
-
-    prepareRead(cpu, 0);
-
-    if (info.size == 4)
-        result = regData32(daddr);
-
-    if (info.size == 8)
-        result = regData64(daddr);
-
-    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
-            info.name, cpu, result);
-
-    return NoFault;
-}
-*/
-/**
- * I/O write of device register
- */
-Tick
-Device::write(PacketPtr pkt)
-{
-    assert(config.command & PCI_CMD_MSE);
-    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
-
-    ContextID cpu = pkt->req->contextId();
-    Addr daddr = pkt->getAddr() - BARAddrs[0];
-    Addr index = daddr >> Regs::VirtualShift;
-    Addr raddr = daddr & Regs::VirtualMask;
-
-    if (!regValid(raddr))
-        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
-                cpu, daddr, pkt->getAddr(), pkt->getSize());
-
-    const Regs::Info &info = regInfo(raddr);
-    if (!info.write)
-        panic("write %s (read only): "
-              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
-              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
-    if (pkt->getSize() != info.size)
-        panic("write %s (invalid size): "
-              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
-              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
-    VirtualReg &vnic = virtualRegs[index];
-
-    DPRINTF(EthernetPIO,
-            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
-            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
-            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
-
-    prepareWrite(cpu, index);
-
-    switch (raddr) {
-      case Regs::Config:
-        changeConfig(pkt->get<uint32_t>());
-        break;
-
-      case Regs::Command:
-        command(pkt->get<uint32_t>());
-        break;
-
-      case Regs::IntrStatus:
-        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
-        break;
-
-      case Regs::IntrMask:
-        devIntrChangeMask(pkt->get<uint32_t>());
-        break;
-
-      case Regs::RxData:
-        if (Regs::get_RxDone_Busy(vnic.RxDone))
-            panic("receive machine busy with another request! rxState=%s",
-                  RxStateStrings[rxState]);
-
-        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");
-#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);
-#endif
-        } else {
-            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
-                    index, vnic.rxUnique);
-        }
-
-        if (vnic.rxIndex == rxFifo.end()) {
-            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
-            rxList.push_back(index);
-        } else {
-            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
-            rxBusy.push_back(index);
-        }
-
-        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
-            rxState = rxFifoBlock;
-            rxKick();
-        }
-        break;
-
-      case Regs::TxData:
-        if (Regs::get_TxDone_Busy(vnic.TxDone))
-            panic("transmit machine busy with another request! txState=%s",
-                  TxStateStrings[txState]);
-
-        vnic.txUnique = txUnique++;
-        vnic.TxDone = Regs::TxDone_Busy;
-
-        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
-            panic("vtophys won't work here in newmem.\n");
-#ifdef SINIC_VTOPHYS
-            Addr vaddr = Regs::get_TxData_Addr(reg64);
-            Addr paddr = vtophys(req->xc, vaddr);
-            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);
-#endif
-        } else {
-            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
-                    index, vnic.txUnique);
-        }
-
-        if (txList.empty() || txList.front() != index)
-            txList.push_back(index);
-        if (txEnable && txState == txIdle && txList.front() == index) {
-            txState = txFifoBlock;
-            txKick();
-        }
-        break;
-    }
-
-    return pioDelay;
-}
-
-void
-Device::devIntrPost(uint32_t interrupts)
-{
-    if ((interrupts & Regs::Intr_Res))
-        panic("Cannot set a reserved interrupt");
-
-    regs.IntrStatus |= interrupts;
-
-    DPRINTF(EthernetIntr,
-            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
-            interrupts, regs.IntrStatus, regs.IntrMask);
-
-    interrupts = regs.IntrStatus & regs.IntrMask;
-
-    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
-    // and then filled it above the high watermark
-    if (rxEmpty)
-        rxEmpty = false;
-    else
-        interrupts &= ~Regs::Intr_RxHigh;
-
-    // Intr_TxLow is special, we only signal it if we've filled up the fifo
-    // and then dropped below the low watermark
-    if (txFull)
-        txFull = false;
-    else
-        interrupts &= ~Regs::Intr_TxLow;
-
-    if (interrupts) {
-        Tick when = curTick();
-        if ((interrupts & Regs::Intr_NoDelay) == 0)
-            when += intrDelay;
-        cpuIntrPost(when);
-    }
-}
-
-void
-Device::devIntrClear(uint32_t interrupts)
-{
-    if ((interrupts & Regs::Intr_Res))
-        panic("Cannot clear a reserved interrupt");
-
-    regs.IntrStatus &= ~interrupts;
-
-    DPRINTF(EthernetIntr,
-            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
-            interrupts, regs.IntrStatus, regs.IntrMask);
-
-    if (!(regs.IntrStatus & regs.IntrMask))
-        cpuIntrClear();
-}
-
-void
-Device::devIntrChangeMask(uint32_t newmask)
-{
-    if (regs.IntrMask == newmask)
-        return;
-
-    regs.IntrMask = newmask;
-
-    DPRINTF(EthernetIntr,
-            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
-            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
-
-    if (regs.IntrStatus & regs.IntrMask)
-        cpuIntrPost(curTick());
-    else
-        cpuIntrClear();
-}
-
-void
-Base::cpuIntrPost(Tick when)
-{
-    // If the interrupt you want to post is later than an interrupt
-    // already scheduled, just let it post in the coming one and don't
-    // schedule another.
-    // HOWEVER, must be sure that the scheduled intrTick is in the
-    // future (this was formerly the source of a bug)
-    /**
-     * @todo this warning should be removed and the intrTick code should
-     * be fixed.
-     */
-    assert(when >= curTick());
-    assert(intrTick >= curTick() || intrTick == 0);
-    if (!cpuIntrEnable) {
-        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
-                intrTick);
-        return;
-    }
-
-    if (when > intrTick && intrTick != 0) {
-        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
-                intrTick);
-        return;
-    }
-
-    intrTick = when;
-    if (intrTick < curTick()) {
-        Debug::breakpoint();
-        intrTick = curTick();
-    }
-
-    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
-            intrTick);
-
-    if (intrEvent)
-        intrEvent->squash();
-    intrEvent = new IntrEvent(this, true);
-    schedule(intrEvent, intrTick);
-}
-
-void
-Base::cpuInterrupt()
-{
-    assert(intrTick == curTick());
-
-    // Whether or not there's a pending interrupt, we don't care about
-    // it anymore
-    intrEvent = 0;
-    intrTick = 0;
-
-    // Don't send an interrupt if there's already one
-    if (cpuPendingIntr) {
-        DPRINTF(EthernetIntr,
-                "would send an interrupt now, but there's already pending\n");
-    } else {
-        // Send interrupt
-        cpuPendingIntr = true;
-
-        DPRINTF(EthernetIntr, "posting interrupt\n");
-        intrPost();
-    }
-}
-
-void
-Base::cpuIntrClear()
-{
-    if (!cpuPendingIntr)
-        return;
-
-    if (intrEvent) {
-        intrEvent->squash();
-        intrEvent = 0;
-    }
-
-    intrTick = 0;
-
-    cpuPendingIntr = false;
-
-    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
-    intrClear();
-}
-
-bool
-Base::cpuIntrPending() const
-{ return cpuPendingIntr; }
-
-void
-Device::changeConfig(uint32_t newconf)
-{
-    uint32_t changed = regs.Config ^ newconf;
-    if (!changed)
-        return;
-
-    regs.Config = newconf;
-
-    if ((changed & Regs::Config_IntEn)) {
-        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
-        if (cpuIntrEnable) {
-            if (regs.IntrStatus & regs.IntrMask)
-                cpuIntrPost(curTick());
-        } else {
-            cpuIntrClear();
-        }
-    }
-
-    if ((changed & Regs::Config_TxEn)) {
-        txEnable = regs.Config & Regs::Config_TxEn;
-        if (txEnable)
-            txKick();
-    }
-
-    if ((changed & Regs::Config_RxEn)) {
-        rxEnable = regs.Config & Regs::Config_RxEn;
-        if (rxEnable)
-            rxKick();
-    }
-}
-
-void
-Device::command(uint32_t command)
-{
-    if (command & Regs::Command_Intr)
-        devIntrPost(Regs::Intr_Soft);
-
-    if (command & Regs::Command_Reset)
-        reset();
-}
-
-void
-Device::reset()
-{
-    using namespace Regs;
-
-    memset(&regs, 0, sizeof(regs));
-
-    regs.Config = 0;
-    if (params()->rx_thread)
-        regs.Config |= Config_RxThread;
-    if (params()->tx_thread)
-        regs.Config |= Config_TxThread;
-    if (params()->rss)
-        regs.Config |= Config_RSS;
-    if (params()->zero_copy)
-        regs.Config |= Config_ZeroCopy;
-    if (params()->delay_copy)
-        regs.Config |= Config_DelayCopy;
-    if (params()->virtual_addr)
-        regs.Config |= Config_Vaddr;
-
-    if (params()->delay_copy && params()->zero_copy)
-        panic("Can't delay copy and zero copy");
-
-    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
-    regs.RxMaxCopy = params()->rx_max_copy;
-    regs.TxMaxCopy = params()->tx_max_copy;
-    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.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;
-
-    rxFifo.clear();
-    rxFifoPtr = rxFifo.end();
-    txFifo.clear();
-    rxEmpty = false;
-    rxLow = true;
-    txFull = false;
-
-    int size = virtualRegs.size();
-    virtualRegs.clear();
-    virtualRegs.resize(size);
-    for (int i = 0; i < size; ++i)
-        virtualRegs[i].rxIndex = rxFifo.end();
-}
-
-void
-Device::rxDmaDone()
-{
-    assert(rxState == rxCopy);
-    rxState = rxCopyDone;
-    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
-            rxDmaAddr, rxDmaLen);
-    DDUMP(EthernetData, rxDmaData, rxDmaLen);
-
-    // If the transmit state machine  has a pending DMA, let it go first
-    if (txState == txBeginCopy)
-        txKick();
-
-    rxKick();
-}
-
-void
-Device::rxKick()
-{
-    VirtualReg *vnic = NULL;
-
-    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
-            RxStateStrings[rxState], rxFifo.size());
-
-    if (rxKickTick > curTick()) {
-        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
-                rxKickTick);
-        return;
-    }
-
-  next:
-    rxFifo.check();
-    if (rxState == rxIdle)
-        goto exit;
-
-    if (rxActive == -1) {
-        if (rxState != rxFifoBlock)
-            panic("no active vnic while in state %s", RxStateStrings[rxState]);
-
-        DPRINTF(EthernetSM, "processing rxState=%s\n",
-                RxStateStrings[rxState]);
-    } else {
-        vnic = &virtualRegs[rxActive];
-        DPRINTF(EthernetSM,
-                "processing rxState=%s for vnic %d (rxunique %d)\n",
-                RxStateStrings[rxState], rxActive, vnic->rxUnique);
-    }
-
-    switch (rxState) {
-      case rxFifoBlock:
-        if (DTRACE(EthernetSM)) {
-            PacketFifo::iterator end = rxFifo.end();
-            int size = virtualRegs.size();
-            for (int i = 0; i < size; ++i) {
-                VirtualReg *vn = &virtualRegs[i];
-                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
-                if (vn->rxIndex != end) {
-#ifndef NDEBUG
-                    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 %s (rxunique %d), packet %d, slack %d\n",
-                            i, status, vn->rxUnique,
-                            rxFifo.countPacketsBefore(vn->rxIndex),
-                            vn->rxIndex->slack);
-#endif
-                } else if (busy) {
-                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
-                            i, vn->rxUnique);
-                }
-            }
-        }
-
-        if (!rxBusy.empty()) {
-            rxActive = rxBusy.front();
-            rxBusy.pop_front();
-            vnic = &virtualRegs[rxActive];
-
-            if (vnic->rxIndex == rxFifo.end())
-                panic("continuing vnic without packet\n");
-
-            DPRINTF(EthernetSM,
-                    "continue processing for vnic %d (rxunique %d)\n",
-                    rxActive, vnic->rxUnique);
-
-            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;
-        }
-
-        if (rxFifoPtr == rxFifo.end()) {
-            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
-            goto exit;
-        }
-
-        if (rxList.empty())
-            panic("Not idle, but nothing to do!");
-
-        assert(!rxFifo.empty());
-
-        rxActive = rxList.front();
-        rxList.pop_front();
-        vnic = &virtualRegs[rxActive];
-
-        DPRINTF(EthernetSM,
-                "processing new packet for vnic %d (rxunique %d)\n",
-                rxActive, vnic->rxUnique);
-
-        // Grab a new packet from the fifo.
-        vnic->rxIndex = rxFifoPtr++;
-        vnic->rxIndex->priv = rxActive;
-        vnic->rxPacketOffset = 0;
-        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
-        assert(vnic->rxPacketBytes);
-        rxMappedCount++;
-
-        vnic->rxDoneData = 0;
-        /* scope for variables */ {
-            IpPtr ip(vnic->rxIndex->packet);
-            if (ip) {
-                DPRINTF(Ethernet, "ID is %d\n", ip->id());
-                vnic->rxDoneData |= Regs::RxDone_IpPacket;
-                rxIpChecksums++;
-                if (cksum(ip) != 0) {
-                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
-                    vnic->rxDoneData |= Regs::RxDone_IpError;
-                }
-                TcpPtr tcp(ip);
-                UdpPtr udp(ip);
-                if (tcp) {
-                    DPRINTF(Ethernet,
-                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
-                            tcp->sport(), tcp->dport(), tcp->seq(),
-                            tcp->ack());
-                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
-                    rxTcpChecksums++;
-                    if (cksum(tcp) != 0) {
-                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
-                        vnic->rxDoneData |= Regs::RxDone_TcpError;
-                    }
-                } else if (udp) {
-                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
-                    rxUdpChecksums++;
-                    if (cksum(udp) != 0) {
-                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
-                        vnic->rxDoneData |= Regs::RxDone_UdpError;
-                    }
-                }
-            }
-        }
-        rxState = rxBeginCopy;
-        break;
-
-      case rxBeginCopy:
-        if (dmaPending() || drainState() != DrainState::Running)
-            goto exit;
-
-        rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
-        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
-                                 vnic->rxPacketBytes);
-
-        /*
-         * 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 rxCopy:
-        DPRINTF(EthernetSM, "receive machine still copying\n");
-        goto exit;
-
-      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->rxIndex);
-            vnic->rxIndex = rxFifo.end();
-            rxMappedCount--;
-        } else {
-            if (!vnic->rxPacketOffset)
-                rxDirtyCount++;
-
-            vnic->rxPacketBytes -= rxDmaLen;
-            vnic->rxPacketOffset += rxDmaLen;
-            vnic->RxDone |= Regs::RxDone_More;
-            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
-                                                    vnic->rxPacketBytes);
-            DPRINTF(EthernetSM,
-                    "rxKick: packet not complete on vnic %d (rxunique %d): "
-                    "%d bytes left\n",
-                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
-        }
-
-        rxActive = -1;
-        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
-
-        if (rxFifo.empty()) {
-            devIntrPost(Regs::Intr_RxEmpty);
-            rxEmpty = true;
-        }
-
-        if (rxFifo.size() < regs.RxFifoLow)
-            rxLow = true;
-
-        if (rxFifo.size() > regs.RxFifoHigh)
-            rxLow = false;
-
-        devIntrPost(Regs::Intr_RxDMA);
-        break;
-
-      default:
-        panic("Invalid rxState!");
-    }
-
-    DPRINTF(EthernetSM, "entering next rxState=%s\n",
-            RxStateStrings[rxState]);
-
-    goto next;
-
-  exit:
-    /**
-     * @todo do we want to schedule a future kick?
-     */
-    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
-            RxStateStrings[rxState]);
-}
-
-void
-Device::txDmaDone()
-{
-    assert(txState == txCopy);
-    txState = txCopyDone;
-    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
-            txDmaAddr, txDmaLen);
-    DDUMP(EthernetData, txDmaData, txDmaLen);
-
-    // If the receive state machine  has a pending DMA, let it go first
-    if (rxState == rxBeginCopy)
-        rxKick();
-
-    txKick();
-}
-
-void
-Device::transmit()
-{
-    if (txFifo.empty()) {
-        DPRINTF(Ethernet, "nothing to transmit\n");
-        return;
-    }
-
-    uint32_t interrupts;
-    EthPacketPtr packet = txFifo.front();
-    if (!interface->sendPacket(packet)) {
-        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
-                txFifo.avail());
-        return;
-    }
-
-    txFifo.pop();
-#if TRACING_ON
-    if (DTRACE(Ethernet)) {
-        IpPtr ip(packet);
-        if (ip) {
-            DPRINTF(Ethernet, "ID is %d\n", ip->id());
-            TcpPtr tcp(ip);
-            if (tcp) {
-                DPRINTF(Ethernet,
-                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
-                        tcp->sport(), tcp->dport(), tcp->seq(),
-                        tcp->ack());
-            }
-        }
-    }
-#endif
-
-    DDUMP(EthernetData, packet->data, packet->length);
-    txBytes += packet->length;
-    txPackets++;
-
-    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
-            txFifo.avail());
-
-    interrupts = Regs::Intr_TxPacket;
-    if (txFifo.size() < regs.TxFifoLow)
-        interrupts |= Regs::Intr_TxLow;
-    devIntrPost(interrupts);
-}
-
-void
-Device::txKick()
-{
-    VirtualReg *vnic;
-    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
-            TxStateStrings[txState], txFifo.size());
-
-    if (txKickTick > curTick()) {
-        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
-                txKickTick);
-        return;
-    }
-
-  next:
-    if (txState == txIdle)
-        goto exit;
-
-    assert(!txList.empty());
-    vnic = &virtualRegs[txList.front()];
-
-    switch (txState) {
-      case txFifoBlock:
-        assert(Regs::get_TxDone_Busy(vnic->TxDone));
-        if (!txPacket) {
-            // Grab a new packet from the fifo.
-            txPacket = make_shared<EthPacketData>(16384);
-            txPacketOffset = 0;
-        }
-
-        if (txFifo.avail() - txPacket->length <
-            Regs::get_TxData_Len(vnic->TxData)) {
-            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
-            goto exit;
-        }
-
-        txState = txBeginCopy;
-        break;
-
-      case txBeginCopy:
-        if (dmaPending() || drainState() != DrainState::Running)
-            goto exit;
-
-        txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
-        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
-        txDmaData = txPacket->data + txPacketOffset;
-        txState = txCopy;
-
-        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
-        break;
-
-      case txCopy:
-        DPRINTF(EthernetSM, "transmit machine still copying\n");
-        goto exit;
-
-      case txCopyDone:
-        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
-        txPacket->length += txDmaLen;
-        if ((vnic->TxData & Regs::TxData_More)) {
-            txPacketOffset += txDmaLen;
-            txState = txIdle;
-            devIntrPost(Regs::Intr_TxDMA);
-            break;
-        }
-
-        assert(txPacket->length <= txFifo.avail());
-        if ((vnic->TxData & Regs::TxData_Checksum)) {
-            IpPtr ip(txPacket);
-            if (ip) {
-                TcpPtr tcp(ip);
-                if (tcp) {
-                    tcp->sum(0);
-                    tcp->sum(cksum(tcp));
-                    txTcpChecksums++;
-                }
-
-                UdpPtr udp(ip);
-                if (udp) {
-                    udp->sum(0);
-                    udp->sum(cksum(udp));
-                    txUdpChecksums++;
-                }
-
-                ip->sum(0);
-                ip->sum(cksum(ip));
-                txIpChecksums++;
-            }
-        }
-
-        txFifo.push(txPacket);
-        if (txFifo.avail() < regs.TxMaxCopy) {
-            devIntrPost(Regs::Intr_TxFull);
-            txFull = true;
-        }
-        txPacket = 0;
-        transmit();
-        txList.pop_front();
-        txState = txList.empty() ? txIdle : txFifoBlock;
-        devIntrPost(Regs::Intr_TxDMA);
-        break;
-
-      default:
-        panic("Invalid txState!");
-    }
-
-    DPRINTF(EthernetSM, "entering next txState=%s\n",
-            TxStateStrings[txState]);
-
-    goto next;
-
-  exit:
-    /**
-     * @todo do we want to schedule a future kick?
-     */
-    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
-            TxStateStrings[txState]);
-}
-
-void
-Device::transferDone()
-{
-    if (txFifo.empty()) {
-        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
-        return;
-    }
-
-    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
-
-    reschedule(txEvent, clockEdge(Cycles(1)), true);
-}
-
-bool
-Device::rxFilter(const EthPacketPtr &packet)
-{
-    if (!Regs::get_Config_Filter(regs.Config))
-        return false;
-
-    panic("receive filter not implemented\n");
-    bool drop = true;
-
-#if 0
-    string type;
-
-    EthHdr *eth = packet->eth();
-    if (eth->unicast()) {
-        // If we're accepting all unicast addresses
-        if (acceptUnicast)
-            drop = false;
-
-        // If we make a perfect match
-        if (acceptPerfect && params->eaddr == eth.dst())
-            drop = false;
-
-        if (acceptArp && eth->type() == ETH_TYPE_ARP)
-            drop = false;
-
-    } else if (eth->broadcast()) {
-        // if we're accepting broadcasts
-        if (acceptBroadcast)
-            drop = false;
-
-    } else if (eth->multicast()) {
-        // if we're accepting all multicasts
-        if (acceptMulticast)
-            drop = false;
-
-    }
-
-    if (drop) {
-        DPRINTF(Ethernet, "rxFilter drop\n");
-        DDUMP(EthernetData, packet->data, packet->length);
-    }
-#endif
-    return drop;
-}
-
-bool
-Device::recvPacket(EthPacketPtr packet)
-{
-    rxBytes += packet->length;
-    rxPackets++;
-
-    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
-            rxFifo.avail());
-
-    if (!rxEnable) {
-        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
-        return true;
-    }
-
-    if (rxFilter(packet)) {
-        DPRINTF(Ethernet, "packet filtered...dropped\n");
-        return true;
-    }
-
-    if (rxFifo.size() >= regs.RxFifoHigh)
-        devIntrPost(Regs::Intr_RxHigh);
-
-    if (!rxFifo.push(packet)) {
-        DPRINTF(Ethernet,
-                "packet will not fit in receive buffer...packet dropped\n");
-        return false;
-    }
-
-    // If we were at the last element, back up one ot go to the new
-    // last element of the list.
-    if (rxFifoPtr == rxFifo.end())
-        --rxFifoPtr;
-
-    devIntrPost(Regs::Intr_RxPacket);
-    rxKick();
-    return true;
-}
-
-void
-Device::drainResume()
-{
-    Drainable::drainResume();
-
-    // During drain we could have left the state machines in a waiting state and
-    // they wouldn't get out until some other event occured to kick them.
-    // This way they'll get out immediately
-    txKick();
-    rxKick();
-}
-
-//=====================================================================
-//
-//
-void
-Base::serialize(CheckpointOut &cp) const
-{
-    // Serialize the PciDevice base class
-    PciDevice::serialize(cp);
-
-    SERIALIZE_SCALAR(rxEnable);
-    SERIALIZE_SCALAR(txEnable);
-    SERIALIZE_SCALAR(cpuIntrEnable);
-
-    /*
-     * Keep track of pending interrupt status.
-     */
-    SERIALIZE_SCALAR(intrTick);
-    SERIALIZE_SCALAR(cpuPendingIntr);
-    Tick intrEventTick = 0;
-    if (intrEvent)
-        intrEventTick = intrEvent->when();
-    SERIALIZE_SCALAR(intrEventTick);
-}
-
-void
-Base::unserialize(CheckpointIn &cp)
-{
-    // Unserialize the PciDevice base class
-    PciDevice::unserialize(cp);
-
-    UNSERIALIZE_SCALAR(rxEnable);
-    UNSERIALIZE_SCALAR(txEnable);
-    UNSERIALIZE_SCALAR(cpuIntrEnable);
-
-    /*
-     * Keep track of pending interrupt status.
-     */
-    UNSERIALIZE_SCALAR(intrTick);
-    UNSERIALIZE_SCALAR(cpuPendingIntr);
-    Tick intrEventTick;
-    UNSERIALIZE_SCALAR(intrEventTick);
-    if (intrEventTick) {
-        intrEvent = new IntrEvent(this, true);
-        schedule(intrEvent, intrEventTick);
-    }
-}
-
-void
-Device::serialize(CheckpointOut &cp) const
-{
-    int count;
-
-    // Serialize the PciDevice base class
-    Base::serialize(cp);
-
-    if (rxState == rxCopy)
-        panic("can't serialize with an in flight dma request rxState=%s",
-              RxStateStrings[rxState]);
-
-    if (txState == txCopy)
-        panic("can't serialize with an in flight dma request txState=%s",
-              TxStateStrings[txState]);
-
-    /*
-     * 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.RxData);
-    SERIALIZE_SCALAR(regs.TxData);
-
-    /*
-     * Serialize the virtual nic state
-     */
-    int virtualRegsSize = virtualRegs.size();
-    SERIALIZE_SCALAR(virtualRegsSize);
-    for (int i = 0; i < virtualRegsSize; ++i) {
-        const VirtualReg *vnic = &virtualRegs[i];
-
-        std::string reg = csprintf("vnic%d", i);
-        paramOut(cp, reg + ".RxData", vnic->RxData);
-        paramOut(cp, reg + ".RxDone", vnic->RxDone);
-        paramOut(cp, reg + ".TxData", vnic->TxData);
-        paramOut(cp, reg + ".TxDone", vnic->TxDone);
-
-        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
-        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
-        if (rxPacketExists) {
-            int rxPacket = 0;
-            auto i = rxFifo.begin();
-            while (i != vnic->rxIndex) {
-                assert(i != rxFifo.end());
-                ++i;
-                ++rxPacket;
-            }
-
-            paramOut(cp, reg + ".rxPacket", rxPacket);
-            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
-            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
-        }
-        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
-    }
-
-    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::const_iterator i, end;
-    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
-        paramOut(cp, csprintf("rxList%d", count++), *i);
-    int rxListSize = count;
-    SERIALIZE_SCALAR(rxListSize);
-
-    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
-        paramOut(cp, csprintf("rxBusy%d", count++), *i);
-    int rxBusySize = count;
-    SERIALIZE_SCALAR(rxBusySize);
-
-    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
-        paramOut(cp, csprintf("txList%d", count++), *i);
-    int txListSize = count;
-    SERIALIZE_SCALAR(txListSize);
-
-    /*
-     * Serialize rx state machine
-     */
-    int rxState = this->rxState;
-    SERIALIZE_SCALAR(rxState);
-    SERIALIZE_SCALAR(rxEmpty);
-    SERIALIZE_SCALAR(rxLow);
-    rxFifo.serialize("rxFifo", cp);
-
-    /*
-     * Serialize tx state machine
-     */
-    int txState = this->txState;
-    SERIALIZE_SCALAR(txState);
-    SERIALIZE_SCALAR(txFull);
-    txFifo.serialize("txFifo", cp);
-    bool txPacketExists = txPacket != nullptr;
-    SERIALIZE_SCALAR(txPacketExists);
-    if (txPacketExists) {
-        txPacket->serialize("txPacket", cp);
-        SERIALIZE_SCALAR(txPacketOffset);
-        SERIALIZE_SCALAR(txPacketBytes);
-    }
-
-    /*
-     * If there's a pending transmit, store the time so we can
-     * reschedule it later
-     */
-    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
-    SERIALIZE_SCALAR(transmitTick);
-}
-
-void
-Device::unserialize(CheckpointIn &cp)
-{
-    // Unserialize the PciDevice base class
-    Base::unserialize(cp);
-
-    /*
-     * 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.RxData);
-    UNSERIALIZE_SCALAR(regs.TxData);
-
-    UNSERIALIZE_SCALAR(rxActive);
-    UNSERIALIZE_SCALAR(rxBusyCount);
-    UNSERIALIZE_SCALAR(rxDirtyCount);
-    UNSERIALIZE_SCALAR(rxMappedCount);
-
-    int rxListSize;
-    UNSERIALIZE_SCALAR(rxListSize);
-    rxList.clear();
-    for (int i = 0; i < rxListSize; ++i) {
-        int value;
-        paramIn(cp, csprintf("rxList%d", i), value);
-        rxList.push_back(value);
-    }
-
-    int rxBusySize;
-    UNSERIALIZE_SCALAR(rxBusySize);
-    rxBusy.clear();
-    for (int i = 0; i < rxBusySize; ++i) {
-        int value;
-        paramIn(cp, csprintf("rxBusy%d", i), value);
-        rxBusy.push_back(value);
-    }
-
-    int txListSize;
-    UNSERIALIZE_SCALAR(txListSize);
-    txList.clear();
-    for (int i = 0; i < txListSize; ++i) {
-        int value;
-        paramIn(cp, csprintf("txList%d", i), value);
-        txList.push_back(value);
-    }
-
-    /*
-     * Unserialize rx state machine
-     */
-    int rxState;
-    UNSERIALIZE_SCALAR(rxState);
-    UNSERIALIZE_SCALAR(rxEmpty);
-    UNSERIALIZE_SCALAR(rxLow);
-    this->rxState = (RxState) rxState;
-    rxFifo.unserialize("rxFifo", cp);
-
-    int rxFifoPtr;
-    UNSERIALIZE_SCALAR(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
-     */
-    int txState;
-    UNSERIALIZE_SCALAR(txState);
-    UNSERIALIZE_SCALAR(txFull);
-    this->txState = (TxState) txState;
-    txFifo.unserialize("txFifo", cp);
-    bool txPacketExists;
-    UNSERIALIZE_SCALAR(txPacketExists);
-    txPacket = 0;
-    if (txPacketExists) {
-        txPacket = make_shared<EthPacketData>(16384);
-        txPacket->unserialize("txPacket", cp);
-        UNSERIALIZE_SCALAR(txPacketOffset);
-        UNSERIALIZE_SCALAR(txPacketBytes);
-    }
-
-    /*
-     * unserialize the virtual nic registers/state
-     *
-     * this must be done after the unserialization of the rxFifo
-     * because the packet iterators depend on the fifo being populated
-     */
-    int virtualRegsSize;
-    UNSERIALIZE_SCALAR(virtualRegsSize);
-    virtualRegs.clear();
-    virtualRegs.resize(virtualRegsSize);
-    for (int i = 0; i < virtualRegsSize; ++i) {
-        VirtualReg *vnic = &virtualRegs[i];
-        std::string reg = csprintf("vnic%d", i);
-
-        paramIn(cp, reg + ".RxData", vnic->RxData);
-        paramIn(cp, reg + ".RxDone", vnic->RxDone);
-        paramIn(cp, reg + ".TxData", vnic->TxData);
-        paramIn(cp, reg + ".TxDone", vnic->TxDone);
-
-        vnic->rxUnique = rxUnique++;
-        vnic->txUnique = txUnique++;
-
-        bool rxPacketExists;
-        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
-        if (rxPacketExists) {
-            int rxPacket;
-            paramIn(cp, reg + ".rxPacket", rxPacket);
-            vnic->rxIndex = rxFifo.begin();
-            while (rxPacket--)
-                ++vnic->rxIndex;
-
-            paramIn(cp, reg + ".rxPacketOffset",
-                    vnic->rxPacketOffset);
-            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
-        } else {
-            vnic->rxIndex = rxFifo.end();
-        }
-        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
-    }
-
-    /*
-     * If there's a pending transmit, reschedule it now
-     */
-    Tick transmitTick;
-    UNSERIALIZE_SCALAR(transmitTick);
-    if (transmitTick)
-        schedule(txEvent, curTick() + transmitTick);
-
-    pioPort.sendRangeChange();
-
-}
-
-} // namespace Sinic
-
-Sinic::Device *
-SinicParams::create()
-{
-    return new Sinic::Device(this);
-}
diff --git a/src/dev/sinic.hh b/src/dev/sinic.hh
deleted file mode 100644 (file)
index dc1947f..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#ifndef __DEV_SINIC_HH__
-#define __DEV_SINIC_HH__
-
-#include "base/inet.hh"
-#include "base/statistics.hh"
-#include "dev/etherdevice.hh"
-#include "dev/etherint.hh"
-#include "dev/etherpkt.hh"
-#include "dev/io_device.hh"
-#include "dev/pci/device.hh"
-#include "dev/pktfifo.hh"
-#include "dev/sinicreg.hh"
-#include "params/Sinic.hh"
-#include "sim/eventq.hh"
-
-namespace Sinic {
-
-class Interface;
-class Base : public EtherDevBase
-{
-  protected:
-    bool rxEnable;
-    bool txEnable;
-
-  protected:
-    Tick intrDelay;
-    Tick intrTick;
-    bool cpuIntrEnable;
-    bool cpuPendingIntr;
-    void cpuIntrPost(Tick when);
-    void cpuInterrupt();
-    void cpuIntrClear();
-
-    typedef EventWrapper<Base, &Base::cpuInterrupt> IntrEvent;
-    friend void IntrEvent::process();
-    IntrEvent *intrEvent;
-    Interface *interface;
-
-    bool cpuIntrPending() const;
-    void cpuIntrAck() { cpuIntrClear(); }
-
-/**
- * Serialization stuff
- */
-  public:
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-
-/**
- * Construction/Destruction/Parameters
- */
-  public:
-    typedef SinicParams Params;
-    const Params *params() const { return (const Params *)_params; }
-    Base(const Params *p);
-};
-
-class Device : public Base
-{
-  protected:
-    /** Receive State Machine States */
-    enum RxState {
-        rxIdle,
-        rxFifoBlock,
-        rxBeginCopy,
-        rxCopy,
-        rxCopyDone
-    };
-
-    /** Transmit State Machine states */
-    enum TxState {
-        txIdle,
-        txFifoBlock,
-        txBeginCopy,
-        txCopy,
-        txCopyDone
-    };
-
-    /** device register file */
-    struct {
-        uint32_t Config;       // 0x00
-        uint32_t Command;      // 0x04
-        uint32_t IntrStatus;   // 0x08
-        uint32_t IntrMask;     // 0x0c
-        uint32_t RxMaxCopy;    // 0x10
-        uint32_t TxMaxCopy;    // 0x14
-        uint32_t ZeroCopySize; // 0x18
-        uint32_t ZeroCopyMark; // 0x1c
-        uint32_t VirtualCount; // 0x20
-        uint32_t RxMaxIntr;    // 0x24
-        uint32_t RxFifoSize;   // 0x28
-        uint32_t TxFifoSize;   // 0x2c
-        uint32_t RxFifoLow;    // 0x30
-        uint32_t TxFifoLow;    // 0x34
-        uint32_t RxFifoHigh;   // 0x38
-        uint32_t TxFifoHigh;   // 0x3c
-        uint64_t RxData;       // 0x40
-        uint64_t RxDone;       // 0x48
-        uint64_t RxWait;       // 0x50
-        uint64_t TxData;       // 0x58
-        uint64_t TxDone;       // 0x60
-        uint64_t TxWait;       // 0x68
-        uint64_t HwAddr;       // 0x70
-        uint64_t RxStatus;     // 0x78
-    } regs;
-
-    struct VirtualReg {
-        uint64_t RxData;
-        uint64_t RxDone;
-        uint64_t TxData;
-        uint64_t TxDone;
-
-        PacketFifo::iterator rxIndex;
-        unsigned rxPacketOffset;
-        unsigned rxPacketBytes;
-        uint64_t rxDoneData;
-
-        Counter rxUnique;
-        Counter txUnique;
-
-        VirtualReg()
-            : RxData(0), RxDone(0), TxData(0), TxDone(0),
-              rxPacketOffset(0), rxPacketBytes(0), rxDoneData(0)
-        { }
-    };
-    typedef std::vector<VirtualReg> VirtualRegs;
-    typedef std::list<unsigned> VirtualList;
-    Counter rxUnique;
-    Counter txUnique;
-    VirtualRegs virtualRegs;
-    VirtualList rxList;
-    VirtualList rxBusy;
-    int rxActive;
-    VirtualList txList;
-
-    int rxBusyCount;
-    int rxMappedCount;
-    int rxDirtyCount;
-
-    uint8_t  &regData8(Addr daddr) { return *((uint8_t *)&regs + daddr); }
-    uint32_t &regData32(Addr daddr) { return *(uint32_t *)&regData8(daddr); }
-    uint64_t &regData64(Addr daddr) { return *(uint64_t *)&regData8(daddr); }
-
-  protected:
-    RxState rxState;
-    PacketFifo rxFifo;
-    PacketFifo::iterator rxFifoPtr;
-    bool rxEmpty;
-    bool rxLow;
-    Addr rxDmaAddr;
-    uint8_t *rxDmaData;
-    unsigned rxDmaLen;
-
-    TxState txState;
-    PacketFifo txFifo;
-    bool txFull;
-    EthPacketPtr txPacket;
-    int txPacketOffset;
-    int txPacketBytes;
-    Addr txDmaAddr;
-    uint8_t *txDmaData;
-    int txDmaLen;
-
-  protected:
-    void reset();
-
-    void rxKick();
-    Tick rxKickTick;
-    typedef EventWrapper<Device, &Device::rxKick> RxKickEvent;
-    friend void RxKickEvent::process();
-
-    void txKick();
-    Tick txKickTick;
-    typedef EventWrapper<Device, &Device::txKick> TxKickEvent;
-    friend void TxKickEvent::process();
-
-    /**
-     * Retransmit event
-     */
-    void transmit();
-    void txEventTransmit()
-    {
-        transmit();
-        if (txState == txFifoBlock)
-            txKick();
-    }
-    typedef EventWrapper<Device, &Device::txEventTransmit> TxEvent;
-    friend void TxEvent::process();
-    TxEvent txEvent;
-
-    void txDump() const;
-    void rxDump() const;
-
-    /**
-     * receive address filter
-     */
-    bool rxFilter(const EthPacketPtr &packet);
-
-/**
- * device configuration
- */
-    void changeConfig(uint32_t newconfig);
-    void command(uint32_t command);
-
-/**
- * device ethernet interface
- */
-  public:
-    bool recvPacket(EthPacketPtr packet);
-    void transferDone();
-    EtherInt *getEthPort(const std::string &if_name, int idx) override;
-
-/**
- * DMA parameters
- */
-  protected:
-    void rxDmaDone();
-    friend class EventWrapper<Device, &Device::rxDmaDone>;
-    EventWrapper<Device, &Device::rxDmaDone> rxDmaEvent;
-
-    void txDmaDone();
-    friend class EventWrapper<Device, &Device::txDmaDone>;
-    EventWrapper<Device, &Device::txDmaDone> txDmaEvent;
-
-    Tick dmaReadDelay;
-    Tick dmaReadFactor;
-    Tick dmaWriteDelay;
-    Tick dmaWriteFactor;
-
-/**
- * Interrupt management
- */
-  protected:
-    void devIntrPost(uint32_t interrupts);
-    void devIntrClear(uint32_t interrupts = Regs::Intr_All);
-    void devIntrChangeMask(uint32_t newmask);
-
-/**
- * Memory Interface
- */
-  public:
-    Tick read(PacketPtr pkt) override;
-    Tick write(PacketPtr pkt) override;
-    virtual void drainResume() override;
-
-    void prepareIO(ContextID cpu, int index);
-    void prepareRead(ContextID cpu, int index);
-    void prepareWrite(ContextID cpu, int index);
- //   Fault iprRead(Addr daddr, ContextID cpu, uint64_t &result);
-
-/**
- * Statistics
- */
-  private:
-    Stats::Scalar totalVnicDistance;
-    Stats::Scalar numVnicDistance;
-    Stats::Scalar maxVnicDistance;
-    Stats::Formula avgVnicDistance;
-
-    int _maxVnicDistance;
-
-  public:
-    void regStats() override;
-    void resetStats() override;
-
-/**
- * Serialization stuff
- */
-  public:
-    void serialize(CheckpointOut &cp) const override;
-    void unserialize(CheckpointIn &cp) override;
-
-  public:
-    Device(const Params *p);
-    ~Device();
-};
-
-/*
- * Ethernet Interface for an Ethernet Device
- */
-class Interface : public EtherInt
-{
-  private:
-    Device *dev;
-
-  public:
-    Interface(const std::string &name, Device *d)
-        : EtherInt(name), dev(d)
-    { }
-
-    virtual bool recvPacket(EthPacketPtr pkt) { return dev->recvPacket(pkt); }
-    virtual void sendDone() { dev->transferDone(); }
-};
-
-} // namespace Sinic
-
-#endif // __DEV_SINIC_HH__
diff --git a/src/dev/sinicreg.hh b/src/dev/sinicreg.hh
deleted file mode 100644 (file)
index 540e690..0000000
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * 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
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#ifndef __DEV_SINICREG_HH__
-#define __DEV_SINICREG_HH__
-
-#define __SINIC_REG32(NAME, VAL) static const uint32_t NAME = (VAL);
-#define __SINIC_REG64(NAME, VAL) static const uint64_t NAME = (VAL);
-
-#define __SINIC_VAL32(NAME, OFFSET, WIDTH) \
-        static const uint32_t NAME##_width = WIDTH; \
-        static const uint32_t NAME##_offset = OFFSET; \
-        static const uint32_t NAME##_mask = (1 << WIDTH) - 1; \
-        static const uint32_t NAME = ((1 << WIDTH) - 1) << OFFSET; \
-        static inline uint32_t get_##NAME(uint32_t reg) \
-        { return (reg & NAME) >> OFFSET; } \
-        static inline uint32_t set_##NAME(uint32_t reg, uint32_t val) \
-        { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
-
-#define __SINIC_VAL64(NAME, OFFSET, WIDTH) \
-        static const uint64_t NAME##_width = WIDTH; \
-        static const uint64_t NAME##_offset = OFFSET; \
-        static const uint64_t NAME##_mask = (ULL(1) << WIDTH) - 1; \
-        static const uint64_t NAME = ((ULL(1) << WIDTH) - 1) << OFFSET; \
-        static inline uint64_t get_##NAME(uint64_t reg) \
-        { return (reg & NAME) >> OFFSET; } \
-        static inline uint64_t set_##NAME(uint64_t reg, uint64_t val) \
-        { return (reg & ~NAME) | ((val << OFFSET) & NAME); }
-
-namespace Sinic {
-namespace Regs {
-
-static const int VirtualShift = 8;
-static const int VirtualMask = 0xff;
-
-// Registers
-__SINIC_REG32(Config,        0x00) // 32: configuration register
-__SINIC_REG32(Command,       0x04) // 32: command register
-__SINIC_REG32(IntrStatus,    0x08) // 32: interrupt status
-__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(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_VAL32(Config_DelayCopy,11, 1) // enable delayed copy
-__SINIC_VAL32(Config_RSS,      10, 1) // enable receive side scaling
-__SINIC_VAL32(Config_RxThread,  9, 1) // enable receive threads
-__SINIC_VAL32(Config_TxThread,  8, 1) // enable transmit thread
-__SINIC_VAL32(Config_Filter,    7, 1) // enable receive filter
-__SINIC_VAL32(Config_Vlan,      6, 1) // enable vlan tagging
-__SINIC_VAL32(Config_Vaddr,     5, 1) // enable virtual addressing
-__SINIC_VAL32(Config_Desc,      4, 1) // enable tx/rx descriptors
-__SINIC_VAL32(Config_Poll,      3, 1) // enable polling
-__SINIC_VAL32(Config_IntEn,     2, 1) // enable interrupts
-__SINIC_VAL32(Config_TxEn,      1, 1) // enable transmit
-__SINIC_VAL32(Config_RxEn,      0, 1) // enable receive
-
-// Command register bits
-__SINIC_VAL32(Command_Intr,  1, 1) // software interrupt
-__SINIC_VAL32(Command_Reset, 0, 1) // reset chip
-
-// Interrupt register bits
-__SINIC_VAL32(Intr_Soft,      8, 1) // software interrupt
-__SINIC_VAL32(Intr_TxLow,     7, 1) // tx fifo dropped below watermark
-__SINIC_VAL32(Intr_TxFull,    6, 1) // tx fifo full
-__SINIC_VAL32(Intr_TxDMA,     5, 1) // tx dma completed w/ interrupt
-__SINIC_VAL32(Intr_TxPacket,  4, 1) // packet transmitted
-__SINIC_VAL32(Intr_RxHigh,    3, 1) // rx fifo above high watermark
-__SINIC_VAL32(Intr_RxEmpty,   2, 1) // rx fifo empty
-__SINIC_VAL32(Intr_RxDMA,     1, 1) // rx dma completed w/ interrupt
-__SINIC_VAL32(Intr_RxPacket,  0, 1) // packet received
-__SINIC_REG32(Intr_All,       0x01ff) // all valid interrupts
-__SINIC_REG32(Intr_NoDelay,   0x01cc) // interrupts that aren't coalesced
-__SINIC_REG32(Intr_Res,      ~0x01ff) // reserved interrupt bits
-
-// RX Data Description
-__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(TxData_Checksum, 62,  1) // do checksum
-__SINIC_VAL64(TxData_Vaddr,    60,  1) // Addr is virtual
-__SINIC_VAL64(TxData_Len,      40, 20) // 0 - 256k
-__SINIC_VAL64(TxData_Addr,      0, 40) // Address 1TB
-
-// RX Done/Busy Information
-__SINIC_VAL64(RxDone_Packets,   32, 16) // number of packets in rx fifo
-__SINIC_VAL64(RxDone_Busy,      31,  1) // receive dma busy copying
-__SINIC_VAL64(RxDone_Complete,  30,  1) // valid data (packet complete)
-__SINIC_VAL64(RxDone_More,      29,  1) // Packet has more data (dma again)
-__SINIC_VAL64(RxDone_Empty,     28,  1) // rx fifo is empty
-__SINIC_VAL64(RxDone_High,      27,  1) // rx fifo is above the watermark
-__SINIC_VAL64(RxDone_NotHigh,   26,  1) // rxfifo never hit the high watermark
-__SINIC_VAL64(RxDone_TcpError,  25,  1) // TCP packet error (bad checksum)
-__SINIC_VAL64(RxDone_UdpError,  24,  1) // UDP packet error (bad checksum)
-__SINIC_VAL64(RxDone_IpError,   23,  1) // IP packet error (bad checksum)
-__SINIC_VAL64(RxDone_TcpPacket, 22,  1) // this is a TCP packet
-__SINIC_VAL64(RxDone_UdpPacket, 21,  1) // this is a UDP packet
-__SINIC_VAL64(RxDone_IpPacket,  20,  1) // this is an IP packet
-__SINIC_VAL64(RxDone_CopyLen,    0, 20) // up to 256k
-
-// TX Done/Busy Information
-__SINIC_VAL64(TxDone_Packets,   32, 16) // number of packets in tx fifo
-__SINIC_VAL64(TxDone_Busy,      31,  1) // transmit dma busy copying
-__SINIC_VAL64(TxDone_Complete,  30,  1) // valid data (packet complete)
-__SINIC_VAL64(TxDone_Full,      29,  1) // tx fifo is full
-__SINIC_VAL64(TxDone_Low,       28,  1) // tx fifo is below the watermark
-__SINIC_VAL64(TxDone_Res0,      27,  1) // reserved
-__SINIC_VAL64(TxDone_Res1,      26,  1) // reserved
-__SINIC_VAL64(TxDone_Res2,      25,  1) // reserved
-__SINIC_VAL64(TxDone_Res3,      24,  1) // reserved
-__SINIC_VAL64(TxDone_Res4,      23,  1) // reserved
-__SINIC_VAL64(TxDone_Res5,      22,  1) // reserved
-__SINIC_VAL64(TxDone_Res6,      21,  1) // reserved
-__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;
-    bool read;
-    bool write;
-    const char *name;
-};
-
-} // namespace Regs
-
-inline const Regs::Info&
-regInfo(Addr daddr)
-{
-    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, "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, "RxWait"       },
-        invalid,
-        { 8, true,  true,  "TxData"       },
-        invalid,
-        { 8, true,  false, "TxDone"       },
-        invalid,
-        { 8, true,  false, "TxWait"       },
-        invalid,
-        { 8, true,  false, "HwAddr"       },
-        invalid,
-        { 8, true,  false, "RxStatus"     },
-        invalid,
-    };
-
-    return info[daddr / 4];
-}
-
-inline bool
-regValid(Addr daddr)
-{
-    if (daddr > Regs::Size)
-        return false;
-
-    if (regInfo(daddr).size == 0)
-        return false;
-
-    return true;
-}
-
-} // namespace Sinic
-
-#endif // __DEV_SINICREG_HH__
diff --git a/src/dev/tcp_iface.cc b/src/dev/tcp_iface.cc
deleted file mode 100644 (file)
index f18486f..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * TCP stream socket based interface class implementation for multi gem5 runs.
- */
-
-#include "dev/tcp_iface.hh"
-
-#include <arpa/inet.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <cerrno>
-#include <cstring>
-
-#include "base/types.hh"
-#include "debug/MultiEthernet.hh"
-
-// MSG_NOSIGNAL does not exists on OS X
-#if defined(__APPLE__) || defined(__MACH__)
-#ifndef MSG_NOSIGNAL
-#define MSG_NOSIGNAL SO_NOSIGPIPE
-#endif
-#endif
-
-using namespace std;
-
-vector<int> TCPIface::sockRegistry;
-
-TCPIface::TCPIface(string server_name, unsigned server_port,
-                   unsigned multi_rank, Tick sync_start, Tick sync_repeat,
-                   EventManager *em) :
-    MultiIface(multi_rank, sync_start, sync_repeat, em)
-{
-    struct addrinfo addr_hint, *addr_results;
-    int ret;
-
-    string port_str = to_string(server_port);
-
-    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
-    panic_if(sock < 0, "socket() failed: %s", strerror(errno));
-
-    bzero(&addr_hint, sizeof(addr_hint));
-    addr_hint.ai_family = AF_INET;
-    addr_hint.ai_socktype = SOCK_STREAM;
-    addr_hint.ai_protocol = IPPROTO_TCP;
-
-    ret = getaddrinfo(server_name.c_str(), port_str.c_str(),
-                      &addr_hint, &addr_results);
-    panic_if(ret < 0, "getaddrinf() failed: %s", strerror(errno));
-
-    DPRINTF(MultiEthernet, "Connecting to %s:%u\n",
-            server_name.c_str(), port_str.c_str());
-
-    ret = ::connect(sock, (struct sockaddr *)(addr_results->ai_addr),
-                    addr_results->ai_addrlen);
-    panic_if(ret < 0, "connect() failed: %s", strerror(errno));
-
-    freeaddrinfo(addr_results);
-    // add our socket to the static registry
-    sockRegistry.push_back(sock);
-    // let the server know who we are
-    sendTCP(sock, &multi_rank, sizeof(multi_rank));
-}
-
-TCPIface::~TCPIface()
-{
-    int M5_VAR_USED ret;
-
-    ret = close(sock);
-    assert(ret == 0);
-}
-
-void
-TCPIface::sendTCP(int sock, void *buf, unsigned length)
-{
-    ssize_t ret;
-
-    ret = ::send(sock, buf, length, MSG_NOSIGNAL);
-    panic_if(ret < 0, "send() failed: %s", strerror(errno));
-    panic_if(ret != length, "send() failed");
-}
-
-bool
-TCPIface::recvTCP(int sock, void *buf, unsigned length)
-{
-    ssize_t ret;
-
-    ret = ::recv(sock, buf, length,  MSG_WAITALL );
-    if (ret < 0) {
-        if (errno == ECONNRESET || errno == EPIPE)
-            inform("recv(): %s", strerror(errno));
-        else if (ret < 0)
-            panic("recv() failed: %s", strerror(errno));
-    } else if (ret == 0) {
-        inform("recv(): Connection closed");
-    } else if (ret != length)
-        panic("recv() failed");
-
-    return (ret == length);
-}
-
-void
-TCPIface::syncRaw(MultiHeaderPkt::MsgType sync_req, Tick sync_tick)
-{
-    /*
-     * Barrier is simply implemented by point-to-point messages to the server
-     * for now. This method is called by only one TCPIface object.
-     * The server will send back an 'ack' message when it gets the
-     * sync request from all clients.
-     */
-    MultiHeaderPkt::Header header_pkt;
-    header_pkt.msgType = sync_req;
-    header_pkt.sendTick = sync_tick;
-
-    for (auto s : sockRegistry)
-        sendTCP(s, (void *)&header_pkt, sizeof(header_pkt));
-}
-
diff --git a/src/dev/tcp_iface.hh b/src/dev/tcp_iface.hh
deleted file mode 100644 (file)
index 553f862..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2015 ARM Limited
- * All rights reserved
- *
- * The license below extends only to copyright in the software and shall
- * not be construed as granting a license to any other intellectual
- * property including but not limited to intellectual property relating
- * to a hardware implementation of the functionality of the software
- * licensed hereunder.  You may use the software subject to the license
- * terms below provided that you ensure that this notice is replicated
- * unmodified and in its entirety in all distributions of the software,
- * modified or unmodified, in source code or in binary form.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Gabor Dozsa
- */
-
-/* @file
- * TCP stream socket based interface class for multi gem5 runs.
- *
- * For a high level description about multi gem5 see comments in
- * header file multi_iface.hh.
- *
- * The TCP subclass of MultiIface uses a separate server process
- * (see tcp_server.[hh,cc] under directory gem5/util/multi). Each gem5
- * process connects to the server via a stream socket. The server process
- * transfers messages and co-ordinates the synchronisation among the gem5
- * peers.
- */
-#ifndef __DEV_TCP_IFACE_HH__
-#define __DEV_TCP_IFACE_HH__
-
-
-#include <string>
-
-#include "dev/multi_iface.hh"
-
-class EventManager;
-
-class TCPIface : public MultiIface
-{
-  private:
-    /**
-     * The stream socket to connect to the server.
-     */
-    int sock;
-
-    /**
-     * Registry for all sockets to the server opened by this gem5 process.
-     */
-    static std::vector<int> sockRegistry;
-
-  private:
-
-    /**
-     * Send out a message through a TCP stream socket.
-     *
-     * @param sock TCP stream socket.
-     * @param buf Start address of the message.
-     * @param length Size of the message in bytes.
-     */
-    void
-    sendTCP(int sock, void *buf, unsigned length);
-
-    /**
-     * Receive the next incoming message through a TCP stream socket.
-     *
-     * @param sock TCP stream socket.
-     * @param buf Start address of buffer to store the message.
-     * @param length Exact size of the expected message in bytes.
-     */
-    bool recvTCP(int sock, void *buf, unsigned length);
-
-
-  protected:
-
-    virtual void
-    sendRaw(void *buf, unsigned length,
-            const MultiHeaderPkt::AddressType dest_addr=nullptr) override
-    {
-        sendTCP(sock, buf, length);
-    }
-
-    virtual bool recvRaw(void *buf, unsigned length) override
-    {
-        return recvTCP(sock, buf, length);
-    }
-
-    virtual void syncRaw(MultiHeaderPkt::MsgType sync_req,
-                         Tick sync_tick) override;
-
-  public:
-    /**
-     * The ctor creates and connects the stream socket to the server.
-     * @param server_name The name (or IP address) of the host running the
-     * server process.
-     * @param server_port The port number the server listening for new
-     * connections.
-     * @param sync_start The tick for the first multi synchronisation.
-     * @param sync_repeat The frequency of multi synchronisation.
-     * @param em The EventManager object associated with the simulated
-     * Ethernet link.
-     */
-    TCPIface(std::string server_name, unsigned server_port,
-             unsigned multi_rank, Tick sync_start, Tick sync_repeat,
-             EventManager *em);
-
-    ~TCPIface() override;
-};
-
-#endif
index 85a303b434c8871140e88b8cc27ec2266f9d073e..79d7c3581260abcf7d1e5385928dc7f42feb1891 100644 (file)
@@ -36,8 +36,8 @@
 #include "base/output.hh"
 #include "config/the_isa.hh"
 #if THE_ISA != NULL_ISA
-#include "dev/etherdevice.hh"
-#include "dev/etherobject.hh"
+#include "dev/net/etherdevice.hh"
+#include "dev/net/etherobject.hh"
 #endif
 #include "mem/ruby/slicc_interface/AbstractController.hh"
 #include "mem/mem_object.hh"
index ea2948826d35e181454dc9815b7d5069a42dc21f..6147e4bd978936cb69d4d3bb4819ff1c2d3c420f 100644 (file)
@@ -31,7 +31,7 @@
 #include <Python.h>
 
 #include "base/types.hh"
-#include "dev/etherint.hh"
+#include "dev/net/etherint.hh"
 #include "sim/serialize.hh"
 #include "sim/sim_object.hh"