data_offload: Improve external synchronization

This commit adds a new synthesis option to the design, that controls
whether an internal clock domain crossing will be generated. Disabling
this option allows you to use a synchronization signal that is
synchronized to the write clock domain externally, and possibly shared
between multiple devices.

The default value retains the old behavior.

Signed-off-by: David Winter <david.winter@analog.com>
main
David Winter 2021-08-11 09:59:16 +02:00 committed by Adrian Costina
parent 0372ce1821
commit 7423ecae14
5 changed files with 61 additions and 33 deletions

View File

@ -55,7 +55,8 @@ module data_offload #(
parameter DST_RAW_DATA_EN = 1'b0, // TBD
parameter DST_CYCLIC_EN = 1'b0, // 1'b1 - CYCLIC mode enabled; 1'b0 - CYCLIC mode disabled
parameter AUTO_BRINGUP = 1) (
parameter AUTO_BRINGUP = 1,
parameter SYNC_EXT_ADD_INTERNAL_CDC = 1) (
// AXI4 Slave for configuration
@ -215,8 +216,10 @@ module data_offload #(
.WR_ADDRESS_WIDTH (SRC_ADDR_WIDTH),
.WR_DATA_WIDTH (SRC_DATA_WIDTH),
.RD_ADDRESS_WIDTH (DST_ADDR_WIDTH),
.RD_DATA_WIDTH (DST_DATA_WIDTH))
.RD_DATA_WIDTH (DST_DATA_WIDTH),
.SYNC_EXT_ADD_INTERNAL_CDC (SYNC_EXT_ADD_INTERNAL_CDC ))
i_data_offload_fsm (
.up_clk (up_clk),
.wr_clk (src_clk),
.wr_resetn_in (src_rstn),
.wr_resetn_out (fifo_src_resetn),

View File

@ -5,6 +5,7 @@
<: setFileProcessingOrder late :>
<: set mem_type [getBooleanValue "MEM_TYPE"] :>
<: set tx_enable [getBooleanValue "TX_OR_RXN_PATH"] :>
<: set internal_cdc [getBooleanValue "SYNC_EXT_ADD_INTERNAL_CDC"] :>
## for all synchronization registers from util_cdc modules
set_property ASYNC_REG TRUE \
@ -14,9 +15,23 @@ set_property ASYNC_REG TRUE \
## For RX in case of BRAMs
<: if { $tx_enable == 0 } { :>
<: if { $internal_cdc } { :>
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_wr_sync/cdc_sync_stage1_reg[*]/D}]
<: } :>
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_wr_sync/cdc_sync_stage1_reg[*]/D}]
-from [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_data_reg[*]}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/in_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_out/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_in/cdc_sync_stage1_reg[*]/D}]
<: if { !$mem_type } { :>
set_false_path \
@ -34,9 +49,12 @@ set_false_path \
## For TX in case of BRAMs
<: if { $tx_enable == 1 } { :>
<: if { $internal_cdc } { :>
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_rd_sync/cdc_sync_stage1_reg[*]/D}]
<: } :>
<: if { !$mem_type } { :>
set_false_path \
@ -52,21 +70,9 @@ set_false_path \
<: } :>
## For external DDRx memory
<: if { $mem_type == 1 } { :>
set_false_path \
-from [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/cdc_hold_reg[*]}] \
-to [get_cells -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_data_reg[*]}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/in_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_out/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-from [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/out_toggle_d1_reg/C}] \
-to [get_pins -hierarchical * -filter {NAME=~*/i_sync_src_transfer_length/i_sync_in/cdc_sync_stage1_reg[*]/D}]
set_false_path \
-to [get_pins -hierarchical * -filter {NAME=~*i_ddr_calib_done_sync/cdc_sync_stage1_reg[0]/D}]

View File

