Crossing into a slower clock is the dangerous direction: the destination samples rarely, so short events fall between edges and disappear. Every fast-to-slow rule exists to make sure each event is still present when an edge finally comes.
Stretch every pulse past two destination periods before a plain synchroniser, measured against the slowest destination mode.
Prefer a toggle scheme where the ratio is wide or unknown: flip a bit per event, synchronise the level, and detect edges on the slow side.
Space events apart by more than the synchroniser latency plus the detector width, so pulses never merge.
Hold handshake data stable until the slow side's acknowledge returns, however long that takes.
The testbench below sends four fast events as toggles through a slow-domain synchroniser with an edge detector, and checks that four slow pulses arrive. Event spacing is 100 ns against a 30 ns slow clock, comfortably wider than the synchroniser latency.
`timescale 1ns/1ps
// Fast-to-slow event crossing: the event toggles a bit, the toggle crosses on a
// two-flop synchroniser, and an edge detector in the slow domain recovers one pulse.
module toggle_sync (input logic clk_s, input logic tog_f, output logic pulse_s);
logic q1 = 1'b0, q2 = 1'b0, q2_d = 1'b0;
always_ff @(posedge clk_s) begin
q1 <= tog_f; q2 <= q1; q2_d <= q2;
end
assign pulse_s = q2 ^ q2_d; // one slow cycle high per toggle
endmodule
Structural analysis recognises the toggle flop, the two synchroniser flops, and the edge detector as one scheme, and flags a bare pulse wire into a slow domain. The review checks stretch widths against the slowest mode and event spacing against the synchroniser latency.
The stretch or spacing against the new period: 100 ns spacing still clears the latency, but any width sized at two old periods must be rechecked against two new ones. The toggle scheme itself stays correct.
No. The second toggle can follow before the first has crossed and been detected, merging the two. The source must space events wider than the slow-side latency.