Q004FreeSystemVerilog
Clock-Domain Crossing Strategies for ASIC Interviews
Question
Choose the correct clock-domain crossing (CDC) method for four signal types: a stable one-bit level, a short pulse, a held multi-bit setting, and a continuous stream. Then implement the one-bit level and pulse crossings. Raw reset drives the reset-release chains; their local synchronized outputs drive the corresponding functional reset pins. Reset cancels an event in flight. Physical integration must check synchronizer placement, reset pulse width, reset-tree recovery/removal and CDC timing; digital simulation does not establish those physical guarantees.
Implementation scaffold
module cdc_reset_release (
input logic clk,
input logic async_rst_n,
output logic local_rst_n
);
(* ASYNC_REG = "TRUE" *) logic [1:0] release_q;
always_ff @(posedge clk or negedge async_rst_n) begin : release_pipe
// TODO: Implement release_pipe using the supplied state and interface.
end
assign local_rst_n = release_q[1];
endmodule
module cdc_level_sync (
input logic dst_clk,
input logic async_rst_n,
input logic async_level,
output logic level_sync
);
logic dst_rst_n;
(* ASYNC_REG = "TRUE" *) logic [1:0] sync_q;
cdc_reset_release u_reset (.clk(dst_clk), .async_rst_n, .local_rst_n(dst_rst_n));
always_ff @(posedge dst_clk or negedge dst_rst_n) begin : level_pipe
// TODO: Implement level_pipe using the supplied state and interface.
end
assign level_sync = sync_q[1];
endmodule
module cdc_pulse_toggle (
input logic src_clk,
input logic src_pulse,
output logic src_ready,
input logic dst_clk,
input logic async_rst_n,
output logic dst_pulse
);
logic src_rst_n, dst_rst_n;
logic src_toggle;
(* ASYNC_REG = "TRUE" *) logic [1:0] dst_sync;
(* ASYNC_REG = "TRUE" *) logic [1:0] ack_sync;
logic dst_seen;
cdc_reset_release u_src_reset (
.clk(src_clk), .async_rst_n, .local_rst_n(src_rst_n)
);
cdc_reset_release u_dst_reset (
.clk(dst_clk), .async_rst_n, .local_rst_n(dst_rst_n)
);
always_ff @(posedge src_clk or negedge src_rst_n) begin : source_toggle_and_ack
// TODO: Implement source_toggle_and_ack using the supplied state and interface.
end
assign src_ready = src_rst_n && (ack_sync[1] == src_toggle);
always_ff @(posedge dst_clk or negedge dst_rst_n) begin : destination_event
// TODO: Implement destination_event using the supplied state and interface.
end
property p_source_ready;
// TODO: Check that each source pulse occurs only while locally ready.
endproperty
a_source_ready: assert property (p_source_ready);
endmodule
// TODO: Explain the level, event, held-word and streaming CDC choices, including coherency and physical/reset integration.
Requirements
- Use a two-flop destination synchronizer only for a stable single-bit level.
- Transfer a pulse with an acknowledged toggle; the source may issue a pulse only while src_ready is high.
- Use a bundled-data handshake for a held multi-bit value and an asynchronous FIFO for a stream.
- Use one shared asynchronous reset event, synchronize its release separately in each domain, and initialize both toggle endpoints to zero.
Short answer
Use a two-flop synchronizer for a stable one-bit level; convert a short pulse into a source toggle and acknowledge it before accepting another event. Hold multi-bit control data stable under a bundled-data handshake, and carry continuous traffic through an asynchronous FIFO. Each destination domain also needs its own reset-release synchronization.
Why this reasoning works
The architecture depends on what must survive the crossing. A single stable bit needs metastability containment, but a pulse may disappear between destination edges. Encoding the pulse as a persistent state change makes it observable; returning an acknowledgment supplies explicit backpressure and prevents a second event from overwriting the first.
Synchronizing every bit of a bus independently cannot guarantee a coherent word, because the bits can settle on different destination cycles. A handshake can transfer an infrequently changed bus while the source holds it, whereas an asynchronous FIFO provides storage and rate decoupling for a stream. Resetting toggle endpoints consistently avoids manufacturing a false event.
Interview takeaways
- Match CDC architecture to traffic
- Handshake narrow pulses
- Never bit-sync arbitrary buses
