Skip to content

Commit cb22428

Browse files
committed
Added synchronizer modules
1 parent d8beb37 commit cb22428

File tree

2 files changed

+152
-0
lines changed

2 files changed

+152
-0
lines changed

cdc_data.sv

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//--------------------------------------------------------------------------------
2+
// cdc_data.sv
3+
// Konstantin Pavlov, [email protected]
4+
//--------------------------------------------------------------------------------
5+
6+
// INFO --------------------------------------------------------------------------------
7+
// Standard two-stage synchronizer
8+
// CDC stands for "clock data crossing"
9+
//
10+
// In fact, this madule is just a wrapper for dalay.sv
11+
//
12+
// Don`t forget to write false_path constraints for all your synchronizers
13+
// The best way to do it - is to mark all synchonizer delay.sv instances
14+
// with "_SYNC_ATTR" suffix. After that, just one constraint is required:
15+
//
16+
// For Quartus:
17+
// set_false_path -to [get_registers {*delay:*_SYNC_ATTR*|data[1]*}]
18+
//
19+
// For Vivado:
20+
// set_false_path -to [get_cells -hier -filter {NAME =~ *_SYNC_ATTR/data_reg[1]*}]
21+
//
22+
23+
24+
/* --- INSTANTIATION TEMPLATE BEGIN ---
25+
26+
cdc_data CD [31:0] (
27+
.clk( {32{clk}} ),
28+
.nrst( {32{1'b1}} ),
29+
.d( ext_data[31:0] ),
30+
.q( synchronized_data[31:0] )
31+
);
32+
33+
--- INSTANTIATION TEMPLATE END ---*/
34+
35+
36+
module cdc_data(
37+
input clk,
38+
input nrst,
39+
input d,
40+
output q
41+
);
42+
43+
delay #(
44+
.LENGTH( 2 ),
45+
.WIDTH( 1 ),
46+
.TYPE( "CELLS" ),
47+
.REGISTER_OUTPUTS( "FALSE" )
48+
) data_SYNC_ATTR (
49+
.clk( clk ),
50+
.nrst( nrst ),
51+
.ena( 1'b1 ),
52+
53+
.in( d ),
54+
.out( q )
55+
);
56+
57+
endmodule
58+

cdc_strobe.sv

+94
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
//--------------------------------------------------------------------------------
2+
// cdc_strobe.sv
3+
// Konstantin Pavlov, [email protected]
4+
//--------------------------------------------------------------------------------
5+
6+
// INFO --------------------------------------------------------------------------------
7+
// Clock crossing setup for single-pulse strobes
8+
// CDC stands for "clock data crossing"
9+
//
10+
// This is a simplest form of strobe CDC circuit. Good enough for rare single
11+
// strobe events. This module does NOT support close-standing strobes,
12+
// placed in adjacent lock cycles
13+
//
14+
// Don`t forget to write false_path constraints for all your synchronizers
15+
// The best way to do it - is to mark all synchonizer delay.sv instances
16+
// with "_SYNC_ATTR" suffix. After that, just one constraint is required:
17+
//
18+
// For Quartus:
19+
// set_false_path -to [get_registers {*delay:*_SYNC_ATTR*|data[1]*}]
20+
//
21+
// For Vivado:
22+
// set_false_path -to [get_cells -hier -filter {NAME =~ *_SYNC_ATTR/data_reg[1]*}]
23+
//
24+
25+
26+
/* --- INSTANTIATION TEMPLATE BEGIN ---
27+
28+
cdc_strobe CS [7:0] (
29+
.clk1_i( {8{clk1}} ),
30+
.nrst1_i( {8{1'b1}} ),
31+
.strb1_i( input_strobes[7:0] ),
32+
33+
.clk2_i( {8{clk2}} ),
34+
.strb2_o( output_strobes[7:0] )
35+
);
36+
37+
--- INSTANTIATION TEMPLATE END ---*/
38+
39+
40+
module cdc_strobe #( parameter
41+
PRE_STRETCH( 2 ) // number of cycles to stretch input strobe
42+
)(
43+
input clk1_i, // clock domain 1 clock
44+
input nrst1_i, // clock domain 1 reset (inversed)
45+
input strb1_i, // clock domain 1 strobe
46+
47+
input clk2_i, // clock domain 2 clock
48+
output strb2_o // clock domain 2 strobe
49+
);
50+
51+
// This signal should be at_least(!!!) one clk2_i period long
52+
// Preliminary stretching is usually nessesary, unless you are crossing
53+
// to essentialy high-frequency clock clk2_i, that is > 2*clk1_i
54+
logic strb1_stretched;
55+
56+
pulse_stretch #(
57+
.WIDTH( PRE_STRETCH ),
58+
.USE_CNTR( 0 )
59+
) stretch_strb1 (
60+
.clk( clk1_i ),
61+
.nrst( nrst1_i ),
62+
.in( strb1_i ),
63+
.out( strb1_stretched )
64+
);
65+
66+
// This is a synchronized signal in clk2_i clock domain,
67+
// but no guarantee, that it is one-cycle-high
68+
logic strb2_stretched;
69+
70+
delay #(
71+
.LENGTH( 2 ),
72+
.WIDTH( 1 ),
73+
.TYPE( "CELLS" ),
74+
.REGISTER_OUTPUTS( "FALSE" )
75+
) delay_strb1_SYNC_ATTR (
76+
.clk( clk2_i ),
77+
.nrst( 1'b1 ),
78+
.ena( 1'b1 ),
79+
80+
.in( strb1_stretched ),
81+
.out( strb2_stretched )
82+
);
83+
84+
edge_detect ed_strb2 (
85+
.clk( clk2_i ),
86+
.nrst( 1'b1 ),
87+
.in( strb2_stretched ),
88+
.rising( strb2_o ), // and now the signal is definitely one-cycle-high
89+
.falling( ),
90+
.both( )
91+
);
92+
93+
endmodule
94+

0 commit comments

Comments
 (0)