Fast to Slow Clock Domain Crossing
When a short pulse originating in a fast clock domain needs to be sampled by a slow clock domain, the slow clock might completely miss the event if the pulse duration is shorter than the slow clock period. To prevent data loss, the pulse must be stretched into a sustained level signal within the fast domain. This level is then synchronized across the boundary. To ensure the stretched signal does not remain high indefinitely, a feedback mechanism is employed: the synchronized level is passed back to the fast domain. Once the fast domain detects this acknowledgment, it de-asserts the stretched signal.
module pulse_stretch_sync (
input wire fast_clk,
input wire slow_clk,
input wire rst_n,
input wire fast_pulse_in,
output wire slow_pulse_out,
output wire slow_level_out
);
reg stretch_req;
reg slow_sync_0, slow_sync_1, slow_sync_2;
reg fast_ack_0, fast_ack_1;
always @(posedge fast_clk or negedge rst_n) begin
if (!rst_n)
stretch_req <= 1'b0;
else if (fast_pulse_in)
stretch_req <= 1'b1;
else if (fast_ack_1)
stretch_req <= 1'b0;
end
always @(posedge slow_clk or negedge rst_n) begin
if (!rst_n) begin
slow_sync_0 <= 1'b0;
slow_sync_1 <= 1'b0;
slow_sync_2 <= 1'b0;
end else begin
slow_sync_0 <= stretch_req;
slow_sync_1 <= slow_sync_0;
slow_sync_2 <= slow_sync_1;
end
end
always @(posedge fast_clk or negedge rst_n) begin
if (!rst_n) begin
fast_ack_0 <= 1'b0;
fast_ack_1 <= 1'b0;
end else begin
fast_ack_0 <= slow_sync_1;
fast_ack_1 <= fast_ack_0;
end
end
assign slow_level_out = slow_sync_1;
assign slow_pulse_out = slow_sync_1 & ~slow_sync_2;
endmoduleSlow to Fast Clock Domain Crossing
Transferring a pulse from a slow clock domain to a fast clock domain guarantees that the fast clock will capture the event, as the pulse width naturally spans multiple fast clock cycles. However, metastability must still be mitigated. A standard two-stage synchronizer stabilizes the incoming signal, and edge detection logic converts the synchronized level back into a single-cycle pulse within the fast domain.
module slow_to_fast_edge_sync (
input wire fast_clk,
input wire rst_n,
input wire slow_signal_in,
output wire fast_pulse_out
);
reg sync_stage_0, sync_stage_1, sync_stage_2;
always @(posedge fast_clk or negedge rst_n) begin
if (!rst_n) begin
sync_stage_0 <= 1'b0;
sync_stage_1 <= 1'b0;
sync_stage_2 <= 1'b0;
end else begin
sync_stage_0 <= slow_signal_in;
sync_stage_1 <= sync_stage_0;
sync_stage_2 <= sync_stage_1;
end
end
assign fast_pulse_out = sync_stage_1 & ~sync_stage_2;
endmodule