Gap 7 MMCM jitter cleaner + CIC comb CREG pipeline + XDC clock-name fix

MMCM (Gap 7):
- Add adc_clk_mmcm.v: MMCME2_ADV wrapper (VCO=800MHz, CLKOUT0=400MHz)
- Modify ad9484_interface_400m.v: replace BUFG with MMCM path, gate reset on mmcm_locked
- Add adc_clk_mmcm.xdc: CDC false paths for clk_mmcm_out0 <-> clk_100m

XDC Fix (Build 19 WNS=-0.011 root cause):
- Remove conflicting create_generated_clock -name clk_400m_mmcm
- Replace all clk_400m_mmcm references with Vivado auto-generated clk_mmcm_out0
- CDC false paths now correctly apply to actual timing paths

CIC CREG Pipeline (Build 18 critical path fix):
- Explicit DSP48E1 for comb[0] with CREG=1/AREG=1/BREG=1/PREG=1
- Absorbs integrator_sampled_comb fabric FDRE into DSP48 C-port register
- Eliminates 0.643ns fabric->DSP routing delay (Build 18 tightest path)
- +1 cycle comb latency via data_valid_comb_0_out pipeline
- Move shared register declarations above ifndef SIMULATION (iverilog fix)
- Update golden data for +1 cycle CIC pipeline shift

Build scripts: build19_mmcm.tcl, build20_mmcm_creg.tcl
Regression: 18/18 FPGA pass, 20/20 MCU pass
Build 20 launched on remote Vivado (pending results)
This commit is contained in:
Jason committed 2026-03-19 22:59:46 +02:00
1 parent f3bbf77ca1
commit c6103b37de
10 files changed
+9038 -7438

No files matched your search

