|
| 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