Implement generic MAX2771 raw Ethernet recorder

This commit is contained in:
onur
2026-08-01 01:15:47 +03:00
commit 79d07fdda7
57 changed files with 4810 additions and 0 deletions
+26
View File
@@ -0,0 +1,26 @@
# Hardware assumptions index
Board-specific facts and assumptions are kept beside the target that uses them:
- [Genesys 2 hardware assumptions](../targets/genesys2/docs/hardware_assumptions.md)
- [Efinix Ti375 C529 hardware assumptions](../targets/efinix_ti375_c529/docs/hardware_assumptions.md)
The following items are shared assumptions from the recorder specification:
- the MAX2771 produces one literal 4-bit word on every selected RF clock edge;
- nominal maximum RF clock frequency is 32.736 MHz;
- the default capture edge is rising and the default packing puts the earlier
sample in the high nibble;
- the source cannot be backpressured.
The following are deliberately **not** claimed as verified:
- MAX2771 clock-to-data minimum and maximum delays at the connector;
- RF cable/adapter clock-to-data skew and signal integrity;
- a loss-free sample-zero boundary when RF capture starts before Gigabit link;
- timing behavior outside the FPGA speed/temperature model selected by each
target build.
Obtain the MAX2771 timing values from the exact device/mode datasheet and
measure the assembled clock/data path before final board-level timing sign-off.
No arbitrary `set_input_delay` is presented as a measured value.
+65
View File
@@ -0,0 +1,65 @@
# MAX2771 raw Ethernet protocol
This protocol is Ethernet Layer 2 only. It has no IP, ARP, DHCP, ICMP, UDP, or TCP component.
## Ethernet envelope
| Item | Value |
|---|---|
| Preamble | seven bytes `55` |
| SFD | `D5` |
| Destination | `FF:FF:FF:FF:FF:FF` |
| Source | `02:27:71:00:00:01` |
| EtherType | `0x88B5`, most-significant byte first |
| Maximum Ethernet payload | 1500 bytes |
| VLAN / jumbo frames | not used |
| FCS | reflected Ethernet CRC-32, inverted, least-significant byte first |
| IFG | at least 12 byte times |
The CRC is initialized to `0xFFFFFFFF`, updated LSB-first over destination MAC through the final payload or pad byte with reflected polynomial `0xEDB88320`, then inverted. Preamble and SFD are not part of the CRC. Linux NICs normally remove preamble, SFD, and FCS before an `AF_PACKET` application receives the frame.
## Custom payload header
All multibyte header fields use network byte order. The fixed header is exactly 32 bytes.
| Offset | Size | Field | Encoding |
|---:|---:|---|---|
| 0 | 4 | magic | ASCII `MX27` (`4D 58 32 37`) |
| 4 | 1 | version | `1` |
| 5 | 1 | flags | described below |
| 6 | 2 | header length | `0x0020` |
| 8 | 4 | data-frame sequence | unsigned, wraps modulo 2^32 |
| 12 | 8 | first sample index | unsigned absolute RF sample index |
| 20 | 2 | sample count | number of real 4-bit samples in this frame |
| 22 | 1 | bits per sample | `4` |
| 23 | 1 | packing format | `1` for earlier sample in high nibble |
| 24 | 4 | dropped sample count | cumulative FPGA count, low 32 bits |
| 28 | 4 | reserved | zero |
Flags are:
| Bit | Meaning |
|---:|---|
| 0 | FIFO overflow/input loss occurred since the previous reported packet |
| 1 | first data packet after FPGA reset |
| 2 | first data packet after the PHY reports a resolved 1000BASE-T full-duplex link |
| 7:3 | zero |
Normal frames contain a 32-byte custom header and 1468 data bytes: exactly 2936 samples. Sequence increments once per transmitted data frame. A sample with index `N` followed by `N+1` is contiguous regardless of nibble values.
## Packing
For samples `S0, S1, S2, S3`, each limited to four bits, data bytes are:
```text
byte 0 = {S0[3:0], S1[3:0]}
byte 1 = {S2[3:0], S3[3:0]}
```
There is no sign extension, I/Q interpretation, bit reversal, or numeric conversion. An exceptional overflow boundary can close a short frame. If its sample count is odd, the unused low nibble of the final frame byte is zero and is not a sample. The host parser uses `sample_count`, so it never writes that pad nibble.
## Loss semantics
Each FIFO entry carries its absolute 64-bit input sample index. The packetizer compares adjacent entries. If a full-FIFO interval creates an index discontinuity, it closes the pre-gap packet as an exceptional partial frame and begins the next packet at the first post-gap index. This makes the missing interval visible to the host. It never silently crosses a gap inside a packet.
Packet-sequence gaps indicate frames lost after the FPGA MAC. Sample-index gaps indicate missing sample time, whether due to an FPGA overflow or a lost Ethernet frame. The cumulative drop field distinguishes FPGA-side input loss. The receiver extends the low-32-bit drop count across wraps while it is running.
+24
View File
@@ -0,0 +1,24 @@
# Timing constraints index
The authoritative target timing notes are:
- [Genesys 2 timing constraints](../targets/genesys2/docs/timing_constraints.md)
- [Efinix timing/build notes](../targets/efinix_ti375_c529/docs/efinity_flow.md)
Both implementations constrain the RF clock to 30.547 ns by default and the
Ethernet GMII domain to 8.000 ns. Their generated 125 MHz RGMII transmit clock
phase and board-specific I/O timing are created in the corresponding target
clock/periphery implementation.
Only known asynchronous relationships and synchronizer/Gray-pointer CDC paths
are treated as asynchronous. The design does not apply a broad false path from
RF capture to Ethernet logic; the handwritten asynchronous FIFO is the explicit
boundary. Unknown MAX2771 external input delays remain documented measurement
requirements rather than invented constraints.
Clean builds checked on 1 August 2026 reported:
| Target | Setup slack | Hold slack | CDC |
|---|---:|---:|---|
| Genesys 2, Vivado 2026.1 | +0.212 ns worst | +0.090 ns worst | no unexpected major warning accepted by build script |
| Ti375 C529, Efinity 2026.1 | +0.636 ns Ethernet, +25.614 ns RF | +0.094 ns Ethernet, +0.031 ns RF | no synchronizer warnings |