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.
main
Laszlo Nagy 2018-03-19 10:34:20 +01:00 committed by István Csomortáni
parent 51380fbea4
commit bfc8ec28c3
13 changed files with 168 additions and 123 deletions

View File

@ -439,6 +439,7 @@ module avl_dacfifo_rd #(
.addra (dac_mem_laddr_waddr), .addra (dac_mem_laddr_waddr),
.dina (dac_mem_laddr), .dina (dac_mem_laddr),
.clkb (dac_clk), .clkb (dac_clk),
.reb (1'b1),
.addrb (dac_mem_laddr_raddr), .addrb (dac_mem_laddr_raddr),
.doutb (dac_mem_laddr_s)); .doutb (dac_mem_laddr_s));

View File

@ -213,6 +213,7 @@ module axi_ad9625_if #(
.addra (adc_waddr), .addra (adc_waddr),
.dina (adc_wdata), .dina (adc_wdata),
.clkb (rx_clk), .clkb (rx_clk),
.reb (1'b1),
.addrb (adc_raddr_s), .addrb (adc_raddr_s),
.doutb (adc_rdata_s)); .doutb (adc_rdata_s));

View File

@ -190,6 +190,7 @@ module axi_ad9671_if #(
.addra(adc_waddr), .addra(adc_waddr),
.dina(adc_wdata), .dina(adc_wdata),
.clkb(rx_clk), .clkb(rx_clk),
.reb (1'b1),
.addrb(adc_raddr_s), .addrb(adc_raddr_s),
.doutb(adc_rdata)); .doutb(adc_rdata));

View File

@ -513,6 +513,7 @@ module axi_hdmi_tx_core #(
.addra (vdma_waddr), .addra (vdma_waddr),
.dina (vdma_wdata), .dina (vdma_wdata),
.clkb (hdmi_clk), .clkb (hdmi_clk),
.reb (1'b1),
.addrb (hdmi_raddr[9:1]), .addrb (hdmi_raddr[9:1]),
.doutb (hdmi_rdata_s)); .doutb (hdmi_rdata_s));

View File

