= 100Base-X Ethernet cores

This repository contains several cores which can be used to implement 100Base-X
Ethernet PHYs, Hubs (Repeaters) and more. All cores are synchronous and are
designed to be used in a single 125 MHz clock domain. These cores target Lattice
iCE40 HX FPGAs (in terms of timing), but most modules are not specific to any
FPGA.

== Building and testing

The following dependencies are required to build this project. Where known,
specific minimum versions have been specified.

- https://yosyshq.net/yosys/[Yosys] >= 0.4
- http://iverilog.icarus.com/[Icarus Verilog] >= 12.0
- https://www.cocotb.org/[cocotb]
- https://github.com/YosysHQ/nextpnr[nextpnr]
- https://clifford.at/icestorm[IceStorm]

To build the example designs (under `examples/`), run

    $ make -j$(nproc)

The outputs will be in their respective directories.

To run pre- and post-synthesis tests, run

    $ make -j$(nproc) -O test

To run a pre-synthesis testbench, run

    $ make MODULE.fst

where `MODULE` is the name of the module to test. To run post-synthesis
simulation, run

    $ make MODULE.synth.fst

You can view `.fst` files with https://gtkwave.sourceforge.net/[GTKWave].

== Resource usage

The following sections show device utilization reports for various
configurations. All cores are verified to work at 125 MHz.

=== PHY with internal MII

These are the resources used by `phy_internal` with a minimal wrapper necessary
to ensure proper timing:

|===
| LUTs | `WISHBONE` | `ENABLE_COUNTERS`

|  408 |          0 |                 0
|  486 |          1 |                 0
|  812 |          1 |                 1
|===

== Modules

This section describes each module found in the `rtl` directory.

=== `axis_replay_buffer`

This module implements an AXI-stream FIFO that can be "`replayed`" indefinitely.
That is, it will store the first `BUF_SIZE` cycles in a BRAM, and when requested
it will send them over the master interface again. Once the buffer is exhausted
it will wait for a replay or continue command. After continuing, it acts as a
regular synchronous FIFO. This module is intended to help implementing
half-duplex Ethernet MACs.

=== `axis_mii_tx`

This module implements the transmit half of a full- or half-duplex Ethernet MAC.
It implements the full CS/CDMA algorithm, and automatically prepends an 8-byte
preamble/SFD and appends a 4-byte FCS to the data. It currently only supports
100M ethernet, although 10M would be easy to add. I have no plans to support
1000M.

=== `axis_wb_bridge`

This module implements an AXI Stream to Wishbone bridge. This is not a
more-typical DMA bridge, where streaming data is written in a fixed pattern.
Rather, this module allows interactive or scripted examination and readout
of a Wishbone bus. For more details on the protocol implemented by this bridge,
refer to the xref:doc/uart_wb_bridge.adoc#protocol[UART-Wishbone Bridge
documentation].

=== `descramble`

This implements a descrambler as specified in ANSI X3.264-1995 section 7.2.3. It
uses the idle sections in the IPG to lock onto the far end's scrambler. It
typically acquires a lock after 29 bits of data, and will lose lock unless 29
idle bits are presented every 4500 bytes. Jumbo frames can be easily supported
by modifying the unlock timeout value.

=== `hub`

This implements an N-port hub (repeater) as specified in IEEE 802.3 clause 29
with a Wishbone management interface.  Each port implements a separate PHY
(including a PCS) and an elastic buffer. The hub core reconciles incoming data
and transmits it over other ports, generating jam bytes as necessary. At the
moment, partitioning and link stability detection are not implemented.

=== `hub_core`

This implements the core hub functionality. It is completely stateless; it only
creates jams when multiple ports have incoming data at the same time.

=== `led_blinker`

This implements LED blinking typical of switches and hubs. When triggered, the
appropriate LED is activated at for one 30 Hz cycle. All LEDs blink in unison.
This is suitable for displaying signals which would otherwise be too short to
notice.

=== `mdio`

This is an MII Management Interface to Wishbone bridge. It decodes management
frames as specified in IEEE 802.3 22.2.4.5. If the Wishbone slave times out or
returns an error response, the MDIO line remains in high-impedance mode. This
allows implementing the behavior for unimplemented registers specified in
22.2.4.3.

=== `mdio_io`

This module instantiates the appropriate I/O block for the MDC, MDIO signals, and an
output-enable for an external level-shifter. It is intended for use with the
`mdio` module.

=== `mdio_regs`

This module implements IEEE 802.3 clause 22 registers over a Wishbone interface.
It may either be used with the `mdio` module or with an internal Wishbone bus.
In addition to the standard MII registers, it also implements several error
counter registers in the vendor-specific address space.  Autonegotiation is not
yet supported. 

=== `mii_elastic_buffer`

This implements an elastic buffer for MII. It is a FIFO where data is only
offered when the internal level reaches half-full. This allows smoothing out
differences in clock speed between the local oscillator and the far end.

=== `mii_io_rx`

This module instantiates the appropriate I/O blocks for the receive MII signals
(`RX_CLK`, `RX_DV`, `RXD`, and `RX_ER`). Due to differences in the local and
far-end clock rates, the duty cycle of `RX_CLK` may vary, but will always remain
within limits. Isolation is supported.

=== `mii_io_tx`

This module instantiates the appropriate I/O blocks for the transmit MII signals
(`TX_CLK`, `TX_EN`, `TXD`, `TX_ER`). Isolation is supported.

=== `nrzi_decode`

