From 5ac728392d3b5f00c929cd1c76be1fd7be4c7d4c Mon Sep 17 00:00:00 2001 From: Istvan Csomortani Date: Wed, 18 Nov 2020 16:14:49 +0000 Subject: [PATCH] util_axis_fifo: Refactoring Refactor the AXI4 stream FIFO implementation. - Define a single address generator which supports both single and double clock mode. (synchronous and asynchronous) - Fix FIFO status bits (empty/full). NOTE: In asynchronous mode the flags can have a several clock cycle delay in function of the upstream/downstream clock ratio. - In synchronous none FIFO mode (ADDRESS_WIDTH==0), the module acts as an AXI4 stream pipeline. --- library/util_axis_fifo/Makefile | 5 +- library/util_axis_fifo/address_gray.v | 155 ------------ .../util_axis_fifo/address_gray_pipelined.v | 152 ------------ library/util_axis_fifo/address_sync.v | 109 --------- library/util_axis_fifo/util_axis_fifo.v | 221 +++++++++--------- .../util_axis_fifo_address_generator.v | 187 +++++++++++++++ library/util_axis_fifo/util_axis_fifo_ip.tcl | 7 +- 7 files changed, 306 insertions(+), 530 deletions(-) delete mode 100644 library/util_axis_fifo/address_gray.v delete mode 100644 library/util_axis_fifo/address_gray_pipelined.v delete mode 100644 library/util_axis_fifo/address_sync.v create mode 100644 library/util_axis_fifo/util_axis_fifo_address_generator.v diff --git a/library/util_axis_fifo/Makefile b/library/util_axis_fifo/Makefile index d76109dd6..4cfa6e8ea 100644 --- a/library/util_axis_fifo/Makefile +++ b/library/util_axis_fifo/Makefile @@ -6,9 +6,8 @@ LIBRARY_NAME := util_axis_fifo GENERIC_DEPS += ../common/ad_mem.v -GENERIC_DEPS += address_gray.v -GENERIC_DEPS += address_gray_pipelined.v -GENERIC_DEPS += address_sync.v +GENERIC_DEPS += ../common/ad_mem_asym.v +GENERIC_DEPS += util_axis_fifo_address_generator.v GENERIC_DEPS += util_axis_fifo.v XILINX_DEPS += util_axis_fifo_ip.tcl diff --git a/library/util_axis_fifo/address_gray.v b/library/util_axis_fifo/address_gray.v deleted file mode 100644 index e292e56ea..000000000 --- a/library/util_axis_fifo/address_gray.v +++ /dev/null @@ -1,155 +0,0 @@ -// *************************************************************************** -// *************************************************************************** -// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. -// -// In this HDL repository, there are many different and unique modules, consisting -// of various HDL (Verilog or VHDL) components. The individual modules are -// developed independently, and may be accompanied by separate and unique license -// terms. -// -// The user should read each of these license terms, and understand the -// freedoms and responsibilities that he or she has by using this source/core. -// -// This core is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -// A PARTICULAR PURPOSE. -// -// Redistribution and use of source or resulting binaries, with or without modification -// of this file, are permitted under one of the following two license terms: -// -// 1. The GNU General Public License version 2 as published by the -// Free Software Foundation, which can be found in the top level directory -// of this repository (LICENSE_GPL2), and also online at: -// -// -// OR -// -// 2. An ADI specific BSD license, which can be found in the top level directory -// of this repository (LICENSE_ADIBSD), and also on-line at: -// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD -// This will allow to generate bit files and not release the source code, -// as long as it attaches to an ADI device. -// -// *************************************************************************** -// *************************************************************************** - -`timescale 1ns/100ps - -module fifo_address_gray #( - parameter ADDRESS_WIDTH = 4 -) ( - input m_axis_aclk, - input m_axis_aresetn, - input m_axis_ready, - output reg m_axis_valid, - output reg [ADDRESS_WIDTH:0] m_axis_level, - - input s_axis_aclk, - input s_axis_aresetn, - output reg s_axis_ready, - input s_axis_valid, - output reg s_axis_empty, - output [ADDRESS_WIDTH-1:0] s_axis_waddr, - output reg [ADDRESS_WIDTH:0] s_axis_room -); - -reg [ADDRESS_WIDTH:0] _s_axis_waddr = 'h00; -reg [ADDRESS_WIDTH:0] _s_axis_waddr_next; - -reg [ADDRESS_WIDTH:0] _m_axis_raddr = 'h00; -reg [ADDRESS_WIDTH:0] _m_axis_raddr_next; - -reg [ADDRESS_WIDTH:0] s_axis_waddr_gray = 'h00; -wire [ADDRESS_WIDTH:0] s_axis_waddr_gray_next; -wire [ADDRESS_WIDTH:0] s_axis_raddr_gray; - -reg [ADDRESS_WIDTH:0] m_axis_raddr_gray = 'h00; -wire [ADDRESS_WIDTH:0] m_axis_raddr_gray_next; -wire [ADDRESS_WIDTH:0] m_axis_waddr_gray; - -assign s_axis_waddr = _s_axis_waddr[ADDRESS_WIDTH-1:0]; - -always @(*) -begin - if (s_axis_ready && s_axis_valid) - _s_axis_waddr_next <= _s_axis_waddr + 1; - else - _s_axis_waddr_next <= _s_axis_waddr; -end - -assign s_axis_waddr_gray_next = _s_axis_waddr_next ^ _s_axis_waddr_next[ADDRESS_WIDTH:1]; - -always @(posedge s_axis_aclk) -begin - if (s_axis_aresetn == 1'b0) begin - _s_axis_waddr <= 'h00; - s_axis_waddr_gray <= 'h00; - end else begin - _s_axis_waddr <= _s_axis_waddr_next; - s_axis_waddr_gray <= s_axis_waddr_gray_next; - end -end - -always @(*) -begin - if (m_axis_ready && m_axis_valid) - _m_axis_raddr_next <= _m_axis_raddr + 1; - else - _m_axis_raddr_next <= _m_axis_raddr; -end - -assign m_axis_raddr_gray_next = _m_axis_raddr_next ^ _m_axis_raddr_next[ADDRESS_WIDTH:1]; - -always @(posedge m_axis_aclk) -begin - if (m_axis_aresetn == 1'b0) begin - _m_axis_raddr <= 'h00; - m_axis_raddr_gray <= 'h00; - end else begin - _m_axis_raddr <= _m_axis_raddr_next; - m_axis_raddr_gray <= m_axis_raddr_gray_next; - end -end - -sync_bits #( - .NUM_OF_BITS(ADDRESS_WIDTH + 1) -) i_waddr_sync ( - .out_clk(m_axis_aclk), - .out_resetn(m_axis_aresetn), - .in_bits(s_axis_waddr_gray), - .out_bits(m_axis_waddr_gray) -); - -sync_bits #( - .NUM_OF_BITS(ADDRESS_WIDTH + 1) -) i_raddr_sync ( - .out_clk(s_axis_aclk), - .out_resetn(s_axis_aresetn), - .in_bits(m_axis_raddr_gray), - .out_bits(s_axis_raddr_gray) -); - -always @(posedge s_axis_aclk) -begin - if (s_axis_aresetn == 1'b0) begin - s_axis_ready <= 1'b1; - s_axis_empty <= 1'b1; - end else begin - s_axis_ready <= (s_axis_raddr_gray[ADDRESS_WIDTH] == s_axis_waddr_gray_next[ADDRESS_WIDTH] || - s_axis_raddr_gray[ADDRESS_WIDTH-1] == s_axis_waddr_gray_next[ADDRESS_WIDTH-1] || - s_axis_raddr_gray[ADDRESS_WIDTH-2:0] != s_axis_waddr_gray_next[ADDRESS_WIDTH-2:0]); - s_axis_empty <= s_axis_raddr_gray == s_axis_waddr_gray_next; - end -end - -always @(posedge m_axis_aclk) -begin - if (s_axis_aresetn == 1'b0) - m_axis_valid <= 1'b0; - else begin - m_axis_valid <= m_axis_waddr_gray != m_axis_raddr_gray_next; - end -end - -endmodule - diff --git a/library/util_axis_fifo/address_gray_pipelined.v b/library/util_axis_fifo/address_gray_pipelined.v deleted file mode 100644 index 1b255543a..000000000 --- a/library/util_axis_fifo/address_gray_pipelined.v +++ /dev/null @@ -1,152 +0,0 @@ -// *************************************************************************** -// *************************************************************************** -// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. -// -// In this HDL repository, there are many different and unique modules, consisting -// of various HDL (Verilog or VHDL) components. The individual modules are -// developed independently, and may be accompanied by separate and unique license -// terms. -// -// The user should read each of these license terms, and understand the -// freedoms and responsibilities that he or she has by using this source/core. -// -// This core is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -// A PARTICULAR PURPOSE. -// -// Redistribution and use of source or resulting binaries, with or without modification -// of this file, are permitted under one of the following two license terms: -// -// 1. The GNU General Public License version 2 as published by the -// Free Software Foundation, which can be found in the top level directory -// of this repository (LICENSE_GPL2), and also online at: -// -// -// OR -// -// 2. An ADI specific BSD license, which can be found in the top level directory -// of this repository (LICENSE_ADIBSD), and also on-line at: -// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD -// This will allow to generate bit files and not release the source code, -// as long as it attaches to an ADI device. -// -// *************************************************************************** -// *************************************************************************** - -`timescale 1ns/100ps - -module fifo_address_gray_pipelined #( - parameter ADDRESS_WIDTH = 4 -) ( - input m_axis_aclk, - input m_axis_aresetn, - input m_axis_ready, - output reg m_axis_valid, - output [ADDRESS_WIDTH-1:0] m_axis_raddr, - output reg [ADDRESS_WIDTH:0] m_axis_level, - - input s_axis_aclk, - input s_axis_aresetn, - output reg s_axis_ready, - input s_axis_valid, - output reg s_axis_empty, - output [ADDRESS_WIDTH-1:0] s_axis_waddr, - output reg [ADDRESS_WIDTH:0] s_axis_room -); - -localparam MAX_ROOM = {1'b1,{ADDRESS_WIDTH{1'b0}}}; - -reg [ADDRESS_WIDTH:0] _s_axis_waddr = 'h00; -reg [ADDRESS_WIDTH:0] _s_axis_waddr_next; -wire [ADDRESS_WIDTH:0] _s_axis_raddr; - -reg [ADDRESS_WIDTH:0] _m_axis_raddr = 'h00; -reg [ADDRESS_WIDTH:0] _m_axis_raddr_next; -wire [ADDRESS_WIDTH:0] _m_axis_waddr; - -assign s_axis_waddr = _s_axis_waddr[ADDRESS_WIDTH-1:0]; -assign m_axis_raddr = _m_axis_raddr[ADDRESS_WIDTH-1:0]; - -always @(*) -begin - if (s_axis_ready && s_axis_valid) - _s_axis_waddr_next <= _s_axis_waddr + 1'b1; - else - _s_axis_waddr_next <= _s_axis_waddr; -end - -always @(posedge s_axis_aclk) -begin - if (s_axis_aresetn == 1'b0) begin - _s_axis_waddr <= 'h00; - end else begin - _s_axis_waddr <= _s_axis_waddr_next; - end -end - -always @(*) -begin - if (m_axis_ready && m_axis_valid) - _m_axis_raddr_next <= _m_axis_raddr + 1'b1; - else - _m_axis_raddr_next <= _m_axis_raddr; -end - -always @(posedge m_axis_aclk) -begin - if (m_axis_aresetn == 1'b0) begin - _m_axis_raddr <= 'h00; - end else begin - _m_axis_raddr <= _m_axis_raddr_next; - end -end - -sync_gray #( - .DATA_WIDTH(ADDRESS_WIDTH + 1) -) i_waddr_sync ( - .in_clk(s_axis_aclk), - .in_resetn(s_axis_aresetn), - .out_clk(m_axis_aclk), - .out_resetn(m_axis_aresetn), - .in_count(_s_axis_waddr), - .out_count(_m_axis_waddr) -); - -sync_gray #( - .DATA_WIDTH(ADDRESS_WIDTH + 1) -) i_raddr_sync ( - .in_clk(m_axis_aclk), - .in_resetn(m_axis_aresetn), - .out_clk(s_axis_aclk), - .out_resetn(s_axis_aresetn), - .in_count(_m_axis_raddr), - .out_count(_s_axis_raddr) -); - -always @(posedge s_axis_aclk) -begin - if (s_axis_aresetn == 1'b0) begin - s_axis_ready <= 1'b1; - s_axis_empty <= 1'b1; - s_axis_room <= MAX_ROOM; - end else begin - s_axis_ready <= (_s_axis_raddr[ADDRESS_WIDTH] == _s_axis_waddr_next[ADDRESS_WIDTH] || - _s_axis_raddr[ADDRESS_WIDTH-1:0] != _s_axis_waddr_next[ADDRESS_WIDTH-1:0]); - s_axis_empty <= _s_axis_raddr == _s_axis_waddr_next; - s_axis_room <= _s_axis_raddr - _s_axis_waddr_next + MAX_ROOM; - end -end - -always @(posedge m_axis_aclk) -begin - if (m_axis_aresetn == 1'b0) begin - m_axis_valid <= 1'b0; - m_axis_level <= 'h00; - end else begin - m_axis_valid <= _m_axis_waddr != _m_axis_raddr_next; - m_axis_level <= _m_axis_waddr - _m_axis_raddr_next; - end -end - -endmodule - diff --git a/library/util_axis_fifo/address_sync.v b/library/util_axis_fifo/address_sync.v deleted file mode 100644 index c6b074f25..000000000 --- a/library/util_axis_fifo/address_sync.v +++ /dev/null @@ -1,109 +0,0 @@ -// *************************************************************************** -// *************************************************************************** -// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. -// -// In this HDL repository, there are many different and unique modules, consisting -// of various HDL (Verilog or VHDL) components. The individual modules are -// developed independently, and may be accompanied by separate and unique license -// terms. -// -// The user should read each of these license terms, and understand the -// freedoms and responsibilities that he or she has by using this source/core. -// -// This core is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -// A PARTICULAR PURPOSE. -// -// Redistribution and use of source or resulting binaries, with or without modification -// of this file, are permitted under one of the following two license terms: -// -// 1. The GNU General Public License version 2 as published by the -// Free Software Foundation, which can be found in the top level directory -// of this repository (LICENSE_GPL2), and also online at: -// -// -// OR -// -// 2. An ADI specific BSD license, which can be found in the top level directory -// of this repository (LICENSE_ADIBSD), and also on-line at: -// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD -// This will allow to generate bit files and not release the source code, -// as long as it attaches to an ADI device. -// -// *************************************************************************** -// *************************************************************************** - -`timescale 1ns/100ps - -module fifo_address_sync #( - parameter ADDRESS_WIDTH = 4 -) ( - input clk, - input resetn, - - input m_axis_ready, - output reg m_axis_valid, - output reg [ADDRESS_WIDTH-1:0] m_axis_raddr, - output [ADDRESS_WIDTH:0] m_axis_level, - - output reg s_axis_ready, - input s_axis_valid, - output reg s_axis_empty, - output reg [ADDRESS_WIDTH-1:0] s_axis_waddr, - output [ADDRESS_WIDTH:0] s_axis_room -); - -localparam MAX_ROOM = {1'b1,{ADDRESS_WIDTH{1'b0}}}; - -reg [ADDRESS_WIDTH:0] room = MAX_ROOM; -reg [ADDRESS_WIDTH:0] level = 'h00; -reg [ADDRESS_WIDTH:0] level_next; - -assign s_axis_room = room; -assign m_axis_level = level; - -wire read = m_axis_ready & m_axis_valid; -wire write = s_axis_ready & s_axis_valid; - -always @(posedge clk) -begin - if (resetn == 1'b0) begin - s_axis_waddr <= 'h00; - m_axis_raddr <= 'h00; - end else begin - if (write) - s_axis_waddr <= s_axis_waddr + 1'b1; - if (read) - m_axis_raddr <= m_axis_raddr + 1'b1; - end -end - -always @(*) -begin - if (read & ~write) - level_next <= level - 1'b1; - else if (~read & write) - level_next <= level + 1'b1; - else - level_next <= level; -end - -always @(posedge clk) -begin - if (resetn == 1'b0) begin - m_axis_valid <= 1'b0; - s_axis_ready <= 1'b0; - level <= 'h00; - room <= MAX_ROOM; - s_axis_empty <= 'h00; - end else begin - level <= level_next; - room <= MAX_ROOM - level_next; - m_axis_valid <= level_next != 0; - s_axis_ready <= level_next != MAX_ROOM; - s_axis_empty <= level_next == 0; - end -end - -endmodule - diff --git a/library/util_axis_fifo/util_axis_fifo.v b/library/util_axis_fifo/util_axis_fifo.v index a62ad2814..efe28cc1e 100644 --- a/library/util_axis_fifo/util_axis_fifo.v +++ b/library/util_axis_fifo/util_axis_fifo.v @@ -32,107 +32,132 @@ // // *************************************************************************** // *************************************************************************** - -`timescale 1ns/100ps +`timescale 1ns/1ps module util_axis_fifo #( parameter DATA_WIDTH = 64, + parameter ADDRESS_WIDTH = 5, parameter ASYNC_CLK = 1, - parameter ADDRESS_WIDTH = 4, - parameter S_AXIS_REGISTERED = 1 + parameter M_AXIS_REGISTERED = 1 ) ( input m_axis_aclk, input m_axis_aresetn, input m_axis_ready, output m_axis_valid, output [DATA_WIDTH-1:0] m_axis_data, - output [ADDRESS_WIDTH:0] m_axis_level, + output [ADDRESS_WIDTH-1:0] m_axis_level, + output m_axis_empty, input s_axis_aclk, input s_axis_aresetn, output s_axis_ready, input s_axis_valid, input [DATA_WIDTH-1:0] s_axis_data, - output s_axis_empty, - output [ADDRESS_WIDTH:0] s_axis_room + output [ADDRESS_WIDTH-1:0] s_axis_room, + output s_axis_full ); -generate if (ADDRESS_WIDTH == 0) begin +generate if (ADDRESS_WIDTH == 0) begin : zerodeep /* it's not a real FIFO, just a 1 stage pipeline */ - reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram; - reg s_axis_waddr = 1'b0; - reg m_axis_raddr = 1'b0; + if (ASYNC_CLK) begin - wire m_axis_waddr; - wire s_axis_raddr; + reg [DATA_WIDTH-1:0] cdc_sync_fifo_ram; + reg s_axis_waddr = 1'b0; + reg m_axis_raddr = 1'b0; - sync_bits #( - .NUM_OF_BITS(1), - .ASYNC_CLK(ASYNC_CLK) - ) i_waddr_sync ( - .out_clk(m_axis_aclk), - .out_resetn(m_axis_aresetn), - .in_bits(s_axis_waddr), - .out_bits(m_axis_waddr) - ); + wire m_axis_waddr; + wire 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_bits(m_axis_raddr), - .out_bits(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_bits(s_axis_waddr), + .out_bits(m_axis_waddr) + ); - 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; + sync_bits #( + .NUM_OF_BITS(1), + .ASYNC_CLK(ASYNC_CLK) + ) i_raddr_sync ( + .out_clk(s_axis_aclk), + .out_resetn(s_axis_aresetn), + .in_bits(m_axis_raddr), + .out_bits(s_axis_raddr) + ); - 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 + assign m_axis_valid = m_axis_raddr != m_axis_waddr; + assign m_axis_level = ~m_axis_ready; + assign s_axis_ready = s_axis_raddr == s_axis_waddr; + assign s_axis_empty = ~s_axis_valid; + assign s_axis_room = s_axis_ready; - 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_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 if (s_axis_ready & s_axis_valid) begin + s_axis_waddr <= s_axis_waddr + 1'b1; + 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; + end + end + + assign m_axis_data = cdc_sync_fifo_ram; + + end else begin /* !ASYNC_CLK */ + + // Note: In this mode, the write and read interface must have a symmetric + // aspect ratio + reg [DATA_WIDTH-1:0] axis_data_d; + reg axis_valid_d; + + always @(posedge s_axis_aclk) begin + if (!s_axis_aresetn) begin + axis_data_d <= {DATA_WIDTH{1'b0}}; + axis_valid_d <= 1'b0; + end else if (s_axis_ready) begin + axis_data_d <= s_axis_data; + axis_valid_d <= s_axis_valid; end end + + assign m_axis_data = axis_data_d; + assign m_axis_valid = axis_valid_d; + assign s_axis_ready = m_axis_ready | ~m_axis_valid; + assign m_axis_empty = 1'b0; + assign m_axis_level = 1'b0; + assign s_axis_full = 1'b0; + assign s_axis_room = 1'b0; + 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; - end - end - - assign m_axis_data = cdc_sync_fifo_ram; - -end else begin - - reg [DATA_WIDTH-1:0] ram[0:2**ADDRESS_WIDTH-1]; +end else begin : fifo /* ADDRESS_WIDTH != 0 - this is a real FIFO implementation */ 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:0] _m_axis_level; wire s_mem_write; wire m_mem_read; - reg valid; + reg valid = 1'b0; + /* Control for first falls through */ always @(posedge m_axis_aclk) begin if (m_axis_aresetn == 1'b0) begin valid <= 1'b0; @@ -147,29 +172,29 @@ end else begin 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 + util_axis_fifo_address_generator #( + .ASYNC_CLK(ASYNC_CLK), + .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), + .m_axis_empty(m_axis_empty), + .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_full(s_axis_full), + .s_axis_waddr(s_axis_waddr), + .s_axis_room(s_axis_room) + ); - // The assumption is that in this mode the S_AXIS_REGISTERED is 1 - - 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), - - .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) - ); + if (ASYNC_CLK == 1) begin : async_clocks /* Asynchronous WRITE/READ clocks */ + // The assumption is that in this mode the M_AXIS_REGISTERED is 1 // When the clocks are asynchronous instantiate a block RAM // regardless of the requested size to make sure we threat the // clock crossing correctly @@ -189,29 +214,10 @@ end else begin assign _m_axis_ready = ~valid || m_axis_ready; assign m_axis_valid = valid; - // the util_axis_fifo is functioning in 'first write fall through' mode, - // which means that we need to assure that the value of the level reflects - // the actual FIFO level plus the available data, which sits on the bus - assign m_axis_level = (m_axis_valid) ? _m_axis_level + 1'b1 : _m_axis_level; - end else begin + end else begin : sync_clocks /* Synchronous WRITE/READ clocks */ - 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) - ); + reg [DATA_WIDTH-1:0] ram[0:2**ADDRESS_WIDTH-1]; // When the clocks are synchronous use behavioral modeling for the SDP RAM // Let the synthesizer decide what to infer (distributed or block RAM) @@ -220,7 +226,7 @@ end else begin ram[s_axis_waddr] <= s_axis_data; end - if (S_AXIS_REGISTERED == 1) begin + if (M_AXIS_REGISTERED == 1) begin reg [DATA_WIDTH-1:0] data; @@ -240,9 +246,8 @@ end else begin assign m_axis_data = ram[m_axis_raddr]; end - end - -end endgenerate +end /* fifo */ +endgenerate endmodule diff --git a/library/util_axis_fifo/util_axis_fifo_address_generator.v b/library/util_axis_fifo/util_axis_fifo_address_generator.v new file mode 100644 index 000000000..4d2494001 --- /dev/null +++ b/library/util_axis_fifo/util_axis_fifo_address_generator.v @@ -0,0 +1,187 @@ +// *************************************************************************** +// *************************************************************************** +// Copyright 2014 - 2017 (c) Analog Devices, Inc. All rights reserved. +// +// In this HDL repository, there are many different and unique modules, consisting +// of various HDL (Verilog or VHDL) components. The individual modules are +// developed independently, and may be accompanied by separate and unique license +// terms. +// +// The user should read each of these license terms, and understand the +// freedoms and responsibilities that he or she has by using this source/core. +// +// This core is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +// A PARTICULAR PURPOSE. +// +// Redistribution and use of source or resulting binaries, with or without modification +// of this file, are permitted under one of the following two license terms: +// +// 1. The GNU General Public License version 2 as published by the +// Free Software Foundation, which can be found in the top level directory +// of this repository (LICENSE_GPL2), and also online at: +// +// +// OR +// +// 2. An ADI specific BSD license, which can be found in the top level directory +// of this repository (LICENSE_ADIBSD), and also on-line at: +// https://github.com/analogdevicesinc/hdl/blob/master/LICENSE_ADIBSD +// This will allow to generate bit files and not release the source code, +// as long as it attaches to an ADI device. +// +// *************************************************************************** +// *************************************************************************** +`timescale 1ns/1ps + +module util_axis_fifo_address_generator #( + parameter ASYNC_CLK = 0, // single or double clocked FIFO + parameter ADDRESS_WIDTH = 4 // address width, effective FIFO depth +) ( + // Read interface - Sink side + + input m_axis_aclk, + input m_axis_aresetn, + input m_axis_ready, + output m_axis_valid, + output m_axis_empty, + output [ADDRESS_WIDTH-1:0] m_axis_raddr, + output [ADDRESS_WIDTH-1:0] m_axis_level, + + // Write interface - Source side + + input s_axis_aclk, + input s_axis_aresetn, + output s_axis_ready, + input s_axis_valid, + output s_axis_full, + output [ADDRESS_WIDTH-1:0] s_axis_waddr, + output [ADDRESS_WIDTH-1:0] s_axis_room +); + +//------------------------------------------------------------------------------ +// local parameters +//------------------------------------------------------------------------------ + +localparam FIFO_DEPTH = {ADDRESS_WIDTH{1'b1}}; + +//------------------------------------------------------------------------------ +// registers +//------------------------------------------------------------------------------ + +// Definition of address counters +// All the counters are wider with one bit to indicate wraparounds +reg [ADDRESS_WIDTH:0] s_axis_waddr_reg = 'h0; +reg [ADDRESS_WIDTH:0] m_axis_raddr_reg = 'h0; + +//------------------------------------------------------------------------------ +// wires +//------------------------------------------------------------------------------ + +wire [ADDRESS_WIDTH:0] s_axis_raddr_reg; +wire [ADDRESS_WIDTH:0] m_axis_waddr_reg; + +wire s_axis_write_s; +wire s_axis_ready_s; + +wire m_axis_read_s; +wire m_axis_valid_s; +wire [ADDRESS_WIDTH-1:0] m_axis_level_s; + +//------------------------------------------------------------------------------ +// Write address counter +//------------------------------------------------------------------------------ + +assign s_axis_write_s = s_axis_ready && s_axis_valid; +always @(posedge s_axis_aclk) +begin + if (!s_axis_aresetn) + s_axis_waddr_reg <= 'h0; + else + if (s_axis_write_s) + s_axis_waddr_reg <= s_axis_waddr_reg + 1'b1; +end + +//------------------------------------------------------------------------------ +// Read address counter +//------------------------------------------------------------------------------ + +assign m_axis_read_s = m_axis_ready && m_axis_valid; +always @(posedge m_axis_aclk) +begin + if (!m_axis_aresetn) + m_axis_raddr_reg <= 'h0; + else + if (m_axis_read_s) + m_axis_raddr_reg <= m_axis_raddr_reg + 1'b1; +end + +//------------------------------------------------------------------------------ +// Output assignments +//------------------------------------------------------------------------------ + +assign s_axis_waddr = s_axis_waddr_reg[ADDRESS_WIDTH-1:0]; +assign m_axis_raddr = m_axis_raddr_reg[ADDRESS_WIDTH-1:0]; + +//------------------------------------------------------------------------------ +// CDC circuits for double clock configuration +//------------------------------------------------------------------------------ + +generate if (ASYNC_CLK == 1) begin : g_async_clock + // CDC transfer of the write pointer to the read clock domain + sync_gray #( + .DATA_WIDTH(ADDRESS_WIDTH + 1) + ) i_waddr_sync_gray ( + .in_clk(s_axis_aclk), + .in_resetn(s_axis_aresetn), + .out_clk(m_axis_aclk), + .out_resetn(m_axis_aresetn), + .in_count(s_axis_waddr_reg), + .out_count(m_axis_waddr_reg) + ); + + // CDC transfer of the read pointer to the write clock domain + sync_gray #( + .DATA_WIDTH(ADDRESS_WIDTH + 1) + ) i_raddr_sync_gray ( + .in_clk(m_axis_aclk), + .in_resetn(m_axis_aresetn), + .out_clk(s_axis_aclk), + .out_resetn(s_axis_aresetn), + .in_count(m_axis_raddr_reg), + .out_count(s_axis_raddr_reg) + ); +end else begin + assign m_axis_waddr_reg = s_axis_waddr_reg; + assign s_axis_raddr_reg = m_axis_raddr_reg; +end +endgenerate + +//------------------------------------------------------------------------------ +// FIFO write logic - upstream +// +// s_axis_full - FIFO is full if next write pointer equal to read pointer +// s_axis_ready - FIFO is always ready, unless it's full +// +//------------------------------------------------------------------------------ + +wire [ADDRESS_WIDTH:0] s_axis_fifo_fill = s_axis_waddr_reg - s_axis_raddr_reg; +assign s_axis_full = (s_axis_fifo_fill == { 1'b1, {ADDRESS_WIDTH-1{1'b0}}}); +assign s_axis_ready = ~s_axis_full; +assign s_axis_room = ~s_axis_fifo_fill; + +//------------------------------------------------------------------------------ +// FIFO read logic - downstream +// +// m_axis_empty - FIFO is empty if read pointer equal to write pointer +// m_axis_valid - FIFO has a valid output data, if it's not empty +// +//------------------------------------------------------------------------------ + +wire [ADDRESS_WIDTH:0] m_axis_fifo_fill = m_axis_waddr_reg - m_axis_raddr_reg; +assign m_axis_empty = m_axis_fifo_fill == 0; +assign m_axis_valid = ~m_axis_empty; +assign m_axis_level = m_axis_fifo_fill; + +endmodule + diff --git a/library/util_axis_fifo/util_axis_fifo_ip.tcl b/library/util_axis_fifo/util_axis_fifo_ip.tcl index 8902ce156..bfe85072f 100644 --- a/library/util_axis_fifo/util_axis_fifo_ip.tcl +++ b/library/util_axis_fifo/util_axis_fifo_ip.tcl @@ -4,10 +4,9 @@ source $ad_hdl_dir/library/scripts/adi_ip_xilinx.tcl adi_ip_create util_axis_fifo adi_ip_files util_axis_fifo [list \ - "address_gray.v" \ - "address_gray_pipelined.v" \ - "address_sync.v" \ + "util_axis_fifo_address_generator.v" \ "../common/ad_mem.v" \ + "../common/ad_mem_asym.v" \ "util_axis_fifo.v" \ ] @@ -38,4 +37,6 @@ adi_add_bus "m_axis" "master" \ adi_add_bus_clock "m_axis_aclk" "m_axis" "m_axis_aresetn" adi_add_bus_clock "s_axis_aclk" "s_axis" "m_axis_aresetn" +## TODO: Validate RD_ADDRESS_WIDTH + ipx::save_core [ipx::current_core]