# Packet TX FSM

## What You Will Learn

Real transmitters are control-heavy FSMs. `packet_tx_fsm` walks through header and payload beats, CRC check, and error/timeout paths using a two-always style: combinational `state_d` and registered `state_q`.

## Learning Objectives

- Map states `S_IDLE` through `S_ERROR` to protocol phases.
- Read Mealy-ish outputs (`busy`, `valid`) driven in combinational always.
- Understand `ready`/`timeout`/`crc_ok` as external handshake inputs.
- See how `start` clears done and re-arms idle.

## Theory

The combinational block computes next state and outputs from `state_q` and inputs. The clocked block updates `state_q <= state_d`. This separation is the classic two-process FSM template—easy for tools to extract state diagrams and for engineers to review default output assignments each state.

Timeout and CRC failure funnel to `S_ERROR`; success lands in `S_DONE` with `done` asserted until `start` deasserts. Such structure mirrors UART/Ethernet transmit controllers at a abstract level.

## When to use this pattern

Use multi-state transmit FSMs for serialized buses, packetized links, and memory-mapped burst writers with per-beat handshakes.

## Files

| File | Role |
|------|------|
| `tb/tb_packet_tx.v` | Testbench — **`tb_packet_tx`** |
| `rtl/packet_tx_fsm.v` | RTL / DUT — **`packet_tx_fsm`** |

## Practice Architecture

```mermaid
flowchart TB
  tb[tb_packet_tx] -->|start ready crc_ok timeout| dut[packet_tx_fsm]
  dut -->|busy valid done error| tb
```

## What to explore

- List default values assigned to outputs at the top of the combo always.
- Trace a happy path: `start` → header → pay0 → pay1 → CRC → done.
- Assert `timeout` in header state and find `error` behavior.
- Synthesize and open FSM diagram—compare to RTL `localparam` names.
- Add a `$display` on `state_q` changes in TB mentally—what prints?

## Summary

Packet TX FSM scales Starter's single always into the two-block pattern used in production controllers—defaults, explicit error state, and handshake inputs.

# Appendix (Code Review)

This section is an optional deep dive into the example source files. Line numbers refer to the copies in your workspace under `rtl/` and `tb/`.

## rtl/packet_tx_fsm.v

**Purpose:** Multi-state transmit controller (`packet_tx_fsm`).

Lines 6–84 — Module `packet_tx_fsm`

```verilog
module packet_tx_fsm (
  input wire clk,
  input wire rst_n,
  input wire start,
  input wire ready,
  input wire crc_ok,
  input wire timeout,
  output reg busy,
  output reg valid,
  output reg done,
  output reg error
);
    localparam [2:0] S_IDLE = 3'd0;
  localparam [2:0] S_HDR = 3'd1;
  localparam [2:0] S_PAY0 = 3'd2;
  localparam [2:0] S_PAY1 = 3'd3;
  localparam [2:0] S_CRC = 3'd4;
  localparam [2:0] S_DONE = 3'd5;
  localparam [2:0] S_ERROR = 3'd6;

  reg [2:0] state_q, state_d;

  always @(*) begin
    state_d = state_q;
    busy = 1'b0;
    valid = 1'b0;
    done = 1'b0;
    error = 1'b0;
    case (state_q)
      S_IDLE: begin
        if (start) state_d = S_HDR;
      end
      S_HDR: begin
        busy = 1'b1;
        valid = 1'b1;
        if (timeout) state_d = S_ERROR;
        else if (ready) state_d = S_PAY0;
      end
      S_PAY0: begin
        busy = 1'b1;
        valid = 1'b1;
        if (timeout) state_d = S_ERROR;
        else if (ready) state_d = S_PAY1;
      end
      S_PAY1: begin
        busy = 1'b1;
        valid = 1'b1;
        if (timeout) state_d = S_ERROR;
        else if (ready) state_d = S_CRC;
      end
      S_CRC: begin
        busy = 1'b1;
        valid = 1'b1;
        if (timeout) state_d = S_ERROR;
        else if (ready) begin
          if (crc_ok) state_d = S_DONE;
          else state_d = S_ERROR;
        end
      end
      S_DONE: begin
        done = 1'b1;
        if (!start) state_d = S_IDLE;
      end
      default: begin
        error = 1'b1;
        if (!start) state_d = S_IDLE;
      end
    endcase
  end

  always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
      state_q <= S_IDLE;
    end else begin
      state_q <= state_d;
    end
  end
endmodule
```

**Code review:** States: `S_IDLE`, `S_HDR`, `S_PAY0`, `S_PAY1`, `S_CRC`, `S_DONE`, `S_ERROR`. Combo always: Sets `state_d`, `busy`, `valid`, `done`, `error` per state. Seq always: `state_q <= state_d` on clock; async reset to idle. Handshakes: `ready` advances beats; `timeout` forces error; `crc_ok` gates done. Outputs cleared: Defaults at block top prevent latches.

## tb/tb_packet_tx.v

**Purpose:** Testbench `tb_packet_tx` — elaborates `DUT` and captures waves under `sim/`.

Lines 7–64 — Module `tb_packet_tx`

```verilog
`timescale 1ns/1ps
module tb_packet_tx;
  reg clk, rst_n, start, ready, crc_ok, timeout;
  wire busy, valid, done, error;

  packet_tx_fsm dut (
    .clk(clk),
    .rst_n(rst_n),
    .start(start),
    .ready(ready),
    .crc_ok(crc_ok),
    .timeout(timeout),
    .busy(busy),
    .valid(valid),
    .done(done),
    .error(error)
  );

  initial clk = 1'b0;
  always #5 clk = ~clk;

  initial begin
    $dumpfile("sim/dump.vcd");
    $dumpvars(0, tb_packet_tx);
    rst_n = 1'b0;
    start = 1'b0;
    ready = 1'b0;
    crc_ok = 1'b1;
    timeout = 1'b0;
    #20 rst_n = 1'b1;

    // Normal packet
    start = 1'b1;
    repeat (4) begin
      @(posedge clk);
      ready = 1'b1;
      @(posedge clk);
      ready = 1'b0;
    end
    @(posedge clk);
    start = 1'b0;
    repeat (2) @(posedge clk);

    // Error packet (bad crc)
    start = 1'b1;
    crc_ok = 1'b0;
    repeat (4) begin
      @(posedge clk);
      ready = 1'b1;
      @(posedge clk);
      ready = 1'b0;
    end
    @(posedge clk);
    start = 1'b0;
    crc_ok = 1'b1;
    repeat (3) @(posedge clk);
    $finish;
  end
endmodule
```

**Code review:** `tb_packet_tx` instantiates `DUT`. Look for `$dumpfile` / `$dumpvars` in an `initial` block and any loops or `$display` checks that report PASS/FAIL.

---

© 2026 RtlStudio. Licensed under [CC BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/). Commercial use and modifications by third parties are not permitted.

© 2026 RtlStudio. All rights reserved. RTL Studio is proprietary software.