@ -44,7 +44,10 @@ module data_offload_fsm #(
parameter WR_ADDRESS_WIDTH = 4,
parameter WR_DATA_WIDTH = 128,
parameter RD_ADDRESS_WIDTH = 4,
parameter RD_DATA_WIDTH = 128)(
parameter RD_DATA_WIDTH = 128,
parameter SYNC_EXT_ADD_INTERNAL_CDC = 1) (
input up_clk,
// write control interface
input wr_clk,
@ -132,8 +135,6 @@ module data_offload_fsm #(
wire rd_init_ack_s;
wire [WR_ADDRESS_WIDTH-1:0] rd_wr_last_addr_s;
wire [WR_DATA_WIDTH/8-1:0] rd_wr_last_tkeep_s;
wire wr_sync_internal_s;
wire rd_sync_internal_s;
wire wr_sync_external_s;
wire rd_sync_external_s;
wire wr_oneshot;
@ -171,7 +172,7 @@ module data_offload_fsm #(
end
end
SOFTWARE: begin
if (wr_sync_internal_s) begin
if (sync_internal) begin
wr_fsm_state <= WR_WRITE_TO_MEM;
end
end
@ -256,7 +257,7 @@ module data_offload_fsm #(
end
end
end
always @(posedge wr_clk) begin
wr_ready_d <= wr_ready;
end
@ -315,7 +316,7 @@ module data_offload_fsm #(
end
end
SOFTWARE: begin
if (rd_sync_internal_s) begin
if (sync_internal) begin
rd_fsm_state <= RD_READ_FROM_MEM;
end
end
@ -555,24 +556,27 @@ module data_offload_fsm #(
end
end
// When SYNC_EXT_ADD_INTERNAL_CDC is deasserted, one of these signals will end
// up being synchronized to the "wrong" clock domain. This shouldn't matter
// because the incorrectly synchronized signal is guarded by a synthesis constant.
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
.NUM_OF_BITS (1),
.ASYNC_CLK (SYNC_EXT_ADD_INTERNAL_CDC))
i_sync_wr_sync (
.in_bits ({ sync_internal, sync_external }),
.in_bits ({ sync_external }),
.out_clk (wr_clk),
.out_resetn (1'b1),
.out_bits ({ wr_sync_internal_s, wr_sync_external_s })
.out_bits ({ wr_sync_external_s })
);
sync_bits #(
.NUM_OF_BITS (2),
.ASYNC_CLK (1))
.NUM_OF_BITS (1),
.ASYNC_CLK (SYNC_EXT_ADD_INTERNAL_CDC))
i_sync_rd_sync (
.in_bits ({ sync_internal, sync_external }),
.in_bits ({ sync_external }),
.out_clk (rd_clk),
.out_resetn (1'b1),
.out_bits ({ rd_sync_internal_s, rd_sync_external_s })
.out_bits ({ rd_sync_external_s })
);
endmodule

View File

@ -105,6 +105,7 @@ foreach {k v} { \
"SRC_RAW_DATA_EN" "false" \
"DST_RAW_DATA_EN" "false" \
"DST_CYCLIC_EN" "true" \
"SYNC_EXT_ADD_INTERNAL_CDC" "true" \
} { \
set_property -dict [list \
"value_format" "bool" \
@ -229,6 +230,11 @@ set_property -dict [list \
] [ipgui::get_guiparamspec -name "DST_CYCLIC_EN" -component $cc]
set_property enablement_tcl_expr {$TX_OR_RXN_PATH == 1} [ipx::get_user_parameters DST_CYCLIC_EN -of_objects $cc]
ipgui::add_param -name "SYNC_EXT_ADD_INTERNAL_CDC" -component $cc -parent $features_group
set_property -dict [list \
"display_name" "Generate CDC Circuit for sync_ext" \
] [ipgui::get_guiparamspec -name "SYNC_EXT_ADD_INTERNAL_CDC" -component $cc]
## Create and save the XGUI file
ipx::create_xgui_files $cc

View File

@ -1,5 +1,13 @@
proc ad_data_offload_create {instance_name datapath_type mem_type mem_size source_dwidth destination_dwidth {ddr_data_width 0} {ddr_addr_width 0}} {
proc ad_data_offload_create {instance_name
datapath_type
mem_type
mem_size
source_dwidth
destination_dwidth
{ddr_data_width 0}
{ddr_addr_width 0}
{shared_devclk 0}} {
global ad_hdl_dir
global sys_cpu_resetn
@ -44,6 +52,7 @@ proc ad_data_offload_create {instance_name datapath_type mem_type mem_size sourc
DST_DATA_WIDTH $destination_dwidth \
DST_ADDR_WIDTH $destination_awidth \
DST_CYCLIC_EN $datapath_type \
SYNC_EXT_ADD_INTERNAL_CDC [expr {!$shared_devclk}] \
]
if {$mem_type == 0} {