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),
.dina (dac_mem_laddr),
.clkb (dac_clk),
.reb (1'b1),
.addrb (dac_mem_laddr_raddr),
.doutb (dac_mem_laddr_s));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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" \
]

View File

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

View File

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

View File

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

View File

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

View File

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