Introduction
In digital circuits, clock-domain crossing is a broad topic that will be covered as a series. This article begins with handling single-bit signal synchronization across clock domains.
01. Pulse Loss When Crossing from Fast to Slow Clock
Handshake is an effective method for transferring single-bit signals across clock domains. When transferring from a faster clock domain to a slower one, a fast input pulse may disappear before the slower domain samples it, causing a missed-sample condition.
In the figure above, because of the frequency difference between the two clocks, a pulse from the fast domain disappears before the slow domain reaches its sampling edge, resulting in a missed sample.
To ensure reliable transfer, one approach is to widen the pulse and have the destination detect and acknowledge it back to the source after decoding the pulse, indicating receipt and completion. This process is called a handshake.
02. Basic Handshake Protocol
Below is a basic handshake circuit. src_clk and dst_clk are the source and destination clocks respectively; src_pulse is the input pulse; dst_pulse is the pulse synchronized to the destination. After the pulse is synchronized at the destination, the destination immediately sends an acknowledgement back to the source. Only after the acknowledgement is synchronized back to the source can the source issue the next pulse. The Verilog description of this circuit is shown below.
module Sync_Pulse (
input wire src_clk,
input wire dst_clk,
input wire rst_n,
input wire src_pulse,
output wire dst_pulse
);
reg req_state_dly1, req_state_dly2,dst_req_state,src_sync_req;
reg ack_state_dly1,src_sync_ack;
wire dst_sync_ack;
always @ (posedge src_clk or negedge rst_n)
begin
if (rst_n == 1'b0)
src_sync_req <= 1'b0;
else if (src_pulse)
src_sync_req <= 1'b1;
else if (src_sync_ack)
src_sync_req <= 1'b0;
else;
end
always @ (posedge dst_clk or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
req_state_dly1 <= 1'b0;
req_state_dly2 <= 1'b0;
dst_req_state <= 1'b0;
end else begin
req_state_dly1 <= src_sync_req;
req_state_dly2 <= req_state_dly1;
dst_req_state <= req_state_dly2;
end
end
assign dst_sync_ack = req_state_dly2;
always @ (posedge src_clk or negedge rst_n)
begin
if (rst_n == 1'b0)
begin
ack_state_dly1 <= 1'b0;
src_sync_ack <= 1'b0;
end
else
begin
ack_state_dly1 <= dst_sync_ack;
src_sync_ack <= ack_state_dly1;
end
end
assign dst_pulse = dst_req_state & (~req_state_dly2);
endmodule
03. Improved Handshake with Failure Indication
Although the previous circuit can synchronize pulses correctly under normal conditions, if a new input pulse arrives while a prior pulse is still being synchronized, the new pulse will be lost. Worse, the basic circuit provides no feedback indicating synchronization failure, which can mislead users into believing the pulse was synchronized. To address this, the circuit can be improved to assert a src_sync_fail signal when synchronization fails. The following Verilog implements this improvement. This code is sourced from the internet.
module handshake_pulse_sync
(
src_clk , //source clock
src_rst_n , //source clock reset (0: reset)
src_pulse , //source clock pulse in
src_sync_fail , //source clock sync state: 1 clock pulse if sync fail.
dst_clk , //destination clock
dst_rst_n , //destination clock reset (0:reset)
dst_pulse //destination pulse out
);
//PARA DECLARATION
//INPUT DECLARATION
input src_clk ; //source clock
input src_rst_n ; //source clock reset (0: reset)
input src_pulse ; //source clock pulse in
input dst_clk ; //destination clock
input dst_rst_n ; //destination clock reset (0:reset)
//OUTPUT DECLARATION
output src_sync_fail ; //source clock sync state: 1 clock pulse if sync fail.
output dst_pulse ; //destination pulse out
//INTER DECLARATION
wire dst_pulse ;
wire src_sync_idle ;
reg src_sync_fail ;
reg src_sync_req ;
reg src_sync_ack ;
reg ack_state_dly1 ;
reg ack_state_dly2 ;
reg req_state_dly1 ;
reg req_state_dly2 ;
reg dst_req_state ;
reg dst_sync_ack ;
//--========================MODULE SOURCE CODE==========================--
//--=========================================--
// DST Clock :
// 1. generate src_sync_fail;
// 2. generate sync req
// 3. sync dst_sync_ack
//--=========================================--
assign src_sync_idle = ~(src_sync_req | src_sync_ack );
//report an error if src_pulse when sync busy ;
always @(posedge src_clk or negedge src_rst_n)
begin
if(src_rst_n == 1'b0)
src_sync_fail <= 1'b0 ;
else if (src_pulse & (~src_sync_idle))
src_sync_fail <= 1'b1 ;
else
src_sync_fail <= 1'b0 ;
end
//set sync req if src_pulse when sync idle ;
always @(posedge src_clk or negedge src_rst_n)
begin
if(src_rst_n == 1'b0)
src_sync_req <= 1'b0 ;
else if (src_pulse & src_sync_idle)
src_sync_req <= 1'b1 ;
else if (src_sync_ack)
src_sync_req <= 1'b0 ;
end
always @(posedge src_clk or negedge src_rst_n)
begin
if(src_rst_n == 1'b0)
begin
ack_state_dly1 <= 1'b0 ;
ack_state_dly2 <= 1'b0 ;
src_sync_ack <= 1'b0 ;
end
else
begin
ack_state_dly1 <= dst_sync_ack ;
ack_state_dly2 <= ack_state_dly1 ;
src_sync_ack <= ack_state_dly2 ;
end
end
//--=========================================--
// DST Clock :
// 1. sync src sync req
// 2. generate dst pulse
// 3. generate sync ack
//--=========================================--
always @(posedge dst_clk or negedge dst_rst_n)
begin
if(dst_rst_n == 1'b0)
begin
req_state_dly1 <= 1'b0 ;
req_state_dly2 <= 1'b0 ;
dst_req_state <= 1'b0 ;
end
else
begin
req_state_dly1 <= src_sync_req ;
req_state_dly2 <= req_state_dly1 ;
dst_req_state <= req_state_dly2 ;
end
end
//Rising Edge of dst_state generate a dst_pulse;
assign dst_pulse = (~dst_req_state) & req_state_dly2 ;
//set sync ack when src_req = 1 , clear it when src_req = 0 ;
always @(posedge dst_clk or negedge dst_rst_n)
begin
if(dst_rst_n == 1'b0)
dst_sync_ack <= 1'b0;
else if (req_state_dly2)
dst_sync_ack <= 1'b1;
else
dst_sync_ack <= 1'b0;
end
endmodule
From the code, src_sync_idle is pulled low while a synchronization is in progress; if another input pulse arrives during this time, src_sync_fail will be asserted to indicate synchronization failure.
The simulation shows that this design meets the intended synchronization behavior.