From bfc8ec28c389b69d20fa0a75f2ae7ea3fc5607c6 Mon Sep 17 00:00:00 2001 From: Laszlo Nagy Date: Mon, 19 Mar 2018 10:34:20 +0100 Subject: [PATCH] util_axis_fifo: instantiate block ram in async mode In cases when a shallow FIFO is requested the synthesizer infers distributed RAM instead of block RAMs. This can be an issue when the clocks of the FIFO are asynchronous since a timing path is created though the LUTs which implement the memory, resulting in timing failures. Ignoring timing through the path is not a solution since would lead to metastability. This does not happens with block RAMs. The solution is to use the ad_mem (block RAM) in case of async clocks and letting the synthesizer do it's job in case of sync clocks for optimal resource utilization. --- library/altera/avl_dacfifo/avl_dacfifo_rd.v | 1 + library/axi_ad9625/axi_ad9625_if.v | 1 + library/axi_ad9671/axi_ad9671_if.v | 1 + library/axi_hdmi_tx/axi_hdmi_tx_core.v | 1 + library/common/ad_mem.v | 5 +- library/util_axis_fifo/Makefile | 1 + library/util_axis_fifo/util_axis_fifo.v | 275 +++++++++++-------- library/util_axis_fifo/util_axis_fifo_ip.tcl | 1 + library/util_dacfifo/util_dacfifo.v | 1 + library/util_mfifo/util_mfifo.v | 1 + library/util_rfifo/util_rfifo.v | 1 + library/util_wfifo/util_wfifo.v | 1 + library/xilinx/axi_adcfifo/axi_adcfifo_wr.v | 1 + 13 files changed, 168 insertions(+), 123 deletions(-) diff --git a/library/altera/avl_dacfifo/avl_dacfifo_rd.v b/library/altera/avl_dacfifo/avl_dacfifo_rd.v index ff729d6db..1dd5515da 100644 --- a/library/altera/avl_dacfifo/avl_dacfifo_rd.v +++ b/library/altera/avl_dacfifo/avl_dacfifo_rd.v @@ -439,6 +439,7 @@ module avl_dacfifo_rd #( .addra (dac_mem_laddr_waddr), .dina (dac_mem_laddr), .clkb (dac_clk), + .reb (1'b1), .addrb (dac_mem_laddr_raddr), .doutb (dac_mem_laddr_s)); diff --git a/library/axi_ad9625/axi_ad9625_if.v b/library/axi_ad9625/axi_ad9625_if.v index 4ba0fabd0..64e13f610 100644 --- a/library/axi_ad9625/axi_ad9625_if.v +++ b/library/axi_ad9625/axi_ad9625_if.v @@ -213,6 +213,7 @@ module axi_ad9625_if #( .addra (adc_waddr), .dina (adc_wdata), .clkb (rx_clk), + .reb (1'b1), .addrb (adc_raddr_s), .doutb (adc_rdata_s)); diff --git a/library/axi_ad9671/axi_ad9671_if.v b/library/axi_ad9671/axi_ad9671_if.v index 4b8b6c280..4900b58be 100644 --- a/library/axi_ad9671/axi_ad9671_if.v +++ b/library/axi_ad9671/axi_ad9671_if.v @@ -190,6 +190,7 @@ module axi_ad9671_if #( .addra(adc_waddr), .dina(adc_wdata), .clkb(rx_clk), + .reb (1'b1), .addrb(adc_raddr_s), .doutb(adc_rdata)); diff --git a/library/axi_hdmi_tx/axi_hdmi_tx_core.v b/library/axi_hdmi_tx/axi_hdmi_tx_core.v index 2a5c00ae3..c535934d5 100644 --- a/library/axi_hdmi_tx/axi_hdmi_tx_core.v +++ b/library/axi_hdmi_tx/axi_hdmi_tx_core.v @@ -513,6 +513,7 @@ module axi_hdmi_tx_core #( .addra (vdma_waddr), .dina (vdma_wdata), .clkb (hdmi_clk), + .reb (1'b1), .addrb (hdmi_raddr[9:1]), .doutb (hdmi_rdata_s)); diff --git a/library/common/ad_mem.v b/library/common/ad_mem.v index b101e7610..0843d4a17 100644 --- a/library/common/ad_mem.v +++ b/library/common/ad_mem.v @@ -46,6 +46,7 @@ module ad_mem #( input [(DATA_WIDTH-1):0] dina, input clkb, + input reb, input [(ADDRESS_WIDTH-1):0] addrb, output reg [(DATA_WIDTH-1):0] doutb); @@ -59,7 +60,9 @@ module ad_mem #( end always @(posedge clkb) begin - doutb <= m_ram[addrb]; + if (reb == 1'b1) begin + doutb <= m_ram[addrb]; + end end endmodule diff --git a/library/util_axis_fifo/Makefile b/library/util_axis_fifo/Makefile index 699dc8ddf..1c4dad69d 100644 --- a/library/util_axis_fifo/Makefile +++ b/library/util_axis_fifo/Makefile @@ -5,6 +5,7 @@ #################################################################################### #################################################################################### +M_DEPS += ../common/ad_mem.v M_DEPS += ../scripts/adi_env.tcl M_DEPS += ../scripts/adi_ip.tcl M_DEPS += address_gray.v diff --git a/library/util_axis_fifo/util_axis_fifo.v b/library/util_axis_fifo/util_axis_fifo.v index dcd2f2917..99923faa9 100644 --- a/library/util_axis_fifo/util_axis_fifo.v +++ b/library/util_axis_fifo/util_axis_fifo.v @@ -57,153 +57,184 @@ module util_axis_fifo #( generate if (ADDRESS_WIDTH == 0) begin -reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram; -reg s_axis_waddr = 1'b0; -reg m_axis_raddr = 1'b0; + reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram; + reg s_axis_waddr = 1'b0; + reg m_axis_raddr = 1'b0; -wire m_axis_waddr; -wire s_axis_raddr; + wire m_axis_waddr; + wire s_axis_raddr; -sync_bits #( - .NUM_OF_BITS(1), - .ASYNC_CLK(ASYNC_CLK) -) i_waddr_sync ( - .out_clk(m_axis_aclk), - .out_resetn(m_axis_aresetn), - .in(s_axis_waddr), - .out(m_axis_waddr) -); + sync_bits #( + .NUM_OF_BITS(1), + .ASYNC_CLK(ASYNC_CLK) + ) i_waddr_sync ( + .out_clk(m_axis_aclk), + .out_resetn(m_axis_aresetn), + .in(s_axis_waddr), + .out(m_axis_waddr) + ); -sync_bits #( - .NUM_OF_BITS(1), - .ASYNC_CLK(ASYNC_CLK) -) i_raddr_sync ( - .out_clk(s_axis_aclk), - .out_resetn(s_axis_aresetn), - .in(m_axis_raddr), - .out(s_axis_raddr) -); + sync_bits #( + .NUM_OF_BITS(1), + .ASYNC_CLK(ASYNC_CLK) + ) i_raddr_sync ( + .out_clk(s_axis_aclk), + .out_resetn(s_axis_aresetn), + .in(m_axis_raddr), + .out(s_axis_raddr) + ); -assign m_axis_valid = m_axis_raddr != m_axis_waddr; -assign m_axis_level = m_axis_valid; -assign s_axis_ready = s_axis_raddr == s_axis_waddr; -assign s_axis_empty = s_axis_ready; -assign s_axis_room = s_axis_ready; + assign m_axis_valid = m_axis_raddr != m_axis_waddr; + assign m_axis_level = m_axis_valid; + assign s_axis_ready = s_axis_raddr == s_axis_waddr; + assign s_axis_empty = s_axis_ready; + assign s_axis_room = s_axis_ready; -always @(posedge s_axis_aclk) begin - if (s_axis_ready == 1'b1 && s_axis_valid == 1'b1) - cdc_sync_fifo_ram <= s_axis_data; -end + always @(posedge s_axis_aclk) begin + if (s_axis_ready == 1'b1 && s_axis_valid == 1'b1) + cdc_sync_fifo_ram <= s_axis_data; + end -always @(posedge s_axis_aclk) begin - if (s_axis_aresetn == 1'b0) begin - s_axis_waddr <= 1'b0; - end else begin - if (s_axis_ready & s_axis_valid) begin - s_axis_waddr <= s_axis_waddr + 1'b1; + always @(posedge s_axis_aclk) begin + if (s_axis_aresetn == 1'b0) begin + s_axis_waddr <= 1'b0; + end else begin + if (s_axis_ready & s_axis_valid) begin + s_axis_waddr <= s_axis_waddr + 1'b1; + end end end -end -always @(posedge m_axis_aclk) begin - if (m_axis_aresetn == 1'b0) begin - m_axis_raddr <= 1'b0; - end else begin - if (m_axis_valid & m_axis_ready) - m_axis_raddr <= m_axis_raddr + 1'b1; + always @(posedge m_axis_aclk) begin + if (m_axis_aresetn == 1'b0) begin + m_axis_raddr <= 1'b0; + end else begin + if (m_axis_valid & m_axis_ready) + m_axis_raddr <= m_axis_raddr + 1'b1; + end end -end -assign m_axis_data = cdc_sync_fifo_ram; + assign m_axis_data = cdc_sync_fifo_ram; end else begin -reg [DATA_WIDTH-1:0] ram[0:2**ADDRESS_WIDTH-1]; + reg [DATA_WIDTH-1:0] ram[0:2**ADDRESS_WIDTH-1]; -wire [ADDRESS_WIDTH-1:0] s_axis_waddr; -wire [ADDRESS_WIDTH-1:0] m_axis_raddr; -wire _m_axis_ready; -wire _m_axis_valid; + wire [ADDRESS_WIDTH-1:0] s_axis_waddr; + wire [ADDRESS_WIDTH-1:0] m_axis_raddr; + wire _m_axis_ready; + wire _m_axis_valid; -if (ASYNC_CLK == 1) begin + wire s_mem_write; + wire m_mem_read; -fifo_address_gray_pipelined #( - .ADDRESS_WIDTH(ADDRESS_WIDTH) -) i_address_gray ( - .m_axis_aclk(m_axis_aclk), - .m_axis_aresetn(m_axis_aresetn), - .m_axis_ready(_m_axis_ready), - .m_axis_valid(_m_axis_valid), - .m_axis_raddr(m_axis_raddr), - .m_axis_level(m_axis_level), + reg valid; - .s_axis_aclk(s_axis_aclk), - .s_axis_aresetn(s_axis_aresetn), - .s_axis_ready(s_axis_ready), - .s_axis_valid(s_axis_valid), - .s_axis_empty(s_axis_empty), - .s_axis_waddr(s_axis_waddr), - .s_axis_room(s_axis_room) -); - -end else begin - -fifo_address_sync #( - .ADDRESS_WIDTH(ADDRESS_WIDTH) -) i_address_sync ( - .clk(m_axis_aclk), - .resetn(m_axis_aresetn), - .m_axis_ready(_m_axis_ready), - .m_axis_valid(_m_axis_valid), - .m_axis_raddr(m_axis_raddr), - .m_axis_level(m_axis_level), - - .s_axis_ready(s_axis_ready), - .s_axis_valid(s_axis_valid), - .s_axis_empty(s_axis_empty), - .s_axis_waddr(s_axis_waddr), - .s_axis_room(s_axis_room) -); - -end - -always @(posedge s_axis_aclk) begin - if (s_axis_ready == 1'b1 && s_axis_valid == 1'b1) - ram[s_axis_waddr] <= s_axis_data; -end - -if (S_AXIS_REGISTERED == 1) begin - -reg [DATA_WIDTH-1:0] data; -reg valid; - -always @(posedge m_axis_aclk) begin - if (m_axis_aresetn == 1'b0) begin - valid <= 1'b0; - end else begin - if (_m_axis_valid) - valid <= 1'b1; - else if (m_axis_ready) + always @(posedge m_axis_aclk) begin + if (m_axis_aresetn == 1'b0) begin valid <= 1'b0; + end else begin + if (_m_axis_valid) + valid <= 1'b1; + else if (m_axis_ready) + valid <= 1'b0; + end end -end -always @(posedge m_axis_aclk) begin - if ((~valid || m_axis_ready) && _m_axis_valid) - data <= ram[m_axis_raddr]; -end + assign s_mem_write = s_axis_ready & s_axis_valid; + assign m_mem_read = (~valid || m_axis_ready) && _m_axis_valid; -assign _m_axis_ready = ~valid || m_axis_ready; -assign m_axis_data = data; -assign m_axis_valid = valid; + if (ASYNC_CLK == 1) begin -end else begin + // The assumption is that in this mode the S_AXIS_REGISTERED is 1 -assign _m_axis_ready = m_axis_ready; -assign m_axis_valid = _m_axis_valid; -assign m_axis_data = ram[m_axis_raddr]; + fifo_address_gray_pipelined #( + .ADDRESS_WIDTH(ADDRESS_WIDTH) + ) i_address_gray ( + .m_axis_aclk(m_axis_aclk), + .m_axis_aresetn(m_axis_aresetn), + .m_axis_ready(_m_axis_ready), + .m_axis_valid(_m_axis_valid), + .m_axis_raddr(m_axis_raddr), + .m_axis_level(m_axis_level), -end + .s_axis_aclk(s_axis_aclk), + .s_axis_aresetn(s_axis_aresetn), + .s_axis_ready(s_axis_ready), + .s_axis_valid(s_axis_valid), + .s_axis_empty(s_axis_empty), + .s_axis_waddr(s_axis_waddr), + .s_axis_room(s_axis_room) + ); + + // When the clocks are asynchronous instantiate a block RAM + // regardless of the requested size to make sure we threat the + // clock crossing correctly + ad_mem #( + .DATA_WIDTH (DATA_WIDTH), + .ADDRESS_WIDTH (ADDRESS_WIDTH)) + i_mem ( + .clka(s_axis_aclk), + .wea(s_mem_write), + .addra(s_axis_waddr), + .dina(s_axis_data), + .clkb(m_axis_aclk), + .reb(m_mem_read), + .addrb(m_axis_raddr), + .doutb(m_axis_data) + ); + + assign _m_axis_ready = ~valid || m_axis_ready; + assign m_axis_valid = valid; + + end else begin + + fifo_address_sync #( + .ADDRESS_WIDTH(ADDRESS_WIDTH) + ) i_address_sync ( + .clk(m_axis_aclk), + .resetn(m_axis_aresetn), + .m_axis_ready(_m_axis_ready), + .m_axis_valid(_m_axis_valid), + .m_axis_raddr(m_axis_raddr), + .m_axis_level(m_axis_level), + + .s_axis_ready(s_axis_ready), + .s_axis_valid(s_axis_valid), + .s_axis_empty(s_axis_empty), + .s_axis_waddr(s_axis_waddr), + .s_axis_room(s_axis_room) + ); + + // When the clocks are synchronous use behavioral modeling for the SDP RAM + // Let the synthesizer decide what to infer (distributed or block RAM) + always @(posedge s_axis_aclk) begin + if (s_mem_write) + ram[s_axis_waddr] <= s_axis_data; + end + + if (S_AXIS_REGISTERED == 1) begin + + reg [DATA_WIDTH-1:0] data; + + always @(posedge m_axis_aclk) begin + if (m_mem_read) + data <= ram[m_axis_raddr]; + end + + assign _m_axis_ready = ~valid || m_axis_ready; + assign m_axis_data = data; + assign m_axis_valid = valid; + + end else begin + + assign _m_axis_ready = m_axis_ready; + assign m_axis_valid = _m_axis_valid; + assign m_axis_data = ram[m_axis_raddr]; + + end + + end end endgenerate diff --git a/library/util_axis_fifo/util_axis_fifo_ip.tcl b/library/util_axis_fifo/util_axis_fifo_ip.tcl index 8dbaaddc2..d0fc1ce4f 100644 --- a/library/util_axis_fifo/util_axis_fifo_ip.tcl +++ b/library/util_axis_fifo/util_axis_fifo_ip.tcl @@ -7,6 +7,7 @@ adi_ip_files util_axis_fifo [list \ "address_gray.v" \ "address_gray_pipelined.v" \ "address_sync.v" \ + "../common/ad_mem.v" \ "util_axis_fifo.v" \ ] diff --git a/library/util_dacfifo/util_dacfifo.v b/library/util_dacfifo/util_dacfifo.v index 2ff18a846..7e302917c 100644 --- a/library/util_dacfifo/util_dacfifo.v +++ b/library/util_dacfifo/util_dacfifo.v @@ -289,6 +289,7 @@ module util_dacfifo #( .addra (dma_waddr), .dina (dma_data), .clkb (dac_clk), + .reb (1'b1), .addrb (dac_raddr), .doutb (dac_data_s)); diff --git a/library/util_mfifo/util_mfifo.v b/library/util_mfifo/util_mfifo.v index ac56fc40d..f02ccbb4e 100644 --- a/library/util_mfifo/util_mfifo.v +++ b/library/util_mfifo/util_mfifo.v @@ -261,6 +261,7 @@ module util_mfifo #( .addra (din_waddr), .dina (din_wdata_s[n]), .clkb (dout_clk), + .reb (1'b1), .addrb (dout_raddr), .doutb (dout_rdata_s[n])); end diff --git a/library/util_rfifo/util_rfifo.v b/library/util_rfifo/util_rfifo.v index 4d380a281..dd1ff888d 100644 --- a/library/util_rfifo/util_rfifo.v +++ b/library/util_rfifo/util_rfifo.v @@ -395,6 +395,7 @@ module util_rfifo #( .addra (din_waddr), .dina (din_wdata), .clkb (dout_clk), + .reb (1'b1), .addrb (dout_raddr), .doutb (dout_rdata_s)); diff --git a/library/util_wfifo/util_wfifo.v b/library/util_wfifo/util_wfifo.v index 85ffabe5b..ecf222850 100644 --- a/library/util_wfifo/util_wfifo.v +++ b/library/util_wfifo/util_wfifo.v @@ -332,6 +332,7 @@ module util_wfifo #( .addra (din_waddr), .dina (din_wdata), .clkb (dout_clk), + .reb (1'b1), .addrb (dout_raddr), .doutb (dout_rdata_s)); diff --git a/library/xilinx/axi_adcfifo/axi_adcfifo_wr.v b/library/xilinx/axi_adcfifo/axi_adcfifo_wr.v index afdcaec70..a0a5d9663 100644 --- a/library/xilinx/axi_adcfifo/axi_adcfifo_wr.v +++ b/library/xilinx/axi_adcfifo/axi_adcfifo_wr.v @@ -408,6 +408,7 @@ module axi_adcfifo_wr #( .addra (adc_waddr), .dina (adc_wdata), .clkb (axi_clk), + .reb (1'b1), .addrb (axi_raddr), .doutb (axi_rdata_s));