This example replays the report excerpt above in miniature: a start pulse and its mode bit change together in the source domain. The bad path synchronises each through its own chain, with one extra destination flop on the mode chain standing in for one cycle of skew between the paths. The good path synchronises only the start pulse and captures the held-stable mode with the recovered pulse (qualified capture). One testbench runs both and checks every transfer.
`timescale 1ns/1ps
// BAD path: start and mode each cross through their own chain. The mode chain
// has one extra destination flop standing in for one cycle of skew between
// the two synchroniser paths (the same deterministic model as the
// reconvergence-glitch waveform). The checker samples mode_got with the
// recovered start pulse.
module reconv_bad (
input logic clk_d, rst_n, start_s, mode_s,
output logic start_pulse, mode_got
);
logic a1, a2, a2_d; // start chain: two flops
logic m1, m2, m3; // mode chain: three flops (the skew model)
always_ff @(posedge clk_d or negedge rst_n)
if (!rst_n) begin a1 <= 0; a2 <= 0; a2_d <= 0; m1 <= 0; m2 <= 0; m3 <= 0; end
else begin
a1 <= start_s; a2 <= a1; a2_d <= a2;
m1 <= mode_s; m2 <= m1; m3 <= m2;
end
assign start_pulse = a2 & ~a2_d;
assign mode_got = m3;
endmodule
// GOOD path: only the start pulse crosses. The mode is held stable by the
// source around every pulse, so sampling it directly with the recovered pulse
// is sound (the qualified-capture obligation, proven by the hold times in the
// stimulus below, not assumed).
module reconv_good (
input logic clk_d, rst_n, start_s, mode_s,
output logic start_pulse, mode_got
);
logic a1, a2, a2_d, mode_q;
always_ff @(posedge clk_d or negedge rst_n)
if (!rst_n) begin a1 <= 0; a2 <= 0; a2_d <= 0; mode_q <= 0; end
else begin
a1 <= start_s; a2 <= a1; a2_d <= a2;
if (a2 & ~a2_d) mode_q <= mode_s;
end
assign start_pulse = a2 & ~a2_d;
assign mode_got = mode_q;
endmodule
Mode and start change in the same source cycle, like real related logic, and the modes strictly alternate so every stale capture mismatches.
The start level holds four source cycles (40 ns) against the 20 ns destination clock, so each transfer yields exactly one pulse on each path; the pulse counts in the PASS line prove no transfer was lost or doubled.
The mode is stable for more than 100 ns around every pulse, which is the qualified-capture proof for the good path in miniature.
Each side is checked when its result is valid: the bad path exposes a wire, so the stale value is read with the pulse, while the good path exposes a register the pulse loads, so the clean value is read one cycle later after the capture edge.
No. The skew is structural (one flop of depth difference), so every transfer captures the previous mode no matter the spacing, as long as consecutive modes differ. Spacing fixes overlap, not skew.