@ -46,6 +46,7 @@ module ad_mem #(
input [(DATA_WIDTH-1):0] dina, input [(DATA_WIDTH-1):0] dina,
input clkb, input clkb,
input reb,
input [(ADDRESS_WIDTH-1):0] addrb, input [(ADDRESS_WIDTH-1):0] addrb,
output reg [(DATA_WIDTH-1):0] doutb); output reg [(DATA_WIDTH-1):0] doutb);
@ -59,8 +60,10 @@ module ad_mem #(
end end
always @(posedge clkb) begin always @(posedge clkb) begin
if (reb == 1'b1) begin
doutb <= m_ram[addrb]; doutb <= m_ram[addrb];
end end
end
endmodule endmodule

View File

@ -5,6 +5,7 @@
#################################################################################### ####################################################################################
#################################################################################### ####################################################################################
M_DEPS += ../common/ad_mem.v
M_DEPS += ../scripts/adi_env.tcl M_DEPS += ../scripts/adi_env.tcl
M_DEPS += ../scripts/adi_ip.tcl M_DEPS += ../scripts/adi_ip.tcl
M_DEPS += address_gray.v M_DEPS += address_gray.v

View File

@ -125,8 +125,29 @@ wire [ADDRESS_WIDTH-1:0] m_axis_raddr;
wire _m_axis_ready; wire _m_axis_ready;
wire _m_axis_valid; wire _m_axis_valid;
wire s_mem_write;
wire m_mem_read;
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)
valid <= 1'b0;
end
end
assign s_mem_write = s_axis_ready & s_axis_valid;
assign m_mem_read = (~valid || m_axis_ready) && _m_axis_valid;
if (ASYNC_CLK == 1) begin if (ASYNC_CLK == 1) begin
// The assumption is that in this mode the S_AXIS_REGISTERED is 1
fifo_address_gray_pipelined #( fifo_address_gray_pipelined #(
.ADDRESS_WIDTH(ADDRESS_WIDTH) .ADDRESS_WIDTH(ADDRESS_WIDTH)
) i_address_gray ( ) i_address_gray (
@ -146,6 +167,26 @@ fifo_address_gray_pipelined #(
.s_axis_room(s_axis_room) .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 end else begin
fifo_address_sync #( fifo_address_sync #(
@ -165,31 +206,19 @@ fifo_address_sync #(
.s_axis_room(s_axis_room) .s_axis_room(s_axis_room)
); );
end // 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 always @(posedge s_axis_aclk) begin
if (s_axis_ready == 1'b1 && s_axis_valid == 1'b1) if (s_mem_write)
ram[s_axis_waddr] <= s_axis_data; ram[s_axis_waddr] <= s_axis_data;
end end
if (S_AXIS_REGISTERED == 1) begin if (S_AXIS_REGISTERED == 1) begin
reg [DATA_WIDTH-1:0] data; reg [DATA_WIDTH-1:0] data;
reg valid;
always @(posedge m_axis_aclk) begin always @(posedge m_axis_aclk) begin
if (m_axis_aresetn == 1'b0) begin if (m_mem_read)
valid <= 1'b0;
end else begin
if (_m_axis_valid)
valid <= 1'b1;
else if (m_axis_ready)
valid <= 1'b0;
end
end
always @(posedge m_axis_aclk) begin
if ((~valid || m_axis_ready) && _m_axis_valid)
data <= ram[m_axis_raddr]; data <= ram[m_axis_raddr];
end end
@ -205,6 +234,8 @@ assign m_axis_data = ram[m_axis_raddr];
end end
end
end endgenerate end endgenerate
endmodule endmodule

View File

@ -7,6 +7,7 @@ adi_ip_files util_axis_fifo [list \
"address_gray.v" \ "address_gray.v" \
"address_gray_pipelined.v" \ "address_gray_pipelined.v" \
"address_sync.v" \ "address_sync.v" \
"../common/ad_mem.v" \
"util_axis_fifo.v" \ "util_axis_fifo.v" \
] ]

View File

@ -289,6 +289,7 @@ module util_dacfifo #(
.addra (dma_waddr), .addra (dma_waddr),
.dina (dma_data), .dina (dma_data),
.clkb (dac_clk), .clkb (dac_clk),
.reb (1'b1),
.addrb (dac_raddr), .addrb (dac_raddr),
.doutb (dac_data_s)); .doutb (dac_data_s));

View File

@ -261,6 +261,7 @@ module util_mfifo #(
.addra (din_waddr), .addra (din_waddr),
.dina (din_wdata_s[n]), .dina (din_wdata_s[n]),
.clkb (dout_clk), .clkb (dout_clk),
.reb (1'b1),
.addrb (dout_raddr), .addrb (dout_raddr),
.doutb (dout_rdata_s[n])); .doutb (dout_rdata_s[n]));
end end

View File

@ -395,6 +395,7 @@ module util_rfifo #(
.addra (din_waddr), .addra (din_waddr),
.dina (din_wdata), .dina (din_wdata),
.clkb (dout_clk), .clkb (dout_clk),
.reb (1'b1),
.addrb (dout_raddr), .addrb (dout_raddr),
.doutb (dout_rdata_s)); .doutb (dout_rdata_s));

View File

@ -332,6 +332,7 @@ module util_wfifo #(
.addra (din_waddr), .addra (din_waddr),
.dina (din_wdata), .dina (din_wdata),
.clkb (dout_clk), .clkb (dout_clk),
.reb (1'b1),
.addrb (dout_raddr), .addrb (dout_raddr),
.doutb (dout_rdata_s)); .doutb (dout_rdata_s));

View File

@ -408,6 +408,7 @@ module axi_adcfifo_wr #(
.addra (adc_waddr), .addra (adc_waddr),
.dina (adc_wdata), .dina (adc_wdata),
.clkb (axi_clk), .clkb (axi_clk),
.reb (1'b1),
.addrb (axi_raddr), .addrb (axi_raddr),
.doutb (axi_rdata_s)); .doutb (axi_rdata_s));