Interview Question · Code Reading
The Toggle Pulse Synchronizer and Its Rate Limit
The Question
The interviewer asks
What does this circuit do, and what happens if two source pulses come in back-to-back source cycles?
module pulse_sync (input logic clk_s, clk_d, rst_n, pulse_s, output logic pulse_d);
logic tog, d1, d2, d3;
always_ff @(posedge clk_s or negedge rst_n) // each source pulse flips a level
if (!rst_n) tog <= 0; else if (pulse_s) tog <= ~tog;
always_ff @(posedge clk_d or negedge rst_n) // two synchronizer flops, then one for the edge
if (!rst_n) {d3, d2, d1} <= 0; else {d3, d2, d1} <= {d2, d1, tog};
assign pulse_d = d2 ^ d3; // one destination pulse per change
endmodule
You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Each one-cycle source pulse flips tog, a level that stays put until the next pulse. Two destination flops synchronize the level, and the XOR of the last two flops gives one destination pulse per change. Back-to-back pulses flip tog twice before the destination samples it. Then the destination sees no change and both pulses vanish. Pulses must be spaced by a few destination periods.
- Flip
A pulse flips
level. The new level stays until the next pulse, so the slow clock has many edges to catch it. - Synchronize
The level crosses through two flops, like any slow bit.
- Regenerate
In the cycle where s2 differs from last cycle's s2,
pulse_sis 1. A rise and a fall both count, because both are pulses.
Read the diagram as text
- pulse_f: one clk_f cycle
- level: flips once per pulse
- s1, s2: two-flop synchronizer
- s2_q: last cycle's s2
- pulse_s: s2 ^ s2_q
- pulse_f → level: flip
- level → s1, s2: crosses
- s1, s2 → s2_q
- s1, s2 → pulse_s
- s2_q → pulse_s
Two lines change from the lab design: level <= level ^ pulse_f; and pulse_s = s2 ^ s2_q;. Synthesis on this flow: 6 cells, 4 flops, 1 level of logic.
- Cycle 2
Edge 5: the first pulse has flipped
levelto 1, and it stays there. - Cycle 3
Edge 6: s2 has the new level, and
pulse_sfires once. - Cycle 6
Edge 9: the second pulse flipped
levelback to 0. The fall makes a pulse too.
Measured on the lab bench. One regenerated pulse per sent pulse, two or three clk cycles after the flip.
A 4 ns source and a 10 ns destination; three pulses ten source cycles apart.
sent=3 seen=3 PASS: every pulse, spaced well apart, arrived onceSelf-Check
Tick each key point you covered in your answer.
What Interviewers Listen For (Junior)
A good junior answer reads the toggle flop, the two synchronizer flops and the XOR. It explains why a level survives the crossing when a one-cycle pulse would not.
What Interviewers Listen For (Mid-Level)
A good mid-level answer states the spacing rule in destination clock periods. If the source can send bursts, it adds an assertion or a handshake.
Cross-Questions
Where the interviewer goes next. Open a node to practise that follow-up.
WhyWhat IfProve ItBreak ItCompare
- The Toggle Pulse Synchronizer and Its Rate Limit
-
WhyA Fast Pulse into a Slow Clock DomainL1 JuniorL2 Mid-Level
Asked if they suggest synchronizing the pulse directly
What if the source clock is faster than the destination clock and the signal is a one-cycle pulse?
log Illustrative event excerpt (ns) 0: destination rising edge; source pulse=0 4: source pulse rises 8: source pulse falls 10: destination rising edge; source pulse=02:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The pulse can rise and fall between two destination edges and never be sampled. One fix is to hold the signal for at least about 1.5 destination periods. Another is to turn the pulse into a toggle, synchronize the level, and turn each change back into a pulse. For events that must not be lost or merged, use a handshake.
One-Cycle Pulses Through a Two-Flop SynchronizerEdges 3 to 13 of a simulator bench, sampled on clk (10 ns). The sender's clock has a 3 ns period, so each pulse on levellasts 3 ns.All cycles- Cycle 1
Edge 4: the first pulse has come and gone between two edges. No edge of clk ever saw
levelat 1. - Cycle 5
Edge 8: the second pulse is lost the same way.
- Cycle 9
Edge 12: edge 11 fell inside the third pulse, so
pulse_sfires once. The other pulses of the run are all lost.
Samples of
leveltaken 1 ns after each edge never catch a pulse here. The run ends withsent=7 seen=1.Self-Check
Tick each key point you covered in your answer.
Missed Corner
"A two-flop synchronizer carries any single-bit signal."
It carries a level that stays stable long enough. A pulse shorter than a destination period can be missed completely, as the twin shows.
Run It
A one-cycle pulse from a 250 MHz domain into a 100 MHz domain, through two flops.
RUNIcarus Verilog · in your browserExpected:source sent 1 pulse, destination counted 0FAIL: the pulse fell between two destination edges and was lostSee the Fix
module tb; logic sclk = 0, dclk = 0, tog = 0, s1 = 0, s2 = 0, s3 = 0; int sent = 0, seen = 0; always #2 sclk = ~sclk; // fast source: edges at 2, 6, 10, ... always #5 dclk = ~dclk; // slow destination: edges at 5, 15, 25, ... // The fix: turn the pulse into a level change, synchronize the level, and // turn each change back into one destination pulse (s2 ^ s3). always @(posedge dclk) begin s1 <= tog; s2 <= s1; s3 <= s2; end always @(posedge dclk) if (s2 ^ s3) seen++; initial begin @(posedge sclk); @(posedge sclk); tog <= ~tog; sent++; #60; $display("source sent %0d pulse, destination counted %0d", sent, seen); if (seen != sent) $display("FAIL: the pulse fell between two destination edges and was lost"); else $display("PASS: the level change crossed and became one pulse"); $finish; end endmodulePrints:
source sent 1 pulse, destination counted 1PASS: the level change crossed and became one pulse - Cycle 1
-
Prove ItSolve R6.3.1: One Event, One ByteSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
CompareOpen-Loop Toggle vs a Closed-Loop Handshake for EventsL2 Mid-Level
Compare the toggle synchronizer with a handshake for carrying events.
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
The toggle is open loop. The source never learns whether the event arrived, so a design rule must keep events far enough apart. A handshake is closed loop. The source waits for the acknowledge, so it cannot send too fast, but each event costs a round trip. Choose the toggle when the spacing is guaranteed, and the handshake when it is not.
One-Cycle Pulses Through a Two-Flop SynchronizerEdges 3 to 13 of the lab bench, sampled on clk (10 ns). The sender's clock clk_f has a 3 ns period, so each pulse on levellasts 3 ns.All cycles- Cycle 1
Edge 4: the first pulse has come and gone between two edges. No edge of clk ever saw
levelat 1. - Cycle 5
Edge 8: the second pulse is lost the same way.
- Cycle 9
Edge 12: edge 11 fell inside the third pulse, so
pulse_sfires once. The other pulses of the run are all lost.
Measured on the lab bench. In these edges, the samples of
leveltaken 1 ns after each edge never catch a pulse. The final line readssent=7 seen=1.Self-Check
Tick each key point you covered in your answer.
Missed Corner
"Open loop is fine because the source is slow on average."
Average rate does not matter; the two closest events do. One burst is enough to lose pulses.
Source Measured: the twin on design.cdc.pulse-synchronizer, Icarus Verilog 12
- Cycle 1
-
Prove ItSolve R6.3.1: One Event, One ByteSimulator-graded
Show it, don't just say it: this Silicon Lab problem is graded by the simulator.
-
Break ItTaking the Pulse from the First Synchronizer FlopL2 Mid-Level
Break it: a reviewer sees
assign pulse_d = d1 ^ d2;. What is wrong?systemverilog always_ff @(posedge clk_d) {d2, d1} <= {d1, tog}; assign pulse_d = d1 ^ d2; // uses the first flop2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
d1is the flop that samples the asynchronous toggle, so it is the one that can go metastable. Feeding it to the XOR lets an unsettled value reach logic. Take the edge from two flops after the synchronizer, such asd2 ^ d3.Self-Check
Tick each key point you covered in your answer.
Misconception
"It saves a cycle of latency, and the XOR is only one gate."
Any logic on the first flop's output removes the settling time the second flop provides. One gate is enough to spread a metastable value.
Source Mehta, ASIC/SoC Functional Design Verification (2018) ch. 8.3.1 Two-flop synchronizer (no logic between the flops)
-
CompareBreaking a Two-Flop Synchronizer Without Touching Its FlopsL2 Mid-Level
How can a two-flop synchronizer fail even though its two flops are exactly right?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Combinational logic in front of the first flop can glitch, and the destination may catch the glitch. Synchronizing one signal in two places lets the two copies resolve differently. Signals synchronized separately and then combined again lose any timing relationship between them. Logic between the two flops eats the settling time.
One Synchronizer per BitArrows show the bit wires from the sender's flops to the receiver. Each synchronizer decides alone in which clk cycle its bit changes. Illustrative sequence- Three bits make edge 11
Edge 11 of clk is at 115 ns. Bits 0, 1 and 3 have their new values by then.
- Bit 2 misses it
Bit 2 arrives at 115.55 ns, after the edge, so its synchronizer still holds the old 1.
- A torn value
The receiver sees new 1, 0, 0 for bits 3, 1, 0 and old 1 for bit 2: 1100. The count never held 12 here.
Read the diagram as text
- count_tx: 0111 to 1000 at 112.75 ns
- bit 0 sync: arrives 113.15 ns
- bit 1 sync: arrives 113.95 ns
- bit 3 sync: arrives 114.75 ns
- bit 2 sync: arrives 115.55 ns
- count_q: reads 1100 at edge 12
- count_tx → bit 0 sync: 0.4 ns
- count_tx → bit 1 sync: 1.2 ns
- count_tx → bit 3 sync: 2.0 ns
- count_tx → bit 2 sync: 2.8 ns
- bit 0 sync → count_q
- bit 1 sync → count_q
- bit 3 sync → count_q
- bit 2 sync → count_q
Times from a simulator bench. With metastability added, this can happen even with perfectly matched wires, because each first flop settles on its own.
Self-Check
Tick each key point you covered in your answer.
Missed Corner
"Synchronize the signal once per module that needs it."
Two synchronizers on one signal can resolve on different cycles. So the two modules disagree for a cycle.
Source Golson, Synchronization and Metastability (SNUG 2014) §2.3 (Figure 9); Mehta, ASIC/SoC Functional Design Verification ch. 8.5 (PDF p186, re-convergence)
- Three bits make edge 11
-
What IfHow Close Can Two Events BeL2 Mid-LevelL3 Senior
What if the spec allows events every few source cycles? How far apart must they be for the toggle synchronizer?
2:30You have two and a half minutes. Speak or type, then press Get Feedback under your answer. No credits needed.
Speech-to-text runs in your browser. Chrome and Edge may send audio to their own speech service.
You can edit your answer before you send it. Feedback uses AI and checks your answer only against our written answer. No credits are used and your answer is not saved.
Reveal the Model Answer
Each toggle level must last long enough for the destination to sample it reliably. That is about 1.5 destination periods, so three destination edges see it. Add the synchronizer depth and convert to source cycles at the slowest destination clock. Check the rule with an assertion on the source side.
Self-Check
Tick each key point you covered in your answer.
Spec Misquote
"One destination period apart is enough."
A level that lasts exactly one period can fall just between two edges after skew. The rule asks for about 1.5 periods.
Source Cummings, Clock Domain Crossing (CDC) Design & Verification Techniques Using SystemVerilog (SNUG Boston 2008) §4.1.1
What People Get Wrong
Common wrong answers and why they fail. Run It shows the wrong belief failing on a real simulator.
Missed Corner
"A toggle synchronizer never loses a pulse."
It never loses an isolated pulse. Two pulses inside one destination period flip the level back before it is sampled. The twin sends five and sees three.
Run It
The same synchronizer, with two pulses in back-to-back source cycles first.
sent=5 seen=3 FAIL: two pulses one source cycle apart flipped the toggle twice between destination edges, so both vanishedSee the Fix
module pulse_sync (input logic clk_s, clk_d, rst_n, pulse_s, output logic pulse_d);
logic tog, d1, d2, d3;
always_ff @(posedge clk_s or negedge rst_n) // each source pulse flips a level
if (!rst_n) tog <= 0; else if (pulse_s) tog <= ~tog;
always_ff @(posedge clk_d or negedge rst_n) // two synchronizer flops, then one for the edge
if (!rst_n) {d3, d2, d1} <= 0; else {d3, d2, d1} <= {d2, d1, tog};
assign pulse_d = d2 ^ d3; // one destination pulse per change
endmodule
module tb;
logic clk_s = 0, clk_d = 0, rst_n = 0, pulse_s = 0, pulse_d;
int sent = 0, seen = 0;
always #2 clk_s = ~clk_s; // 4 ns source clock
always #5 clk_d = ~clk_d; // 10 ns destination clock
pulse_sync u (.*);
always @(posedge clk_s) if (pulse_s) sent++;
always @(posedge clk_d) if (pulse_d) seen++;
task automatic pulse(input int cycles); // high for this many source cycles
pulse_s = 1; repeat (cycles) @(negedge clk_s); pulse_s = 0;
endtask
initial begin
#11 rst_n = 1; // both clocks have reset the flops
repeat (4) @(negedge clk_s); // t = 24
repeat (6) @(negedge clk_s); pulse(1); // then pulses ten source cycles apart
repeat (9) @(negedge clk_s); pulse(1);
repeat (9) @(negedge clk_s); pulse(1);
repeat (20) @(negedge clk_s);
$display("sent=%0d seen=%0d", sent, seen);
if (seen == sent) $display("PASS: every pulse, spaced well apart, arrived once");
$finish;
end
endmodule
Prints: PASS: every pulse, spaced well apart, arrived once
Misconception
"Just synchronize the pulse itself through two flops."
A pulse shorter than a destination period can fall between two edges and never be sampled. The toggle turns it into a level that waits.
Source Mehta, ASIC/SoC Functional Design Verification (2018) ch. 8.3.3 Synchronizing fast-clock into slow-clock domains