A source toggles every 5 cycles of a 10 ns clock. A metastability model on the destination flop counts data changes inside the setup/hold window.
Four clock setups drive 20,000 source toggles each. The full models sit under Testbench below.
Clocks | Window hits in 20,000 source toggles |
|---|---|
Exact 10 ns / 7 ns, start offset 0.0 ns | 2,858 (every 7th toggle lands in the window) |
Exact 10 ns / 7 ns, start offset 0.4 ns | 0 (the same ratio never hits the window) |
10 ns / 7.13 ns | 1,265 (a finite set of sampled phases) |
10 ns / 7 ns with 0.6 ns jitter | 1,338 |
Read each row as every place a source toggle can land, measured from the last destination edge. The source toggles every 50 ns and 50 mod 7 = 1, so each toggle lands 1 ns later than the one before and the 7 phases repeat for ever.
Offset 0.0 ns: the phase 6.75 ns is 0.25 ns before the next edge, inside the 0.3 ns setup window. Every 7th toggle hits: 20,000 / 7 is about 2,858.
Offset 0.4 ns: every dot moves 0.4 ns left. The last one, at 6.35 ns, now misses the window, so none of the 20,000 toggles hits it.
Unrelated periods or jitter keep shifting the dots, so they eventually sweep through the window. That is why the last two rows of the table have hits.
Hostile timing has seven ingredients. Each one widens the set of phases the test reaches.
Unrelated periods: ratios that are not simple fractions, several per test.
Random start offsets: a fresh phase at the start of each test.
Jitter: random cycle-to-cycle variation on the clock edges.
Functional perturbation models with old/new or X outcomes in each synchroniser; separately characterize physical metastability reliability.
Random reset events during traffic.
Long runs: ten thousand toggles give hundreds of hits, while a hundred give almost none.
Hit coverage: count window hits per crossing and require a minimum.
All phase sweeps here are finite: 1 ps precision, finite duration and chosen clocks/jitter visit only discrete phases, never every real-valued phase or analog trajectory. Retain functional perturbation/X checks and protocol assertions alongside structural analysis, physical constraints and the reliability budget.
Inconclusive, not pass. The stimulus never exercised the dangerous case. Change the ratio, offset or jitter and run longer until the hit count is meaningful.
The metastability model, the stimulus and clock generators, and the testbench that counts the window hits.
`timescale 1ns/1ps
// Functional window exposure / old-new model only; TCQ is not a resolution distribution.
module meta_ff #(parameter real TCQ = 0.25, TSU = 0.3, THD = 0.15) (input logic clk, d, output logic q, output int events);
realtime t_d = -100.0, t_clk = -100.0;
initial begin q = 1'b0; events = 0; end
always @(d) begin
t_d = $realtime;
if ($realtime - t_clk < THD) begin events++; q <= #TCQ $urandom_range(0, 1); end
end
always @(posedge clk) begin
t_clk = $realtime;
if ($realtime - t_d < TSU) begin events++; q <= #TCQ $urandom_range(0, 1); end
else q <= #TCQ d;
end
endmodule
// A source that toggles every 5 clock cycles of its own clock
module toggler (input logic clk, output logic q);
int n = 0;
initial q = 0;
always @(posedge clk) begin n++; if (n % 5 == 0) q <= #0.25 ~q; end
endmodule
// Clock generator with a nominal period and optional cycle-to-cycle jitter (in ps units of 1 ps).
module clk_gen #(parameter real PERIOD = 10.0, parameter real JITTER = 0.0, parameter real START = 0.0) (output logic clk);
initial begin
clk = 0;
#(START); // start offset
forever begin
#((PERIOD / 2.0) + (JITTER == 0.0 ? 0.0 : ($urandom_range(0, 1000) / 1000.0 - 0.5) * JITTER));
clk = ~clk;
end
end
endmodule
Source test, run with Icarus Verilog 13.0 (2026-10-16): prints the four counts in the table, then PASS.