Ethernet Open Core integration on Spartan 3E Starter Kit

Design overview
The Spartan 3E Starter Kit has an Ethernet port, but, unlike the Altera DE2, the chip associated with this port does not implement an Ethernet controller, it only implements the PHY i.e. the physical transceiver layer. This means that in order to send and receive packets over this interface, we need an Ethernet controller. In this design, we use an open core Ethernet controller from Opencores. A host module demonstrates the use of the Ethernet controller; it receives packets and loops them back out without modification.
Supporting documentation
The chip manufacturer and part number is SMSC LAN83C185 and its datasheet can be found here.

The Ethernet controller from Opencores comes with enough documentation to use the core without having to look at the Verilog code too often. There is in particular a specification document and a design document.
Open Core Ethernet Controller
The controller presents three interfaces:
  1. An interface to the PHY
  2. An interface to external memory where the packets will be stored
  3. A user interface that allows the set-up of the rx/tx buffer descriptors and the read/write of the various registers
The PHY interface is straightforward and there is nothing to do there except convert the tristate i/o into two distinct wires.

The controller uses the external memory interface to read and write packets. The user
controls the addresses by setting up the appropriate pointers in the buffer descriptors. This interface is a standard Wishbone interface. Obviously the controller is a master (DMA) and the memory is a slave.

The third interface can be conceptually divided into two different parts. One is composed of the registers and the other is composed of the buffer descriptors. The registers allow control of the ethernet controller, such as setting the modes, the mac address, etc. The buffer descriptors allow the user to control the receiving and sending of packets and where in the external memory the packets are stored. Buffer descriptors are either transmit or receive. They are 8-bytes long; the first 4-bytes contain the status/control of the packet and the last 4-bytes contain the external memory address of the buffer where the packet is stored. The interface is a standard Wishbone interface. Obviously, this interface is a slave, and the host is the master.
Here is the design diagram:

ethernet design diagram

The top level module, eth_loopback, instantiates the host, the memory and the wishbone arbiter.

We choose the DDR SDRAM as external memory, and for this we re-use the Xilinx MIG2.0 controller. The main change here is that we need to add a module to convert from the Wishbone to the MIG2.0 proprietary interface. The module that provides this conversion is memory_wb_to_mig. Also note that the MIG2.0-generated constraint file will cause a problem as generated because the IO standard of the net is not declared. Be sure to change the line:
NET "cntrl0_rst_dqs_div" LOC = P13 ;
NET "cntrl0_rst_dqs_div" LOC = P13  | IOSTANDARD = LVCMOS33 ;

To interconnect and arbitrate the two masters and two slaves, we use eth_cop, a simple arbiter provided with the test bench of the Ethernet core. The module needs very slight modifications in order for it to be synthetizable with XST and this also impacts some of the constants in the defines files. Also note that the define MEM_BASE that is specific to the ethernet cop needs to be renamed because it conflicts with a MIG2.0 define. The arbitration provided by eth_cop is based on the address values:
The host module loopback_controller reads incoming packets and sends them back out without modification. The loopback algorithm is straightforward:
initialize mode register
  initialize one rx buffer descriptor
  wait until packet received in corresponding buffer descriptor
  initialize tx buffer descriptor w/ same address as rx buffer and same length

The default parameters are used for all registers except the mode register. The mode register needs its tx and rx bits set in order to enable receive and transmit.

Buffer descriptors are composed of a pointer and of control/status bits. The pointer is simply the DDR SDRAM address of the packet data. Some control/status bits are determined by the user, for example the CRC bit in the tx buffer descriptor tells the Ethernet core to calculate and add the CRC before sending the packet and some control/status bits are determined by the Ethernet core, for example tx or rx errors will be indicated to the user. One particularly important control/status bit is the enable bit. In a rx buffer descriptor an enable bit set to 1 indicates to the core that it can write the buffer descriptor and its associated buffer for packet reception. Once the packet is received, the core resets the enable bit, and the user can read the received packet and its status. The tx buffer descriptors contain a similar enable bit. The user sets it to tell the core to send a packet. Once sent, the core resets this bit indicating that the packet was sent (or at least that there was an attempt to send it).
Using the design
Design files