Implements a flag bit which is set in one clock domain and cleared from another clock domain, without any asynchronous resets, and with simpler CDC behaviour and control than a Flancter.
This design is derived from Rob Weinstein's Flancter design, but synchronizes all signals crossing clock domains, which makes it simpler to ensure it works correctly. The synchronization also frees us from the constraint that set and reset must never be asserted at the same time or within each others setup/hold window.
On the other hand, this circuit isn't quite equivalent to a Flancter as it depends on both clock domains to be always running for the synchronizers to pass values, while a Flancter does not (e.g.: we can still reset a Flancter even if the set clock is not running). Depending on your application, you may need to use Registers with asynchronous resets instead.
bit_set for one
clock_set cycle to raise
bit_out_set (and then
bit_out_reset), and pulse
bit_reset for one
clock_reset cycle to
bit_out_reset (and then
bit_out_set). A set or reset is
immediately visible in its own domain, then propagates to the other domain
after the usual CDC synchronization delay. A set operation while already
set, or a reset operation while already reset, is allowable and has no
clear_reset together for at least
+ EXTRA_CDC_STAGES cycles in each clock domain (
clock_reset) to reset the entire CDC Flag Bit, else
bit_out_reset may unexpectedly set rather than clear.
EXTRA_CDC_STAGES parameter if you are running near the
speed/temperature limits of your device. Consult your vendor datasheets.
`default_nettype none module CDC_Flag_Bit #( parameter EXTRA_CDC_STAGES = 0 ) ( input wire clock_set, input wire clear_set, input wire bit_set, output reg bit_out_set, input wire clock_reset, input wire clear_reset, input wire bit_reset, output reg bit_out_reset ); initial begin bit_out_set = 1'b0; bit_out_reset = 1'b0; end
resetting_bit Registers together form a toggle
register but split into two parts, one in each clock domain (set and
reset), whose relative difference expresses the value of the CDC flag bit.
bit_set makes the output of
setting_bit take the opposite
value of the synchronised
resetting_bit output, which signifies a flag
value of one.
wire reset_toggle_synced; wire set_toggle; Register #( .WORD_WIDTH (1), .RESET_VALUE (1'b0) ) setting_bit ( .clock (clock_set), .clock_enable (bit_set), .clear (clear_set), .data_in (~reset_toggle_synced), .data_out (set_toggle) );
We then sync the
set_toggle into the reset clock domain.
wire set_toggle_synced; CDC_Bit_Synchronizer #( .EXTRA_DEPTH (EXTRA_CDC_STAGES) // Must be 0 or greater ) set_to_reset ( .receiving_clock (clock_reset), .bit_in (set_toggle), .bit_out (set_toggle_synced) );
And use the
set_toggle_synced as the input to the
bit_reset makes the output of
resetting_bit match that of the
synchronized version of
setting_bit, which signifies a flag value of
wire reset_toggle; Register #( .WORD_WIDTH (1), .RESET_VALUE (1'b0) ) resetting_bit ( .clock (clock_reset), .clock_enable (bit_reset), .clear (clear_reset), .data_in (set_toggle_synced), .data_out (reset_toggle) );
Then we sync the
reset_toggle into the set clock domain.
CDC_Bit_Synchronizer #( .EXTRA_DEPTH (EXTRA_CDC_STAGES) // Must be 0 or greater ) reset_to_set ( .receiving_clock (clock_set), .bit_in (reset_toggle), .bit_out (reset_toggle_synced) );
Finally, in each clock domain, if the set and reset toggles differ, the flag is one. If they are the same, the flag is zero. The toggles, and thus the output bits, will eventually always match after CDC completes.
always @(*) begin bit_out_set = (set_toggle != reset_toggle_synced); bit_out_reset = (set_toggle_synced != reset_toggle); end endmodule
Back to FPGA Design Elements