[KongchangAI]
· 3 min read· 1,859 words

AI-Assisted TCP Stack on FPGA: A Full Cursor Workflow Walkthrough

AI-Assisted TCP Stack on FPGA: A Full Cursor Workflow Walkthrough

Building a full TCP client on FPGA with AI assistance: state machines, timing fixes, and throughput validation.

This article covers an FPGA gigabit Ethernet upgrade that adds a TCP client and ICMP module to an existing UDP design, using a Hub dispatcher to route packets by protocol number. The TCP client implements three-way handshake, byte-based sequence numbers, sliding window, slow start, retransmission, and zero window probing. The standout element is the development workflow: state machine code, slides, and docs were all produced with Cursor, including a timing optimization skill for automatic violation resolution. Tests confirmed zero-loss loopback and Jumbo Frame support, while also revealing that ACK response latency — not raw bandwidth — is the real throughput bottleneck in practice.

From UDP to TCP: Adding a Transport Layer to an Open-Source Gigabit Ethernet Core

This project started with a relatively mature open-source gigabit Ethernet FPGA design. The original author had already implemented the IP layer and UDP in earlier versions, but a complete transport layer was missing. The upgrade goal was straightforward: build on the existing codebase to extract ICMP handling out of the IP core and add a full TCP client module.

What makes this noteworthy isn't TCP itself — it's a decades-old protocol — but the development approach. The author openly acknowledges that the core TCP client logic, state machine code, presentation slides, and teaching documentation were all produced with AI assistance, primarily Cursor. This reflects a shift happening in FPGA and hardware development: complex state machines that once required deep protocol expertise to write by hand can now be rapidly implemented through human-AI collaboration.

The entire project follows an LwIP-style open-source protocol stack philosophy, leveraging the raw IP layer interface to extend upward into independent ICMP and TCP modules. The author also built a dedicated "ICMP/TCP Hub" module that acts as a dispatcher above the IP layer — ICMP uses protocol number 1, TCP uses 6, and UDP uses 17, with the protocol number determining how data is routed.

TCP overview

Module Architecture: Hub Dispatch + Three Demo Projects

At a high level, the protocol stack is layered as: Ethernet → IPv4 → ICMP / TCP / UDP. Each protocol's responsibilities are clearly separated:

  • ICMP: Implements simple ping reply functionality — when a host pings the FPGA's IP address, it returns an Echo Reply. The author considered this sufficient without extensive performance testing.
  • TCP: Implements a single-connection client role that actively initiates the three-way handshake and supports in-order delivery, sliding window, and retransmission.
  • UDP: Reuses the port loopback functionality already present in the original design.

One design detail worth noting: TCP and UDP both use port 1234, but since the IP layer distinguishes them by protocol number, there is no conflict. This is a common point that beginners often overlook in protocol stack design.

On the demo side, the author built three example projects: a TCP loopback FIFO demo, a TCP throughput benchmark (continuously sending stress packets to a PC), and a top-level ICMP reply example. The benchmarking methodology mirrors that used in a previous 10GbE project.

Server IP address configuration

The Protocol Number is an 8-bit field in the IPv4 header, assigned by IANA to identify the upper-layer protocol so the IP layer can correctly deliver packets to the appropriate transport or control module. ICMP is 1, TCP is 6, UDP is 17. In an FPGA-based protocol stack, the "Hub" module is essentially a demultiplexer: it parses the Protocol field from each incoming IP packet header and routes the payload to the corresponding sub-module. This design keeps each protocol module independently developable and testable, and mirrors the "raw API + protocol callback" architecture found in software stacks like LwIP. Because dispatch happens at the IP layer rather than the port layer, TCP and UDP can share port 1234 without conflict — port numbers are meaningful only within their respective protocols.

Key Mechanisms in the TCP Client Implementation

The author's design notes outline several core aspects of the TCP client — precisely the parts that make TCP harder than UDP.

Sequence Numbers Increment in Bytes

TCP sequence number calculation is a classic misunderstanding trap. The author emphasizes: whether you send 4 bytes as a single segment or split them into four 1-byte segments, the sequence number advances by 4 — because sequence numbers are byte-based, not packet-based. If you send four segments of 4 bytes each, the sequence number advances by 16. This detail directly determines the correctness of ACK logic and retransmission behavior.

Three-Way Handshake and Connection Maintenance

Connection establishment follows the standard three-way handshake: after the IP core powers up, it sends SYN packets roughly every 1 millisecond (about 1 second on the host side in the demo); if the host port is open, it responds, and the IP core confirms, completing the connection. Teardown follows the four-way FIN handshake. The demo shows that after a connection drops, the IP core continues sending SYN packets at fixed intervals to attempt reconnection.

Flow Control and Reliable Transmission

On the K7 platform, a transmit buffer depth of 256 was configured to sustain throughput during benchmarking. The implementation covers slow start, advertised window, MSS option negotiation, timeout retransmission (SYN timeout: 1 second; data timeout: 200 milliseconds), retransmission from the unacknowledged pointer, fast retransmit triggered by three duplicate ACKs, zero window probing, and keepalive. This set of mechanisms covers the essential elements of TCP reliable delivery.

AI-generated state machine code

The author takes a pragmatic view of AI-generated code: the state machine came out somewhat verbose, with no deliberate optimization pass and no Chinese-language comments (since Chinese characters in code can cause encoding issues). He suggests that learners ask the AI to add comments for readability.