This module decodes NRZI signals to NRZ.

=== `nrzi_encode`

This module encodes NRZ signals to NRZI.

=== `pcs_rx`

This module implements the receive half of a 100Base-X PCS as specified in IEEE
802.3 24.2. Internally, the `pcs_rx_bits` module performs the serial-to-parallel
conversion and handles the alignment process. It is controlled by the `pcs_rx`
module, which implements the main receive state machine. Back-to-back packets
are not supported; at least two idle bits must be present between packets.

=== `pcs_tx`

This module implements the transmit half of a 100Base-X PCS as specified in IEEE
802.3 24.2. It is a fairly straightforward implementation of the state machine
and encoding process.

=== `phy_core`

This module integrates the 100Base-X PCS and PMA, and the (de)scrambling part of
the 100Base-T PMD. It coordinates loopback functionality. It also support
collision testing.

=== `pmd_dp83223`

This module implements a 100Base-T PMD (except for (de)scrambling) when combined
with a National Instruments DP83223 "Twister" transciever. The transmit half is
quite simple, and most of the trick parts are implemented in the
`pmd_dp83223_rx` module. This module support loopback.

=== `pmd_dp83223_rx`

This module interfaces with a DP83223 and brings its signals into the local
clock domain. It uses 4x oversampling and determines an appropriate sample using
the techniques described in https://docs.xilinx.com/v/u/en-US/xapp225[Xilinx
XAPP225] to select an appropriate sample. The specific implementation is a bit
different since we use a 250 Mhz clock with a DDR FF (as opposed to four 125 MHz
clocks in quadrature) and the selection process is split over several clock
cycles. While most cycles will produce one bit of data, occasionally zero or two
bits will be produced, due to differences in frequency between the local and far
ends. This is a disadvantage when compared to a PLL-based solution, as the
entire rest of the data path up to the PCS (when we can finally align the data)
must handle these edge cases. However, it avoids the internal,
nebulously-specified, and limited-in-number iCE40 PLLs.

=== `reset_sync`

This module synchronizes external reset signals (asynchronous assert and
release) into the local clock domain (asynchronous assert, desynchronous
release). A glitch filter suppresses spurious resets.

=== `scramble`

This module implements a scrambler as described in ANSI X3.264-1995 section
7.1.1.

=== `uart_tx`

A standard UART transmit module, accepting AXI-stream. 8n1 only. Supports
115,200 and 4,000,000 baud.

=== `uart_rx`

A standard UART receive module, outputting AXI-stream. 8n1 only. Supports
115,200 and 4,000,000 baud. Properly detects breaks as (single) frame errors,
and ignores runt start bits.

=== `uart_wb_bridge`

This module combines the above UART cores with the AXI-stream bridge from before
to allow controlling a Wishbone bus over a UART. There is no internal buffering,
but some FIFOs could easily be added to allow more in-flight transactions. At
the moment this only supports 16 data busses with 16-bit granularity. Frame
errors (breaks) reset the bridge (but not the UARTs), providing an "`out of
band`" ability for synchronization.

=== `wb_mux`

This implements a simple Wishbone mux, allowing a single master to access
several slaves. The address decoding is greatly simplified by assigning each
slave a (priority-decoded) address bit.

== Interfaces

Throughout this project, a variety of interfaces, some standard and some
bespoke, are used to communicate between cores. This section describes these
interfaces.

=== "`MII`"

This is the Media-Independent Interface (MII) described by IEEE 802.3 clause 22.
However, instead of RX and TX clocks, clock-enables are used instead. This is a
better fit for the clocking resources found on iCE40 FPGAs. In the 125 MHz clock
domain used by these cores, the clock enable is asserted every 5 clock cycles.
The clock enable generated by `pcs_rx` may vary somewhat from this due to
differences in the local and far end clocks. The `mii_elastic_buffer` module can
be used to smooth out these variations over the course of a frame.

=== "`PMD`"

This is a bespoke interface used by modules in the receive data path below the
PCS layer. It consists of three signals: `clk`, `data`, and `data_valid`. `data`
and `data_valid` are both two bits wide. Data is transferred on the rising edge
of `clk`. The following table shows the relation between `data` and
`data_valid`:

[cols="1,1,1"]
|===
| `data_valid` | `data[1]` | `data[0]`

|            0 | Invalid   | Invalid
|            1 | Valid     | Invalid
|       2 or 3 | Valid     | Valid
|===

In the case where both bits in `data` are valid, `data[1]` is the most recent
bit. As a consequence, when `data_valid` is non-zero, `data[1]` always holds the
new bit to process. Because three bits cannot be transferred at once, only
`data_valid[1]` is necessary to determine if two bits are to be transferred.

=== AXI-Stream

This is https://zipcpu.com/doc/axi-stream.pdf[AMBA 4 AXI4-Stream], minus several
signals. Generally, `ARESETn`, `TSTRB`, `TKEEP`, `TID`, `TDEST` are ommitted.
Sometimes `TUSER` is omitted as well. Additionally, the `A` and `T` prefixes
are not used.

=== Wishbone

This is https://cdn.opencores.org/downloads/wbspec_b4.pdf[Wishbone B4] in
non-pipelined mode. Generally, `RST`, `TGA`, `TGC`, `TGD`, `RTY`, `SEL`, and
`LOCK` signals are omitted. The `_I` and `_O` suffixes are not used. `DAT` is
named `data_read` or `data_write`, depending on the direction of transfer. `ADR`
is expanded to `addr`.
