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,7 +60,9 @@ module ad_mem #(
end end
always @(posedge clkb) begin always @(posedge clkb) begin
doutb <= m_ram[addrb]; if (reb == 1'b1) begin
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

@ -57,153 +57,184 @@ module util_axis_fifo #(
generate if (ADDRESS_WIDTH == 0) begin generate if (ADDRESS_WIDTH == 0) begin
reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram; reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram;
reg s_axis_waddr = 1'b0; reg s_axis_waddr = 1'b0;
reg m_axis_raddr = 1'b0; reg m_axis_raddr = 1'b0;
wire m_axis_waddr; wire m_axis_waddr;
wire s_axis_raddr; wire s_axis_raddr;
sync_bits #( sync_bits #(
.NUM_OF_BITS(1), .NUM_OF_BITS(1),
.ASYNC_CLK(ASYNC_CLK) .ASYNC_CLK(ASYNC_CLK)
) i_waddr_sync ( ) i_waddr_sync (
.out_clk(m_axis_aclk), .out_clk(m_axis_aclk),
.out_resetn(m_axis_aresetn), .out_resetn(m_axis_aresetn),
.in(s_axis_waddr), .in(s_axis_waddr),
.out(m_axis_waddr) .out(m_axis_waddr)
); );
sync_bits #( sync_bits #(
.NUM_OF_BITS(1), .NUM_OF_BITS(1),
.ASYNC_CLK(ASYNC_CLK) .ASYNC_CLK(ASYNC_CLK)
) i_raddr_sync ( ) i_raddr_sync (
.out_clk(s_axis_aclk), .out_clk(s_axis_aclk),
.out_resetn(s_axis_aresetn), .out_resetn(s_axis_aresetn),
.in(m_axis_raddr), .in(m_axis_raddr),
.out(s_axis_raddr) .out(s_axis_raddr)
); );
assign m_axis_valid = m_axis_raddr != m_axis_waddr; assign m_axis_valid = m_axis_raddr != m_axis_waddr;
assign m_axis_level = m_axis_valid; assign m_axis_level = m_axis_valid;
assign s_axis_ready = s_axis_raddr == s_axis_waddr; assign s_axis_ready = s_axis_raddr == s_axis_waddr;
assign s_axis_empty = s_axis_ready; assign s_axis_empty = s_axis_ready;
assign s_axis_room = s_axis_ready; assign s_axis_room = s_axis_ready;
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_axis_ready == 1'b1 && s_axis_valid == 1'b1)
cdc_sync_fifo_ram <= s_axis_data; cdc_sync_fifo_ram <= s_axis_data;
end end
always @(posedge s_axis_aclk) begin always @(posedge s_axis_aclk) begin
if (s_axis_aresetn == 1'b0) begin if (s_axis_aresetn == 1'b0) begin
s_axis_waddr <= 1'b0; s_axis_waddr <= 1'b0;
end else begin end else begin
if (s_axis_ready & s_axis_valid) begin if (s_axis_ready & s_axis_valid) begin
s_axis_waddr <= s_axis_waddr + 1'b1; s_axis_waddr <= s_axis_waddr + 1'b1;
end
end end
end end
end
always @(posedge m_axis_aclk) begin always @(posedge m_axis_aclk) begin
if (m_axis_aresetn == 1'b0) begin if (m_axis_aresetn == 1'b0) begin
m_axis_raddr <= 1'b0; m_axis_raddr <= 1'b0;
end else begin end else begin
if (m_axis_valid & m_axis_ready) if (m_axis_valid & m_axis_ready)
m_axis_raddr <= m_axis_raddr + 1'b1; m_axis_raddr <= m_axis_raddr + 1'b1;
end
end end
end
assign m_axis_data = cdc_sync_fifo_ram; assign m_axis_data = cdc_sync_fifo_ram;
end else begin 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] s_axis_waddr;
wire [ADDRESS_WIDTH-1:0] m_axis_raddr; wire [ADDRESS_WIDTH-1:0] m_axis_raddr;
wire _m_axis_ready; wire _m_axis_ready;
wire _m_axis_valid; wire _m_axis_valid;
if (ASYNC_CLK == 1) begin wire s_mem_write;
wire m_mem_read;
fifo_address_gray_pipelined #( reg valid;
.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),
.s_axis_aclk(s_axis_aclk), always @(posedge m_axis_aclk) begin
.s_axis_aresetn(s_axis_aresetn), if (m_axis_aresetn == 1'b0) begin
.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)
valid <= 1'b0; valid <= 1'b0;
end else begin
if (_m_axis_valid)
valid <= 1'b1;
else if (m_axis_ready)
valid <= 1'b0;
end
end end
end
always @(posedge m_axis_aclk) begin assign s_mem_write = s_axis_ready & s_axis_valid;
if ((~valid || m_axis_ready) && _m_axis_valid) assign m_mem_read = (~valid || m_axis_ready) && _m_axis_valid;
data <= ram[m_axis_raddr];
end
assign _m_axis_ready = ~valid || m_axis_ready; if (ASYNC_CLK == 1) begin
assign m_axis_data = data;
assign m_axis_valid = valid;
end else begin // The assumption is that in this mode the S_AXIS_REGISTERED is 1
assign _m_axis_ready = m_axis_ready; fifo_address_gray_pipelined #(
assign m_axis_valid = _m_axis_valid; .ADDRESS_WIDTH(ADDRESS_WIDTH)
assign m_axis_data = ram[m_axis_raddr]; ) 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 end endgenerate

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