Slow Start is the initial phase of TCP congestion control: after a connection is established, the sender doesn't immediately transmit at full window size. Instead, the congestion window (cwnd) is initialized to 1 MSS and doubles with each ACK received until it reaches the slow start threshold (ssthresh), after which it enters the linear growth of the congestion avoidance phase. MSS (Maximum Segment Size) is negotiated during the TCP three-way handshake via the options field; it defines the maximum amount of data that can be sent in a single segment, typically derived from the link MTU minus IP and TCP header lengths. On standard Ethernet this is 1460 bytes; with Jumbo Frames (MTU up to 9000 bytes), MSS increases accordingly. Zero Window Probe addresses the deadlock that occurs when the receiver advertises a zero window: the sender periodically sends a 1-byte probe packet and waits for the receiver's window to reopen before resuming normal transmission. Together, these mechanisms form the foundation of TCP's reliable, efficient operation in lossy and variable-speed network environments.

Using Cursor for Hardware Development

The most practically valuable part of this project is the author's AI toolchain workflow. He uses Cursor, configured with several Skills and custom capability packs:

  • Timing Optimization Skill: When the design has timing violations, the AI identifies the offending paths, applies register retiming (pipelining) to the driving logic, and iterates until the design is violation-free.
  • Continuous Optimization Skill: A ready-made skill script sourced online.
  • Custom Capability Packs: Added by the author himself — documentation generation, reminder notes, and the ability to automatically produce teaching GPT prompts and design specification documents.

The author's advice for beginners is refreshingly practical: if you're not familiar with Cursor, start with tools like Doubao or DeepSeekAd, give the AI a brief overview of your project, and go deeper from there. The core skill isn't writing code — it's knowing how to direct the AI correctly. For example, if you want to build a TCP server, and you already understand the client and know how to describe your requirements, you can have the AI build out a complete testbench and simulation flow.

Timing Violation is a common issue after FPGA synthesis and place-and-route: it means the propagation delay on a data path exceeds the target clock period, preventing the flip-flop from sampling stable data at the clock edge. Pipeline Register Insertion (Register Retiming) is a standard remedy: extra register stages are inserted into overly long combinational logic paths, spreading the computation across multiple clock cycles to achieve a higher operating frequency, at the cost of added pipeline latency. Cursor's role here is to parse the timing reports from EDA tools (such as Vivado), locate the start and end points of the violation, automatically insert registers at the appropriate locations in the RTL, and re-trigger synthesis for verification. This "analyze report → modify code → verify" iterative loop is exactly the kind of scenario where AI-assisted hardware development can save significant time.

Measured Results: Throughput vs. ACK Latency Trade-offs

The demo session revealed a real engineering trade-off.

Loopback and Jumbo Frame Testing: After TCP connection establishment, the author sent 450 packets and received 450 — zero packet loss. UDP sent 1194 and received 1194, also with no loss. Both protocols supported Jumbo Frames (3695-byte payloads in the demo).

Throughput Results: When using a network debugging assistant for TCP speed testing, the throughput was only about 31 Mbps — because the debugging tool's ACK responses were too slow, dragging down overall performance. The author then had the AI write a lightweight test app that only sends ACKs without storing data, and throughput immediately climbed close to line rate.

This exposed the real bottleneck in TCP performance: the author observed that after the IP core sent 4 packets, the host side returned only one ACK (verified by the sequence number delta — 4 packets × their respective payloads equaling exactly 4896 bytes total). This "cumulative acknowledgment" reduces ACK frequency and minimizes stalls, but it also means that a real TCP server doing actual data processing cannot respond to ACKs this quickly, and throughput will drop noticeably. In other words, near-line-rate numbers in a pure benchmarking scenario don't translate to real-world application performance.

IP core sending data to host

TCP's Cumulative ACK mechanism allows the receiver to acknowledge multiple segments with a single ACK indicating "all bytes up to this point have been received," reducing ACK count and network overhead. However, this also means the sender's maximum in-flight unacknowledged data is bounded by the smaller of the receive window (rwnd) and the congestion window (cwnd). When the receiver has limited processing capacity and replies to ACKs slowly, the sender frequently hits the window ceiling and is forced to stall, causing a significant throughput drop. The author's observation of "4 packets sent per 1 ACK received" is a manifestation of the receiver (the network debugging assistant) using a Delayed ACK strategy — which typically waits up to 40–200 milliseconds or until a certain amount of data accumulates before sending an ACK, in order to reduce the frequency of small ACK packets. This helps in low-throughput or interactive scenarios but becomes a bottleneck in high-throughput benchmarking, which is why the author wrote a dedicated lightweight test program that only sends ACKs without processing data.

Takeaways for Hardware Developers

This project is modest in scale, but it demonstrates a path that is actively taking shape: in domains like FPGA development that have traditionally demanded deep expert knowledge, AI is becoming a genuinely useful collaborator. TCP state machines, timing closure, and documentation generation — all previously time-consuming tasks — can be significantly accelerated with AI assistance.

That said, the prerequisite remains the same: the developer must understand TCP fundamentals. AI can generate the code, but determining whether the sequence number logic is correct, understanding how ACK latency affects throughput, and identifying the root cause of a timing violation still require human expertise. As the author repeatedly emphasizes, if you want to truly learn TCP, you still need to read the protocol specification. AI lowers the barrier to implementation — not the barrier to understanding.

#FPGA TCP stack#Cursor AI hardware development#gigabit Ethernet FPGA#TCP client state machine#FPGA timing optimization#ICMP TCP Hub#AI-assisted RTL design
Share:

Related articles