@@ -0,0 +1,164 @@
# ADC Clock MMCM Integration Guide
## Overview
`adc_clk_mmcm.v` is a drop-in MMCME2_ADV wrapper that replaces the direct BUFG
on the 400 MHz ADC data clock output with a jitter-cleaning PLL loop.
### Current clock path (Build 18)
```
adc_dco_p/n → IBUFDS → BUFIO (drives IDDR only — near-zero delay)
→ BUFG (drives all fabric 400 MHz logic)
```
### New clock path (with MMCM)
```
adc_dco_p/n → IBUFDS → BUFIO (unchanged — drives IDDR only)
→ MMCME2 CLKIN1 → CLKOUT0 → BUFG (fabric 400 MHz)
→ CLKFBOUT → BUFG → CLKFBIN (feedback)
```
## Expected Timing Improvement
| Parameter | Before (Build 18) | After (estimated) |
|-----------|-------------------|-------------------|
| Input jitter | 50 ps | 50 ps (unchanged) |
| Output jitter (MMCM) | N/A | ~20-30 ps |
| Clock uncertainty | 43 ps | ~25 ps |
| WNS (setup, 400 MHz) | +0.062 ns | ~+0.08 to +0.10 ns |
| WHS (hold, 100 MHz) | +0.059 ns | unchanged |
The improvement comes from reduced clock uncertainty in the Vivado timing
analysis. The MMCM's PLL loop attenuates the input jitter, so Vivado deducts
less uncertainty from the timing budget.
## MMCM Configuration
```
CLKIN1 = 400 MHz (2.500 ns)
DIVCLK_DIVIDE = 1
CLKFBOUT_MULT_F = 2.0 → VCO = 800 MHz
CLKOUT0_DIVIDE_F = 2.0 → Output = 400 MHz
BANDWIDTH = HIGH (maximum jitter filtering)
```
VCO at 800 MHz is well within the Artix-7 -2 speed grade range (600–1200 MHz).
## Resource Cost
| Resource | Count | Notes |
|----------|-------|-------|
| MMCME2_ADV | 1 | Was 0/10, now 1/10 |
| BUFG | +1 (feedback) | Was 4/32, now 5/32 |
| FFs | 0 | No additional fabric registers |
## Integration Steps
### Step 1: Modify `ad9484_interface_400m.v`
Replace the BUFG instantiation with `adc_clk_mmcm`:
```verilog
// REMOVE these lines (65-69):
// BUFG bufg_dco (
// .I(adc_dco),
// .O(adc_dco_buffered)
// );
// assign adc_dco_bufg = adc_dco_buffered;
// ADD this instead:
wire mmcm_locked;
wire adc_dco_mmcm;
adc_clk_mmcm mmcm_inst (
.clk_in (adc_dco), // From IBUFDS output
.reset_n (reset_n),
.clk_400m_out (adc_dco_mmcm), // Jitter-cleaned 400 MHz
.mmcm_locked (mmcm_locked)
);
// Use MMCM output for all fabric logic
wire adc_dco_buffered = adc_dco_mmcm;
assign adc_dco_bufg = adc_dco_buffered;
```
### Step 2: Gate reset on MMCM lock (recommended)
In `ad9484_interface_400m.v`, modify the reset synchronizer to require MMCM lock:
```verilog
// Change the reset synchronizer input from:
// always @(posedge adc_dco_buffered or negedge reset_n) begin
// if (!reset_n)
// reset_sync_400m <= 2'b00;
// else
// reset_sync_400m <= {reset_sync_400m[0], 1'b1};
// end
// To:
wire reset_n_gated = reset_n & mmcm_locked;
always @(posedge adc_dco_buffered or negedge reset_n_gated) begin
if (!reset_n_gated)
reset_sync_400m <= 2'b00;
else
reset_sync_400m <= {reset_sync_400m[0], 1'b1};
end
```
This ensures the 400 MHz domain stays in reset until the MMCM has locked and
the clock is stable. Without this, the first ~10 µs after power-up (before
MMCM lock) could produce glitchy clock edges.
### Step 3: Add constraint file
Add `constraints/adc_clk_mmcm.xdc` to the Vivado project. Uncomment the
constraints and adjust hierarchy paths based on your actual instantiation.
Key constraints to uncomment:
1. `create_generated_clock` (or verify Vivado auto-creates it)
2. `set_max_delay` between `adc_dco_p` and `clk_400m_mmcm`
3. `set_false_path` between `clk_400m_mmcm` and other clock domains
4. `set_false_path` on `LOCKED` output
### Step 4: Add to build script
In the Tcl build script, add the new source file:
```tcl
read_verilog adc_clk_mmcm.v
read_xdc constraints/adc_clk_mmcm.xdc
```
### Step 5: Verify
After building:
1. Check `report_clocks` — should show the new MMCM-derived clock
2. Check `report_clock_interaction` — verify no unexpected crossings
3. Check WNS on the `adc_dco_p` / MMCM clock group — should improve
4. Check MMCM locked in ILA during bring-up
## BUFIO Compatibility Note
The BUFIO path for IDDR capture is **not affected** by this change. BUFIO
drives only IOB primitives (IDDR) and cannot go through an MMCM. The BUFIO
continues to use the raw IBUFDS output with near-zero insertion delay, which
is correct for source-synchronous DDR capture.
The re-registration from BUFIO domain to BUFG domain (lines 105-108 of
`ad9484_interface_400m.v`) now crosses from the raw `adc_dco_p` clock to the
MMCM-derived clock. Since both are frequency-matched and the MMCM is locked
to the input, this is a safe single-register transfer. The `set_max_delay`
constraint in the XDC ensures Vivado verifies this.
## Simulation
Under `SIMULATION` define (iverilog), the module passes the clock straight
through with a simulated lock delay of ~4096 cycles. This matches the
current testbench behavior — no changes to any testbenches needed.
## Rollback
To revert: simply restore the original BUFG in `ad9484_interface_400m.v` and
remove `adc_clk_mmcm.v` + `constraints/adc_clk_mmcm.xdc` from the project.
No other files are affected.