ITCH hardware at a glance

NASDAQ ITCH 5.0 parsed in FPGA fabric — live UDP/MoldUDP64 Ethernet ingress on a Nexys A7-100T, an 8-bit streaming parser, a dual-sided 512-slot BRAM order book, and best bid / best offer (BBO) in fixed clock cycles. LEDs and the 7-segment display close the loop on silicon.

Nexys A7-100T bench photo
Figure 1. Nexys A7-100T on the bench — Ethernet to host, bitstream loaded
GitHub Repository TM logotmarhguy.com

First clean Vivado run (2026-08-02, USE_ETH=1, Vivado 2025.2): timing met at 100 MHz (WNS +1.552 ns, WHS +0.033 ns), ~2% LUT, sim latency 3 cycles to record_valid and 6 cycles to bbo_valid on the Add path.

About this manual

This is the detailed engineering reference for the project. It is the companion to the concise, GitHub-facing README.md:

  • README.md — project identity, status, and quick start.

  • docs/ (this manual) — architecture, message formats, interfaces, verification, implementation, and measured behaviour.

  • docs/*.md — normative companions (architecture.md, metrics.md, board_eth_setup.md), linked not duplicated.

  • log/ — dated lab journal (2026-08-02 synthesis/bitstream, Ethernet cable bring-up), summarized in Lab Journal.

Conventions used throughout:

  • monospace marks signals, file paths, commands, and literals.

  • File paths are repository-relative, e.g. rtl/book/order_book.sv.

  • Unmeasured values are written as TBD (unmeasured) — never silently estimated.

  • Numbers in Performance and Implementation are post-route Vivado results and cocotb measurements from the 2026-08-02 build.

Start with Introduction for scope and reading order, then Architecture for the system overview.

1. Introduction

This chapter defines what the system is, what this manual covers, and how to navigate the rest of the document.

1.1. Purpose

NASDAQ’s ITCH feed is a binary stream of Add, Execute, and Cancel messages describing how the open book changes in real time. Exchanges do not wait for a software stack.

This project implements the hardware column: bytes arrive over Ethernet (UDP, Mold-wrapped ITCH) into a Nexys A7-100T, a streaming parser turns them into structured order events, a dual-sided on-chip order book updates and recomputes best bid / best offer (BBO), and LEDs plus the 7-segment display show the answer on silicon.

This manual is the engineering reference for that system. It records design intent, message formats, interfaces, verification strategy, Vivado implementation detail, and measured behaviour in one numbered document.

The fastest way to see what the system is: the bench photo and links at the top of this manual, plus media/a7_fpga.jpeg in the tree.

1.2. Why this exists

In conversations with business friends — especially Wharton students — NASDAQ comes up a lot. The argument starts with the open book: visible bids and asks. The goal is to make the fastest, best decision to buy at the lowest price or sell at the highest.

From a computer engineering perspective, a conventional Von Neumann CPU is a poor fit for that rapid decision-making — fetch, decode, move data through memory, repeat (the Von Neumann bottleneck). To skip the OS and avoid unnecessary data movement, the decision belongs in a hardened logic block that tells the CPU what it did: accurate, deterministic, and fast.

FPGAs sit in the middle: reconfigurability while iterating, hardened logic on paths that must be fast and deterministic. Flash a new bitstream, test, repeat — no fab run. That is what this repo explores: feed an FPGA market data over Ethernet, watch real decision-making happen in hardware, and move toward seeing trades happen one step at a time.

1.3. Scope

The manual covers:

It does not replace:

  • README.md — quick start and repository map

  • docs/architecture.md — data path, order book, BBO timing

  • docs/board_eth_setup.md — cable, LEDs, bench setup

  • docs/metrics.md — timing, utilization, latency numbers

  • log/ — full design notes and lab journal text

  • RTL comments — per-module implementation notes in rtl/

1.4. How to read this manual

Read chapters in order the first time. Chapters 1–2 give context; chapters 3–5 give the working model; chapters 6–8 give the evidence the hardware behaves as claimed.

Each chapter is self-contained enough to be entered directly from the sidebar once the overview in Architecture is familiar.

1.5. Conventions

Normal cross-reference and link usage
  • Internal references look like this: Verification.

  • External links look like this: author site.

  • Inline code uses monospace, e.g. record_valid, order_book.sv, USE_ETH=1.

  • File paths are repository-relative, e.g. rtl/top/nexys_a7_100t_top.sv.

List conventions
  • Unordered lists state properties or inventories.

  • Ordered lists state procedures where sequence matters:

    1. Program the USE_ETH=1 bitstream.

    2. Confirm link on LED15.

    3. Send Mold/ITCH UDP traffic and watch LED0/LED1.

Honest status is a project rule. Roadmap items stay labelled roadmap; unverified claims stay out of this manual. Where a number has not been measured it is written TBD (unmeasured).
The sidebar on the left is collapsible. Select a chapter title to navigate; select its arrow control to expand or collapse its subsections without leaving the page. On narrow screens the sidebar stacks above the content.

2. Architecture

System overview: what the pieces are, how bytes flow from the cable to the display, and where each piece lives in the tree.

2.1. System overview

All boxes run on one FPGA — no host in the hot path.

RMII ingress to display pipeline
Figure 2. System paths at a glance
Ethernet / UDP  ->  Parse ITCH  ->  BBO + LEDs
Mold-wrapped bytes  Order book      7-segment
                    Best bid / offer

The three stages are deliberately asymmetric: ingress is line-driven and lossy-tolerant (lab UDP), parsing is cycle-exact, and the book is stateful with a bounded rescan fallback (see Design).

2.2. Hierarchy

Top: rtl/top/nexys_a7_100t_top.sv · USE_ETH=1 · UDP port 50000.

eth_ingress -> moldudp64_rx -> itch_hw_core -> seven_segment_ctrl
(RMII + UDP)    (Mold)         (parse + book)    (best bid)
Implemented hierarchy
Figure 3. Implemented design hierarchy on xc7a100t
Table 1. Blocks and their responsibilities
Block Module Notes

Ingress

rtl/eth/eth_ingress.sv + rtl/eth/udp_rx_minimal.sv

RMII @ 50 MHz → CDC (rtl/common/byte_cdc_fifo.sv) → UDP filter @ 100 MHz; RX only

PHY link

rtl/eth/lan8720_mdio.sv

MDIO poll → LED15; eth_rstn = ~rst

Unwrap

rtl/mold/moldudp64_rx.sv

Mold length-prefix → raw ITCH bytes

Core

rtl/top/itch_hw_core.sv (rtl/itch/itch_pipeline.sv + rtl/book/order_book.sv)

itch_byte_fsm.sv → itch_record_t on record_valid; book → BBO on bbo_valid

Display

rtl/display/seven_segment_ctrl.sv

Best bid price on 8-digit hex 7-seg, 1 kHz digit scan

Types

rtl/itch/itch_types.sv

OrderSlots=512, OrderIdxW=9, Add/Execute/Cancel lengths

Cocotb tests stop at itch_hw_core — no PHY in sim (see Verification).

2.3. Clocks and reset

  • 100 MHz system (CLK100MHZ, sys_clk_pin, 10 ns) — core, book, display.

  • 50 MHz eth_refclk (20 ns) — RMII nibble capture.

  • Async groups in constraints/nexys_a7_100t.xdc: set_clock_groups -asynchronous between sys_clk_pin and eth_refclk.

  • Reset: center button rst → 2-stage rst_pipe → rst_sync at 100 MHz.

  • USE_ETH=0 ties byte_in/byte_valid to zero for core-only builds; default bitstream is USE_ETH=1.

2.4. Further reading

  • docs/architecture.md — data path, order book, BBO timing

  • docs/board_eth_setup.md — bench wiring and LEDs

  • Design — byte formats behind each box in the figure

3. Design

Message formats, parser, order book, and BBO update. This is the conceptual companion to the Vivado detail in Implementation.

3.1. ITCH subset

NASDAQ ITCH 5.0, big-endian on the wire. Only three messages are implemented (single symbol, lab scope):

Table 2. Message lengths (rtl/itch/itch_types.sv)
Type Length Meaning

A (0x41)

36 B

Add order: side, shares, stock, price

E (0x45)

31 B

Execute: order_ref + executed shares + match number

X (0x58)

23 B

Cancel: order_ref + canceled shares (0 = full)

msg_len_bytes() and msg_from_char() map the leading type byte to length and enum (MsgAdd/MsgExec/MsgCancel/MsgNone). itch_record_t carries msg, 48-bit timestamp_ns, 64-bit order_ref and stock, side (B=buy/S=sell), 32-bit price, shares, and aux_shares (exec/cancel quantity).

MoldUDP64 framing (rtl/mold/moldudp64_rx.sv): each ITCH message is preceded by a 16-bit big-endian length. StHdr collects the 2-byte prefix, StMsg streams exactly that many bytes to the parser. udp_payload_ready = itch_byte_ready && (state != StSkip).

3.2. Parser

rtl/itch/itch_byte_fsm.sv — streaming 8-bit FSM:

StIdle -> StCollect -> StDecode -> StIdle
  type/len    36 B buffer     assemble itch_record_t
  • StIdle: msg_len_bytes(byte_in); unknown type → parse_error.

  • StCollect: pack bytes into 36-byte msg_buf (avoids unpacked-array tool quirks); byte_ready = (state != StDecode).

  • StDecode: big-endian field extraction (timestamp bytes 5–10, order_ref 11–18, side byte 19, shares/price windows per type); record_valid pulses 1 cycle after assembly — ≤3 cycles after the last byte.

  • Timestamps pass through; matching/exchange sequencing is out of scope.

rtl/itch/itch_pipeline.sv wires the FSM as the itch_hw_core front end. (rtl/itch/itch_parser.sv, rtl/book/bbo_update.sv, and rtl/book/lut3_price_cmp.sv are reserved/alternate helpers; the synthesized book path is order_book.sv below.)

3.3. Order book and BBO

rtl/book/order_book.sv — dual 512-slot BRAM, keyed by order_ref[8:0]:

  • Slot word: {valid, price[31:0], shares[31:0]} (65 b), (* ram_style = "block" *) bid_mem/ask_mem.

  • One registered-read + synchronous-write process per array (BRAM-friendly). Read address raddr stages the target slot one cycle before apply_d.

  • Add: write slot, incremental BBO compare (buy: price > best_bid; sell: price < best_ask), bbo_valid immediately — 6 cycles from record_valid in sim.

  • Execute/Cancel: decrement or invalidate; if the touched price equaled the current best, start a sequential rescan (≤512 cycles); otherwise bbo_valid immediately. Unknown slot or message → book_error.

  • Price compare intent is LUT-friendly (lut3_price_cmp.sv, Tomato-style truth tables); the committed path uses direct compares.

Scan engine: scan_active/scan_warm/scan_idx/raddr, running best run_bid/run_ask accumulators, final commit to best_bid/best_ask plus bbo_valid. Reset clears all bests and scan state.

3.4. Display mapping

rtl/display/seven_segment_ctrl.sv: 8-digit multiplexed hex driver, active-low segments/anodes, REFRESH_DIV=100_000 (1 kHz digit advance at 100 MHz). Input is bbo_bid_price; digit_sel selects each nibble with canonical segment patterns. Top level also fans bbo_bid_price[10:0] to LED[14:4] for a binary readback.

Single symbol only; order_ref[8:0] aliases references that differ in upper bits. That is a documented v1 limit, not a silent assumption — see Known Limitations.

4. Interfaces

How operators and programs touch the system: board I/O, network port, bench tools, constraints, and build entry points.

4.1. Board I/O

Table 3. LEDs and display
Output Meaning

LED15

PHY link up (lan8720_mdio MDIO poll; wait ~5 s after cable connect)

LED0

ITCH message parsed (record_valid, stretched 24’hFF_FFFF)

LED1

BBO updated (bbo_valid, stretched)

LED2

Parse error (parse_error)

LED3

Book error (book_error)

LED[14:4]

bbo_bid_price[10:0] binary readback

7-seg (8-digit hex)

Best bid price (bbo_bid_price via seven_segment_ctrl)

Order: LED15 first, then send traffic, then LED0/LED1 pulse. Center button rst re-arms the pipeline; resend after reset.

Pin map lives in constraints/nexys_a7_100t.xdc (xc7a100tcsg324-1): CLK100MHZ E3, rst N17, cathodes ca–cg T10/R10/K16/K13/P15/T11/L18, anodes an[0–7] J17/J18/T9/J14/P14/T14/K2/U13, LEDs H17–V11, RMII eth_mdc/mdio/rstn/crs_dv/rxd/txd/refclk C9/A9/B3/D9/C11/D10/B9/A10/A8/D5. constraints/nexys_a7_100t_eth.xdc is the Ethernet-focused variant.

4.2. Network port

  • Lab UDP broadcast 255.255.255.255:50000 (default UDP_DST_PORT=50000).

  • FPGA is RX-only: no ARP, no TX (eth_txd=0, eth_txen=0).

  • udp_rx_minimal.sv filters Eth → IPv4 (proto 17) → UDP dest-port match, then streams payload bytes. Non-matching frames return to StIdle.

  • eth_ingress.sv captures RMII nibbles on eth_refclk, toggles a frame flag on crs_dv fall, crosses via byte_cdc_fifo, and delimits frames with frame_end into the UDP filter.

4.3. Bench tools

# Full bring-up helper (IP check + LED guide + traffic)
python tools/bench_check.py
python tools/bench_check.py --repeat 10 --skip-send

# Minimal sender (broadcast Mold/ITCH burst)
python tools/send_itch_udp.py --repeat 10
python tools/send_itch_udp.py --host 255.255.255.255 --port 50000 --repeat 3

Both tools build on sim/python/itch_ref.py encoders: two Adds (order 1 buy 100 @ 50_0000, order 2 sell 50 @ 50_1000) plus an Execute (order 1, 25 shares), wrapped with mold_wrap() (2-byte BE length prefix per message).

Table 4. Tool options
Command Effect

bench_check.py [--repeat N] [--skip-send]

check 192.168.1.x adapter, print LED guide, send N bursts

send_itch_udp.py [--host] [--port] [--repeat N]

send N Mold/ITCH UDP bursts; broadcast avoids ARP

4.4. Build and sim entry points

# Simulate (core only, no PHY)
cd sim/cocotb && pip install -r ../requirements.txt && make

# Stress (10M messages, Verilator)
make stress SIM=verilator STRESS_MSGS=10000000

# Build and program (Ethernet bitstream)
vivado -mode batch -source vivado/add_sources.tcl
vivado -mode batch -source vivado/build.tcl
  • vivado/add_sources.tcl — source list for the .xpr.

  • vivado/build.tcl — sets USE_ETH=1, runs synth_1 + impl_1 to write_bitstream (-jobs 8), prints timing/util report paths.

  • vivado/build_eth.tcl, create_eth_ip.tcl, build_windows.ps1 — variants/helpers for Ethernet builds on Windows.

  • sim/cocotb/Makefile, run_tests.py, run_tests.cmd — cocotb runners.

Broadcasting to 255.255.255.255 is correct for the point-to-point bench. Do not point production multicast at this RX-only filter — it will be dropped by the port check.

5. Operation

How to bring the board up and what running looks like: the data-in → decision → data-out loop closed on hardware.

5.1. The loop

MARKET DATA IN          DECISION              OUT
─────────────         ──────────            ───
Ethernet / UDP   →    Parse ITCH      →    BBO + LEDs
Mold-wrapped bytes    Order book           7-segment
                      Best bid / offer
  1. Market data in. Live traffic hits the LAN8720 PHY. RMII RX, UDP filter, Mold unwrap — ITCH bytes reach the parser without a CPU memcpy.

  2. Decision. The 8-bit streaming FSM decodes symbol, side, price, quantity, and timestamp. The dual 512-slot BRAM book applies the event and recomputes BBO — under 10 clock cycles on the Add path at 100 MHz.

  3. Out. LED15 = link up. LED0/LED1 pulse on parse and BBO. The 7-segment shows the best bid. LED[14:4] mirrors the low 11 bits of best bid.

5.2. Bring-up procedure

  1. Program — USE_ETH=1 bitstream from vivado/build.tcl via Hardware Manager (itch-hw.runs/impl_1/nexys_a7_100t_top.bit, xc7a100t_0 JTAG).

  2. PC network — adapter on the Nexys cable: IP 192.168.1.1, mask 255.255.255.0, gateway empty. Ignore “no internet”.

  3. Cable and link — RJ45 to board, power on, wait ~5 s. LED15 = link up.

  4. Send traffic —

    pip install -r sim/requirements.txt
    python tools/bench_check.py

    or python tools/send_itch_udp.py --repeat 10.

  5. Confirm — LED0 parse pulse, LED1 BBO pulse, 7-seg shows best bid (price 500000 in the bench script).

When the 7-seg looks wrong, press center rst and resend before assuming the book is wrong. Most bench surprises are link/broadcast issues (see Interfaces troubleshooting), not RTL.

5.3. Reset and error behaviour

  • rst_sync clears parser buffer, book bests, scan state, and display scan. LEDs 2/3 clear until the next error.

  • parse_error (LED2): unknown message type or undecodable buffer.

  • book_error (LED3): execute/cancel on an empty slot or unknown message.

  • Stretched pulses (LED0/LED1) are human-visible; sim record_valid / bbo_valid are single-cycle — do not compare bench LED timing to cocotb cycle counts directly.

The bench path is lab replay only, not production MoldUDP64 multicast. Full architecture: Architecture.

6. Verification

How the project proves the parser and book are correct — and how to re-run that proof locally. Simulation comes first: millions of synthetic ITCH events run against a Python golden model with zero BBO mismatches before any bitstream is trusted.

6.1. Reference oracle

sim/python/itch_ref.py is the intentionally simple model every RTL path must agree with:

  • encode_add / encode_execute / encode_cancel — big-endian ITCH bytes.

  • mold_wrap() — 16-bit BE length prefix per message.

  • RefOrderBook — dict of orders, apply_bytes(), bbo() as (max bid, min ask).

Every optimized path (incremental BBO, rescan) must equal exhaustive bbo() unless documented as approximate. Deleted/executed-away orders never appear.

6.2. Correctness properties

Property Where it is checked

last-byte → record_valid ≤ 5 cycles

test_e2e_latency (cocotb monitor)

record_valid → bbo_valid (Add) ≤ 6 cycles

test_e2e_latency + latency_summary.json

record_valid → bbo_valid (Exec/Cancel off-best) immediate; at-best ≤ 512-cycle rescan

test_stress_replay + test_add_exec_cancel via wait_bbo(max_cycles=600)

BBO == Python RefOrderBook.bbo() at every stride

test_stress_replay (stride-checked) + test_add_exec_cancel

corrupt/unknown bytes → parse_error, never misread

test_stress_replay asserts no stray parse_error/book_error on valid streams

Corruption handling is fail-loud: unknown type bytes raise parse_error instead of guessing; empty-slot exec/cancel raises book_error.

6.3. Running the gates

cd sim/cocotb && pip install -r ../requirements.txt && make

Stress with Verilator (resume-scale 10M):

make stress SIM=verilator STRESS_MSGS=10000000

Windows equivalent: sim/cocotb/run_tests.cmd. Latency artifact: sim/results/latency_summary.json (parse_max_cycles, bbo_max_cycles, ns @ 100 MHz) — regenerated by test_e2e_latency and consumed by Performance.

No book optimization lands without oracle agreement. The rescan path must reproduce exhaustive BBO exactly.
When adding a message type, add the encoder + oracle comparison first. A failing BBO assert is the specification; a passing one is the proof.

7. Implementation

Vivado synthesis, place-and-route, and bitstream detail. docs/metrics.md is normative for the numbers; this chapter summarizes them and states what was built.

7.1. Build snapshot

First clean end-to-end run with live Ethernet ingress (USE_ETH=1).

Item Value

Date of build

2026-08-02

Toolchain

Vivado 2025.2

FPGA part

xc7a100tcsg324-1 (Nexys A7-100T, Artix-7)

Top module

nexys_a7_100t_top

Clock

100 MHz (sys_clk_pin, 10 ns) + 50 MHz eth_refclk

Generics

USE_ETH=1, UDP_DST_PORT=50000

Runs

synth_1 ✓ · impl_1 ✓ · write_bitstream ✓

Bitstream

itch-hw.runs/impl_1/nexys_a7_100t_top.bit

Project summary timing and utilization
Figure 4. Project summary — timing closed with headroom on Artix-7 100T

7.2. Reports on disk

vivado/build.tcl (batch from repo root):

vivado -mode batch -source vivado/add_sources.tcl
vivado -mode batch -source vivado/build.tcl

build.tcl sets generic {USE_ETH=1} on sources_1, launches synth_1 then impl_1 -to_step write_bitstream -jobs 8, and prints:

  • *.timing_summary_routed.rpt → WNS, TNS, WHS, THS

  • *.utilization_placed.rpt → LUT, FF, BRAM counts

  • *.power_routed.rpt → total power

under itch-hw.runs/impl_1/. Update Performance and docs/metrics.md badges from those reports.

7.3. What the diagrams show

  • synth_design_diagram.png — package view: RMII Ethernet pins (eth_mdc/mdio/rxd/crs_dv) and status LEDs on the Nexys ballout.

  • impl_design_diagram.png — placed hierarchy: gen_eth.u_eth (eth_ingress) → gen_eth.u_mold (moldudp64_rx) → u_core (itch_hw_core) → u_display (seven_segment_ctrl).

  • design_run_succ_synth.png — Design Runs with synth_1/impl_1 green; bitstream_dialog.png — Program Device ready on xc7a100t_0.

Synth package view
Figure 5. Synthesized package pins for Ethernet and LEDs
Program device dialog
Figure 6. Program Device — bitstream generated, board connected
Never hand-edit generated itch-hw.runs/ reports to change the numbers. Rebuild with vivado/build.tcl and copy the routed values — the only writers that preserve the timing-closure claim.

8. Performance

Measured behaviour only. Unmeasured values are TBD (unmeasured). Source build: 2026-08-02 USE_ETH=1, Vivado 2025.2, cocotb @ 100 MHz.

8.1. Timing (post-route impl_1, routed)

Metric Target Measured Status

WNS

≥ 0 ns

+1.552 ns

Met

TNS

0 ns

0.000 ns

Met

WHS

≥ 0 ns

+0.033 ns

Met

THS

0 ns

0.000 ns

Met

Failed routes

0

0

Met

Timing closed at 100 MHz with headroom. Full table: docs/metrics.md.

8.2. Utilization and power

Light footprint — room left on the 100T for deeper book logic.

Resource Used (approx.) Available %

Slice LUTs

—

63,400

2%

Slice FFs

—

126,800

1%

BRAM tiles

—

135

1%

LUTRAM

—

—

1%

DSP

—

240

0%

I/O

—

—

20%

BUFG

—

32

6%

Item Value

Estimated total power

0.117 W (Vivado post-route)

8.3. Functional latency (cocotb, itch_hw_core only)

Source: sim/results/latency_summary.json (regenerated by sim/cocotb/run_tests.cmd).

Path Budget Cycles ns @ 100 MHz

Last ITCH byte → record_valid

≤ 5

3

30

record_valid → bbo_valid (Add)

≤ 6

6

60

record_valid → bbo_valid (Exec/Cancel at BBO)

—

≤ 512 (rescan)

≤ 5,120

On hardware the target remains under 10 cycles on the Add path for parse + BBO combined — sim and silicon to be reconciled after bench traffic.

8.4. How to refresh

Vivado (timing and utilization)
vivado -mode batch -source vivado/build.tcl

Copy from itch-hw.runs/impl_1/ (*_timing_summary_routed.rpt, *_utilization_placed.rpt, *_power_routed.rpt) into the tables above and docs/metrics.md badges.

Simulation (latency)
cd sim/cocotb
run_tests.cmd

Or on Linux / GNU make:

cd sim/cocotb && pip install -r ../requirements.txt && make
Bench LED pulse widths are human-visible stretches, not cycle counts. Only cocotb + latency_summary.json may update the latency table above.

9. Known Limitations

Honest boundaries: what the system is, and what it is not. This chapter overrides any optimistic reading of earlier chapters.

9.1. What is real today

  • RMII ingress with CDC + minimal IPv4/UDP filter (lab port 50000).

  • MoldUDP64 length-prefix unwrap to raw ITCH bytes.

  • Streaming 8-bit FSM for Add / Execute / Cancel → itch_record_t.

  • Dual 512-slot BRAM book with incremental Add BBO and ≤512-cycle rescan on Exec/Cancel at the best.

  • BBO outputs (bid/ask price + shares, bbo_valid) with parse/book error flags.

  • LED + 7-seg proof on Nexys A7-100T (USE_ETH=1 bitstream).

  • cocotb gates vs Python golden model, including 10M-message Verilator stress entry point; post-route timing closed at 100 MHz.

9.2. What is explicitly not here

  • Production MoldUDP64 multicast: lab broadcast replay only.

  • ARP, IP TX, or UDP TX — the board never replies; use broadcast.

  • Multi-symbol books: single symbol in v1.

  • Message types beyond A / E / X (no crosses, halts, or admin).

  • Full 64-bit order identity: slots key on order_ref[8:0], so upper-bit collisions alias — size test traffic accordingly.

  • Exchange sequencing, matching, or order-entry back out.

9.3. Limits to design around

  • A byte is parsed if and only if the UDP dest port matches and the Mold length framing is intact; anything else is dropped to StIdle.

  • Corruption is a loud error (parse_error / book_error), never a degraded read.

  • Published numbers are measured in this tree (WNS +1.552 ns, ~2% LUT, 3 cy parse + 6 cy BBO on Add). Unmeasured values are TBD (unmeasured).

  • Bench LED timing ≠ sim cycle timing; reconcile Add-path <10-cycle claims after bench traffic capture.

10. Lab Journal

Dated bench notes. log/ holds the full text; this chapter summarizes each entry and links the source so the manual never forks the journal.

10.1. 2026-08-02 — Successful Synthesis, Implementation, Bitstream

First clean end-to-end Vivado run for the live UDP path (not just the cocotb core) after several RTL iterations on ingress, Mold unwrap, parser, and book.

  • synth_1 + impl_1 green; write_bitstream produced itch-hw.runs/impl_1/nexys_a7_100t_top.bit.

  • Post-route: WNS +1.552 ns, WHS +0.033 ns, 0 failed routes, ~0.117 W, LUT 2% / FF 1% / BRAM 1%.

  • Hierarchy confirmed: gen_eth.u_eth → gen_eth.u_mold → u_core → u_display; package pins match the Nexys ballout.

  • Hardware Manager sees xc7a100t_0, ready to program.

Design runs complete
Figure 7. Design Runs — synthesis and bitstream complete

Full text with all four screenshots: log/2026-08-02 - Successful Synthesis - Implementation - Bitstream.md.

Public companion on the engineering log: Successful Synthesis - Implementation - Bitstream — first clean Vivado build for the Nexys A7 ITCH pipeline with USE_ETH=1.

10.2. 2026-08-02 — Ethernet Cable

Market data must flow continuously so the FPGA can act — the full data in → decision → data out path matters, without shortcuts that skip real ingress.

  • Ordered Cat5e/Cat6 for PC ↔ Nexys (no switch; LAN8720 auto-MDIX); cable arrived and is ready for testing.

  • Goal: program USE_ETH=1, confirm LED15, inject Mold/ITCH traffic with tools/send_itch_udp.py per docs/board_eth_setup.md.

Full text: log/2026-08-02 - Ethernet Cable.md.

Public companion on the engineering log: ITCH Ethernet Lab Bring-Up — preparing Nexys A7 Ethernet ingress for end-to-end Mold/ITCH UDP testing.

Related bench reading from the sibling stack build: Understanding the UDP Stack and Connecting to ITCH — why market-data pipelines need UDP over TCP, from ITCH ingestion on the FPGA to the custom 100 Mbps stack (github.com/tmarhguy/udp-stack).

New entries go in log/YYYY-MM-DD - Topic.md and get a subsection here. Link the file; do not paste bench speculation as fact.

11. About This Manual

Meta information about this manual — deliberately placed after the work itself.

This manual is the running engineering reference for the project — message formats, pipeline decisions, and measured numbers as they land. It is the companion to the concise, GitHub-facing README.md:

  • README.md — project identity, status, and quick start.

  • docs/*.md — normative companions (architecture.md, metrics.md, board_eth_setup.md).

  • log/ — dated lab journal (design notes, bring-up narrative).

  • docs/ (this manual) — architecture, design, verification, and results in engineering-manual style.

11.1. Conventions

Conventions used throughout:

  • monospace marks commands, file paths, identifiers, and literals.

  • Unmeasured values are written as TBD (unmeasured) — never silently estimated.

  • Clocks are 100 MHz system + 50 MHz eth_refclk unless noted.

  • Characterization is post-route (impl_1) unless a subsection states otherwise.

  • Normative detail lives alongside this manual as Markdown (docs/*.md, log/) and is linked, not duplicated.

  • Figures in docs/images/ are staged copies; sources of truth stay in media/ (see scripts/build-docs.sh).

New here? Start with Introduction for scope and reading order, then Architecture for the system overview.

12. Authors

The manual, RTL, verification, and lab journal are produced by the engineer behind the design.

12.1. Tyrone Marhguy

Computer Engineering '28, University of Pennsylvania. Independent FPGA work: ITCH parsing, order-book logic, and a public build log. Designer of the Tomato 32-bit computer; contributor to open-source EDA (LibreLane, Verilator, OpenROAD, OpenFPGA).

Questions or collabs — reach out. Build log and projects at tmarhguy.com.