From 85a7cebc0e5b592f11873fcd9bd7f951816d482e Mon Sep 17 00:00:00 2001 From: Istvan Csomortani Date: Fri, 4 Aug 2017 10:19:12 +0100 Subject: [PATCH] axi_dacfifo: Major update and redesign Redesign the axi_dacfifo, to increase the supported datarates. Major modifications: + The FIFO consist of two module: WRITE and READ. The axi_dacfifo_dac was deprecated. + Both the AXI write and AXI read transaction are controlled by two FSM, to increase redability of the code. + Support all the possible burst lengths [0..225], handles the last fractional burst on both sides correctly. + Common reset architecture throughout the design, all the internal registers and memories are reset on the posedge of dma_xfer_req + Delete all Altera related sources, for Altera projects avl_dacfifo should be used. WIP: foobar [WIP]axi_dacfifo: Update axi_dacfifo: Few minor updates, almost working state --- library/xilinx/axi_dacfifo/Makefile | 3 +- library/xilinx/axi_dacfifo/axi_dacfifo.v | 41 +- .../axi_dacfifo/axi_dacfifo_address_buffer.v | 78 +++ .../xilinx/axi_dacfifo/axi_dacfifo_constr.sdc | 14 - .../xilinx/axi_dacfifo/axi_dacfifo_constr.xdc | 38 +- library/xilinx/axi_dacfifo/axi_dacfifo_dac.v | 353 ------------- library/xilinx/axi_dacfifo/axi_dacfifo_hw.tcl | 100 ---- library/xilinx/axi_dacfifo/axi_dacfifo_ip.tcl | 8 +- library/xilinx/axi_dacfifo/axi_dacfifo_rd.v | 480 ++++++++++++++---- library/xilinx/axi_dacfifo/axi_dacfifo_wr.v | 342 ++++++++----- 10 files changed, 691 insertions(+), 766 deletions(-) create mode 100644 library/xilinx/axi_dacfifo/axi_dacfifo_address_buffer.v delete mode 100644 library/xilinx/axi_dacfifo/axi_dacfifo_constr.sdc delete mode 100644 library/xilinx/axi_dacfifo/axi_dacfifo_dac.v delete mode 100644 library/xilinx/axi_dacfifo/axi_dacfifo_hw.tcl diff --git a/library/xilinx/axi_dacfifo/Makefile b/library/xilinx/axi_dacfifo/Makefile index 1612d52f6..17d378010 100644 --- a/library/xilinx/axi_dacfifo/Makefile +++ b/library/xilinx/axi_dacfifo/Makefile @@ -9,14 +9,15 @@ M_DEPS += ../../common/ad_axis_inf_rx.v M_DEPS += ../../common/ad_b2g.v M_DEPS += ../../common/ad_g2b.v M_DEPS += ../../common/ad_mem_asym.v +M_DEPS += ../../common/ad_mem.v M_DEPS += ../../common/util_dacfifo_bypass.v M_DEPS += ../../scripts/adi_env.tcl M_DEPS += ../../scripts/adi_ip.tcl M_DEPS += axi_dacfifo.v M_DEPS += axi_dacfifo_constr.xdc -M_DEPS += axi_dacfifo_dac.v M_DEPS += axi_dacfifo_ip.tcl M_DEPS += axi_dacfifo_rd.v +M_DEPS += axi_dacfifo_address_buffer.v M_DEPS += axi_dacfifo_wr.v M_VIVADO := vivado -mode batch -source diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo.v b/library/xilinx/axi_dacfifo/axi_dacfifo.v index eeea7a9c1..895acb49b 100644 --- a/library/xilinx/axi_dacfifo/axi_dacfifo.v +++ b/library/xilinx/axi_dacfifo/axi_dacfifo.v @@ -77,7 +77,6 @@ module axi_dacfifo #( output [ 3:0] axi_awcache, output [ 2:0] axi_awprot, output [ 3:0] axi_awqos, - output [ 3:0] axi_awuser, output [ 7:0] axi_awlen, output [ 2:0] axi_awsize, output [ 31:0] axi_awaddr, @@ -86,12 +85,10 @@ module axi_dacfifo #( output [(AXI_DATA_WIDTH-1):0] axi_wdata, output [(AXI_DATA_WIDTH/8-1):0] axi_wstrb, output axi_wlast, - output [ 3:0] axi_wuser, input axi_wready, input axi_bvalid, input [ 3:0] axi_bid, input [ 1:0] axi_bresp, - input [ 3:0] axi_buser, output axi_bready, output axi_arvalid, output [ 3:0] axi_arid, @@ -100,20 +97,17 @@ module axi_dacfifo #( output [ 3:0] axi_arcache, output [ 2:0] axi_arprot, output [ 3:0] axi_arqos, - output [ 3:0] axi_aruser, output [ 7:0] axi_arlen, output [ 2:0] axi_arsize, output [ 31:0] axi_araddr, input axi_arready, input axi_rvalid, input [ 3:0] axi_rid, - input [ 3:0] axi_ruser, input [ 1:0] axi_rresp, input axi_rlast, input [(AXI_DATA_WIDTH-1):0] axi_rdata, output axi_rready); - localparam FIFO_BYPASS = (DAC_DATA_WIDTH == DMA_DATA_WIDTH) ? 1 : 0; reg dma_bypass_m1 = 1'b0; @@ -123,14 +117,12 @@ module axi_dacfifo #( reg dac_xfer_out_m1 = 1'b0; reg dac_xfer_out_bypass = 1'b0; - // internal signals - wire [(AXI_DATA_WIDTH-1):0] axi_rd_data_s; wire axi_rd_ready_s; wire axi_rd_valid_s; wire axi_xfer_req_s; - wire [31:0] axi_last_addr_s; - wire [ 7:0] axi_last_beats_s; + (* dont_touch = "true" *) wire [31:0] axi_last_addr_s; + (* dont_touch = "true" *) wire [ 7:0] axi_last_beats_s; wire axi_dlast_s; wire [ 3:0] dma_last_beats_s; wire [(DAC_DATA_WIDTH-1):0] dac_data_fifo_s; @@ -147,9 +139,10 @@ module axi_dacfifo #( .AXI_LENGTH (AXI_LENGTH), .AXI_ADDRESS (AXI_ADDRESS), .AXI_ADDRESS_LIMIT (AXI_ADDRESS_LIMIT), - .DMA_MEM_ADDRESS_WIDTH (14) + .DMA_MEM_ADDRESS_WIDTH (12) ) i_wr ( .dma_clk (dma_clk), + .dma_rst (dma_rst), .dma_data (dma_data), .dma_ready (dma_ready), .dma_ready_out (dma_ready_wr_s), @@ -169,7 +162,6 @@ module axi_dacfifo #( .axi_awcache (axi_awcache), .axi_awprot (axi_awprot), .axi_awqos (axi_awqos), - .axi_awuser (axi_awuser), .axi_awlen (axi_awlen), .axi_awsize (axi_awsize), .axi_awaddr (axi_awaddr), @@ -178,12 +170,10 @@ module axi_dacfifo #( .axi_wdata (axi_wdata), .axi_wstrb (axi_wstrb), .axi_wlast (axi_wlast), - .axi_wuser (axi_wuser), .axi_wready (axi_wready), .axi_bvalid (axi_bvalid), .axi_bid (axi_bid), .axi_bresp (axi_bresp), - .axi_buser (axi_buser), .axi_bready (axi_bready), .axi_werror (axi_werror)); @@ -191,7 +181,9 @@ module axi_dacfifo #( .AXI_DATA_WIDTH (AXI_DATA_WIDTH), .AXI_SIZE (AXI_SIZE), .AXI_LENGTH (AXI_LENGTH), - .AXI_ADDRESS (AXI_ADDRESS) + .AXI_ADDRESS (AXI_ADDRESS), + .DAC_DATA_WIDTH (DAC_DATA_WIDTH), + .DAC_MEM_ADDRESS_WIDTH (12) ) i_rd ( .axi_xfer_req (axi_xfer_req_s), .axi_last_raddr (axi_last_addr_s), @@ -205,36 +197,17 @@ module axi_dacfifo #( .axi_arcache (axi_arcache), .axi_arprot (axi_arprot), .axi_arqos (axi_arqos), - .axi_aruser (axi_aruser), .axi_arlen (axi_arlen), .axi_arsize (axi_arsize), .axi_araddr (axi_araddr), .axi_arready (axi_arready), .axi_rvalid (axi_rvalid), .axi_rid (axi_rid), - .axi_ruser (axi_ruser), .axi_rresp (axi_rresp), .axi_rlast (axi_rlast), .axi_rdata (axi_rdata), .axi_rready (axi_rready), .axi_rerror (axi_rerror), - .axi_dvalid (axi_rd_valid_s), - .axi_ddata (axi_rd_data_s), - .axi_dready (axi_rd_ready_s), - .axi_dlast (axi_dlast_s)); - - axi_dacfifo_dac #( - .AXI_DATA_WIDTH (AXI_DATA_WIDTH), - .AXI_LENGTH(AXI_LENGTH), - .DAC_DATA_WIDTH (DAC_DATA_WIDTH), - .DAC_MEM_ADDRESS_WIDTH (14) - ) i_dac ( - .axi_clk (axi_clk), - .axi_dvalid (axi_rd_valid_s), - .axi_ddata (axi_rd_data_s), - .axi_dready (axi_rd_ready_s), - .axi_dlast (axi_dlast_s), - .axi_xfer_req (axi_xfer_req_s), .dma_last_beats (dma_last_beats_s), .dac_clk (dac_clk), .dac_rst (dac_rst), diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_address_buffer.v b/library/xilinx/axi_dacfifo/axi_dacfifo_address_buffer.v new file mode 100644 index 000000000..04395cfd4 --- /dev/null +++ b/library/xilinx/axi_dacfifo/axi_dacfifo_address_buffer.v @@ -0,0 +1,78 @@ +// *************************************************************************** +// *************************************************************************** +// 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 responsabilities 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 axi_dacfifo_address_buffer #( + + parameter ADDRESS_WIDTH = 4, + parameter DATA_WIDTH = 16)( + + input clk, + input rst, + input wea, + input [DATA_WIDTH-1:0] din, + + input rea, + output [DATA_WIDTH-1:0] dout); + + reg [ADDRESS_WIDTH-1:0] waddr; + reg [ADDRESS_WIDTH-1:0] raddr; + + + always @(posedge clk) begin + if (rst == 1'b1) begin + waddr <= 0; + raddr <= 0; + end else begin + waddr <= (wea == 1'b1) ? waddr + 1 : waddr; + raddr <= (rea == 1'b1) ? raddr + 1 : raddr; + end + end + + ad_mem #( + .DATA_WIDTH (DATA_WIDTH), + .ADDRESS_WIDTH (ADDRESS_WIDTH)) + i_mem ( + .clka (clk), + .wea (wea), + .addra (waddr), + .dina (din), + .clkb (clk), + .addrb (raddr), + .doutb (dout)); + +endmodule + diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_constr.sdc b/library/xilinx/axi_dacfifo/axi_dacfifo_constr.sdc deleted file mode 100644 index 49ef19dbb..000000000 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_constr.sdc +++ /dev/null @@ -1,14 +0,0 @@ - -set_false_path -to [get_registers *_xfer_req_m*[0]*] -set_false_path -to [get_registers *_xfer_last_m*[0]*] -set_false_path -to [get_registers *dac_xfer_out_m1*] -set_false_path -to [get_registers *_bypass_m1*] -set_false_path -to [get_registers *dma_rst_m1*] - -set_false_path -from [get_registers *dma_*] -to [get_registers *axi_*_m*] -set_false_path -from [get_registers *axi_*] -to [get_registers *dma_*_m*] -set_false_path -from [get_registers *dac_*] -to [get_registers *axi_*_m*] -set_false_path -from [get_registers *axi_*] -to [get_registers *dac_*_m*] -set_false_path -from [get_registers *dac_*] -to [get_registers *dma_*_m*] -set_false_path -from [get_registers *dma_*] -to [get_registers *dac_*_m*] - diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_constr.xdc b/library/xilinx/axi_dacfifo/axi_dacfifo_constr.xdc index 03fdf443c..726dc2ab8 100644 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_constr.xdc +++ b/library/xilinx/axi_dacfifo/axi_dacfifo_constr.xdc @@ -1,28 +1,34 @@ - set_property ASYNC_REG TRUE \ - [get_cells -hier *_xfer_req_m*] \ - [get_cells -hier *_xfer_last_m*] \ - [get_cells -hier *dac_xfer_out*] \ - [get_cells -hier *dac_bypass_*] \ - [get_cells -hier *dma_bypass_*] + [get_cells -hier *dma_mem_*_m*] \ + [get_cells -hier *axi_xfer_*_m*] \ + [get_cells -hier *axi_mem_*_m*] \ + [get_cells -hier *axi_dma_*_m*] \ + [get_cells -hier *dac_mem_*_m*] \ + [get_cells -hier *dac_xfer_*_m*] \ + [get_cells -hier *dac_last_*_m*] \ + [get_cells -hier *dac_bypass_m*] +set_false_path -to [get_cells -hier -filter {name =~ *_bypass_m1_reg && IS_SEQUENTIAL}] set_false_path -to [get_cells -hier -filter {name =~ *_xfer_req_m_reg[0]* && IS_SEQUENTIAL}] -set_false_path -to [get_cells -hier -filter {name =~ *_xfer_last_m_reg[0]* && IS_SEQUENTIAL}] -set_false_path -to [get_cells -hier -filter {name =~ *dac_xfer_out_m1* && IS_SEQUENTIAL}] -set_false_path -to [get_cells -hier -filter {name =~ *_bypass_m1* && IS_SEQUENTIAL}] -set_false_path -to [get_cells -hier -filter {name =~ *dma_rst_m1* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *dma_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *axi_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *axi_*_m* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *axi_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *dma_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *dma_*_m* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *dac_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *axi_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *axi_*_m* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *axi_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *dac_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *dac_*_m* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *dac_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *dma_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *dma_*_m* && IS_SEQUENTIAL}] set_false_path -from [get_cells -hier -filter {name =~ *dma_* && IS_SEQUENTIAL}] \ - -to [get_cells -hier -filter {name =~ *dac_*_m* && IS_SEQUENTIAL}] + -to [get_cells -hier -filter {name =~ *dac_*_m* && IS_SEQUENTIAL}] + +set_false_path -from [get_cells -hier -filter {name =~ *axi_mem_laddr* && IS_SEQUENTIAL}] \ + -to [get_cells -hier -filter {name =~ *dac_mem_laddr* && IS_SEQUENTIAL}] + +set_false_path -from [get_cells -hier -filter {name =~ *i_laddress_buffer*m_ram_reg* && IS_SEQUENTIAL}] \ + -to [get_cells -hier -filter {name =~ *dac_mem_raddr_reg* && IS_SEQUENTIAL}] + diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_dac.v b/library/xilinx/axi_dacfifo/axi_dacfifo_dac.v deleted file mode 100644 index d88e5a15e..000000000 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_dac.v +++ /dev/null @@ -1,353 +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 responsabilities 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 axi_dacfifo_dac #( - - parameter AXI_DATA_WIDTH = 512, - parameter AXI_LENGTH = 15, - parameter DAC_DATA_WIDTH = 64, - parameter DAC_MEM_ADDRESS_WIDTH = 8) ( - - input axi_clk, - input axi_dvalid, - input [(AXI_DATA_WIDTH-1):0] axi_ddata, - output reg axi_dready, - input axi_dlast, - input axi_xfer_req, - - input [ 3:0] dma_last_beats, - - input dac_clk, - input dac_rst, - input dac_valid, - output [(DAC_DATA_WIDTH-1):0] dac_data, - output dac_xfer_out, - output reg dac_dunf); - - - localparam MEM_RATIO = AXI_DATA_WIDTH/DAC_DATA_WIDTH; - localparam AXI_ADDRESS_WIDTH = (MEM_RATIO == 1) ? DAC_MEM_ADDRESS_WIDTH : - (MEM_RATIO == 2) ? (DAC_MEM_ADDRESS_WIDTH - 1) : - (MEM_RATIO == 4) ? (DAC_MEM_ADDRESS_WIDTH - 2) : - (DAC_MEM_ADDRESS_WIDTH - 3); - - localparam AXI_BUF_THRESHOLD_LO = 3 * (AXI_LENGTH+1); - localparam AXI_BUF_THRESHOLD_HI = {(AXI_ADDRESS_WIDTH){1'b1}} - (AXI_LENGTH+1); - localparam DAC_BUF_THRESHOLD_LO = 3 * (AXI_LENGTH+1) * MEM_RATIO; - localparam DAC_BUF_THRESHOLD_HI = {(DAC_MEM_ADDRESS_WIDTH){1'b1}} - (AXI_LENGTH+1) * MEM_RATIO; - localparam DAC_ARINCR = (AXI_LENGTH+1) * MEM_RATIO; - - // internal registers - - reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0; - reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_laddr = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_g = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr_g = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m1 = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m2 = 'd0; - reg [(AXI_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'd0; - - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr_g = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m1 = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m2 = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_m1 = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_m2 = 'd0; - reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_addr_diff = 'd0; - reg dac_mem_init = 1'b0; - reg dac_mem_init_d = 1'b0; - reg dac_mem_enable = 1'b0; - - reg [ 2:0] dac_xfer_req_m = 3'b0; - reg dac_xfer_init = 1'b0; - - reg [ 3:0] dac_last_beats = 4'b0; - reg [ 3:0] dac_last_beats_m = 4'b0; - reg [ 3:0] dac_beat_cnt = 4'b0; - reg dac_dlast = 1'b0; - reg dac_dlast_m1 = 1'b0; - reg dac_dlast_m2 = 1'b0; - reg dac_dlast_inmem = 1'b0; - reg dac_mem_valid = 1'b0; - - // internal signals - - wire [AXI_ADDRESS_WIDTH:0] axi_mem_addr_diff_s; - wire [(AXI_ADDRESS_WIDTH-1):0] axi_mem_raddr_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_b2g_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr_b2g_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m2_g2b_s; - - wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_addr_diff_s; - wire dac_xfer_init_s; - wire dac_last_axi_beats_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr_b2g_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m2_g2b_s; - wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_m2_g2b_s; - - // write interface - - always @(posedge axi_clk) begin - if (axi_xfer_req == 1'b0) begin - axi_mem_waddr <= 'd0; - axi_mem_waddr_g <= 'd0; - axi_mem_laddr <= {AXI_ADDRESS_WIDTH{1'b1}}; - end else begin - if (axi_dvalid == 1'b1) begin - axi_mem_waddr <= axi_mem_waddr + 1'b1; - axi_mem_laddr <= (axi_dlast == 1'b1) ? axi_mem_waddr : axi_mem_laddr; - end - axi_mem_waddr_g <= axi_mem_waddr_b2g_s; - axi_mem_laddr_g <= axi_mem_laddr_b2g_s; - end - end - - ad_b2g # ( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_axi_mem_waddr_b2g ( - .din (axi_mem_waddr_s), - .dout (axi_mem_waddr_b2g_s)); - - ad_b2g # ( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_axi_mem_laddr_b2g ( - .din (axi_mem_laddr_s), - .dout (axi_mem_laddr_b2g_s)); - - // scale the axi_mem_* addresses - - assign axi_mem_raddr_s = (MEM_RATIO == 1) ? axi_mem_raddr : - (MEM_RATIO == 2) ? axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):1] : - (MEM_RATIO == 4) ? axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):2] : - axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):3]; - assign axi_mem_waddr_s = (MEM_RATIO == 1) ? axi_mem_waddr : - (MEM_RATIO == 2) ? {axi_mem_waddr, 1'b0} : - (MEM_RATIO == 4) ? {axi_mem_waddr, 2'b0} : - {axi_mem_waddr, 3'b0}; - assign axi_mem_laddr_s = (MEM_RATIO == 1) ? axi_mem_laddr : - (MEM_RATIO == 2) ? {axi_mem_laddr, 1'b0} : - (MEM_RATIO == 4) ? {axi_mem_laddr, 2'b0} : - {axi_mem_laddr, 3'b0}; - - // incomming data flow control - - assign axi_mem_addr_diff_s = {1'b1, axi_mem_waddr} - axi_mem_raddr_s; - - always @(posedge axi_clk) begin - if (axi_xfer_req == 1'b0) begin - axi_mem_addr_diff <= 'd0; - axi_mem_raddr <= 'd0; - axi_mem_raddr_m1 <= 'd0; - axi_mem_raddr_m2 <= 'd0; - axi_dready <= 'd0; - end else begin - axi_mem_raddr_m1 <= dac_mem_raddr_g; - axi_mem_raddr_m2 <= axi_mem_raddr_m1; - axi_mem_raddr <= axi_mem_raddr_m2_g2b_s; - axi_mem_addr_diff <= axi_mem_addr_diff_s[AXI_ADDRESS_WIDTH-1:0]; - if (axi_mem_addr_diff >= AXI_BUF_THRESHOLD_HI) begin - axi_dready <= 1'b0; - end else begin - axi_dready <= 1'b1; - end - end - end - - ad_g2b #( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_axi_mem_raddr_m2_g2b ( - .din (axi_mem_raddr_m2), - .dout (axi_mem_raddr_m2_g2b_s)); - - // CDC for xfer_req signal - - always @(posedge dac_clk) begin - if (dac_rst == 1'b1) begin - dac_xfer_req_m <= 3'b0; - end else begin - dac_xfer_req_m <= {dac_xfer_req_m[1:0], axi_xfer_req}; - end - end - - assign dac_xfer_out = dac_xfer_req_m[2]; - assign dac_xfer_init_s = ~dac_xfer_req_m[2] & dac_xfer_req_m[1]; - - // read interface - - always @(posedge dac_clk) begin - if (dac_xfer_out == 1'b0) begin - dac_mem_init <= 1'b0; - dac_mem_init_d <= 1'b0; - dac_mem_enable <= 1'b0; - end else begin - if (dac_xfer_init == 1'b1) begin - dac_mem_init <= 1'b1; - end - if ((dac_mem_init == 1'b1) && (dac_mem_addr_diff > DAC_BUF_THRESHOLD_LO)) begin - dac_mem_init <= 1'b0; - end - dac_mem_init_d <= dac_mem_init; - // memory is ready when the initial fill up is done - dac_mem_enable <= (dac_mem_init_d & ~dac_mem_init) ? 1'b1 : dac_mem_enable; - end - dac_xfer_init <= dac_xfer_init_s; - end - - always @(posedge dac_clk) begin - if (dac_xfer_out == 1'b0) begin - dac_mem_waddr <= 'b0; - dac_mem_waddr_m1 <= 'b0; - dac_mem_waddr_m2 <= 'b0; - dac_mem_laddr <= 'b0; - dac_mem_laddr_m1 <= 'b0; - dac_mem_laddr_m2 <= 'b0; - dac_dlast <= 1'b0; - dac_dlast_m1 <= 1'b0; - dac_dlast_m2 <= 1'b0; - end else begin - dac_mem_waddr_m1 <= axi_mem_waddr_g; - dac_mem_waddr_m2 <= dac_mem_waddr_m1; - dac_mem_waddr <= dac_mem_waddr_m2_g2b_s; - dac_mem_laddr_m1 <= axi_mem_laddr_g; - dac_mem_laddr_m2 <= dac_mem_laddr_m1; - dac_mem_laddr <= dac_mem_laddr_m2_g2b_s; - dac_dlast_m1 <= axi_dlast; - dac_dlast_m2 <= dac_dlast_m1; - dac_dlast <= dac_dlast_m2; - end - end - - ad_g2b #( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_dac_mem_waddr_m2_g2b ( - .din (dac_mem_waddr_m2), - .dout (dac_mem_waddr_m2_g2b_s)); - - ad_g2b #( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_dac_mem_laddr_m2_g2b ( - .din (dac_mem_laddr_m2), - .dout (dac_mem_laddr_m2_g2b_s)); - - assign dac_mem_addr_diff_s = {1'b1, dac_mem_waddr} - dac_mem_raddr; - always @(posedge dac_clk) begin - dac_mem_valid <= (dac_mem_enable) ? dac_valid : 1'b0; - end - - // CDC for the dma_last_beats - - always @(posedge dac_clk) begin - if (dac_rst == 1'b1) begin - dac_last_beats <= 4'b0; - dac_last_beats_m <= 4'b0; - end else begin - dac_last_beats_m <= dma_last_beats; - dac_last_beats <= dac_last_beats_m; - end - end - - // If the MEM_RATIO is grater than one, it can happen that not all the DAC beats from - // an AXI beat are valid. In this case the invalid data is dropped. - // The axi_dlast indicates the last AXI beat. The valid number of DAC beats on the last AXI beat - // commes from the AXI write module. (axi_dacfifo_wr.v) - - assign dac_last_axi_beats_s = ((dac_dlast_inmem == 1'b1) && (dac_mem_raddr >= dac_mem_laddr) && (dac_mem_raddr < dac_mem_laddr + MEM_RATIO)) ? 1'b1 : 1'b0; - - always @(posedge dac_clk) begin - if (dac_xfer_out == 1'b0) begin - dac_mem_raddr <= 'd0; - dac_beat_cnt <= 'd0; - dac_dlast_inmem <= 1'b0; - end else begin - if (dac_dlast == 1'b1) begin - dac_dlast_inmem <= 1'b1; - end else if (dac_mem_raddr == dac_mem_laddr + MEM_RATIO) begin - dac_dlast_inmem <= 1'b0; - end - if (dac_mem_valid == 1'b1) begin - dac_beat_cnt <= ((dac_beat_cnt >= MEM_RATIO-1) || - ((dac_last_beats > 4'b1) && (dac_last_axi_beats_s > 1'b0) && (dac_beat_cnt == dac_last_beats-1))) ? 0 : dac_beat_cnt + 1; - dac_mem_raddr <= ((dac_last_axi_beats_s) && (dac_beat_cnt == dac_last_beats-1)) ? (dac_mem_laddr + MEM_RATIO) : dac_mem_raddr + 1'b1; - end - dac_mem_raddr_g <= dac_mem_raddr_b2g_s; - end - end - - ad_b2g # ( - .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) - ) i_dac_mem_raddr_b2g ( - .din (dac_mem_raddr), - .dout (dac_mem_raddr_b2g_s)); - - // underflow generation, there is no overflow - - always @(posedge dac_clk) begin - if(dac_xfer_out == 1'b0) begin - dac_mem_addr_diff <= 'b0; - dac_dunf <= 1'b0; - end else begin - dac_mem_addr_diff <= dac_mem_addr_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0]; - dac_dunf <= (dac_mem_addr_diff == 1'b0) ? 1'b1 : 1'b0; - end - end - - // instantiations - - ad_mem_asym #( - .A_ADDRESS_WIDTH (AXI_ADDRESS_WIDTH), - .A_DATA_WIDTH (AXI_DATA_WIDTH), - .B_ADDRESS_WIDTH (DAC_MEM_ADDRESS_WIDTH), - .B_DATA_WIDTH (DAC_DATA_WIDTH)) - i_mem_asym ( - .clka (axi_clk), - .wea (axi_dvalid), - .addra (axi_mem_waddr), - .dina (axi_ddata), - .clkb (dac_clk), - .addrb (dac_mem_raddr), - .doutb (dac_data)); - -endmodule - -// *************************************************************************** -// *************************************************************************** - diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_hw.tcl b/library/xilinx/axi_dacfifo/axi_dacfifo_hw.tcl deleted file mode 100644 index 7dc1f6e55..000000000 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_hw.tcl +++ /dev/null @@ -1,100 +0,0 @@ - -package require qsys -source ../../scripts/adi_env.tcl -source ../../scripts/adi_ip_alt.tcl - -ad_ip_create axi_dacfifo {AXI DAC FIFO Interface} -ad_ip_files axi_dacfifo [list\ - $ad_hdl_dir/library/altera/common/ad_mem_asym.v \ - $ad_hdl_dir/library/common/ad_axis_inf_rx.v \ - $ad_hdl_dir/library/common/util_dacfifo_bypass.v \ - axi_dacfifo_dac.v \ - axi_dacfifo_wr.v \ - axi_dacfifo_rd.v \ - axi_dacfifo.v \ - axi_dacfifo_constr.sdc] - -# parameters - -ad_ip_parameter DEVICE_FAMILY STRING {Arria 10} -ad_ip_parameter DAC_DATA_WIDTH INTEGER 64 -ad_ip_parameter DMA_DATA_WIDTH INTEGER 64 -ad_ip_parameter AXI_DATA_WIDTH INTEGER 512 -ad_ip_parameter AXI_SIZE INTEGER 2 -ad_ip_parameter AXI_LENGTH INTEGER 15 -ad_ip_parameter AXI_ADDRESS INTEGER 0 -ad_ip_parameter AXI_ADDRESS_LIMIT INTEGER -1 - -# interfaces - -ad_alt_intf clock dma_clk input 1 clk -ad_alt_intf reset dma_rst input 1 if_dma_clk -ad_alt_intf signal dma_valid input 1 valid -ad_alt_intf signal dma_data input DMA_DATA_WIDTH data -ad_alt_intf signal dma_ready output 1 ready -ad_alt_intf signal dma_xfer_req input 1 xfer_req -ad_alt_intf signal dma_xfer_last input 1 last - -ad_alt_intf clock dac_clk input 1 -ad_alt_intf reset dac_rst input 1 if_dac_clk -ad_alt_intf signal dac_valid input 1 valid -ad_alt_intf signal dac_data output DAC_DATA_WIDTH data -ad_alt_intf signal dac_dunf output 1 unf -ad_alt_intf signal dac_xfer_out output 1 xfer_req - -ad_alt_intf signal bypass input 1 bypass - -add_interface axi_clock clock end -add_interface_port axi_clock axi_clk clk input 1 - -add_interface axi_reset_n reset end -set_interface_property axi_reset_n associatedclock axi_clock -add_interface_port axi_reset_n axi_resetn reset_n input 1 - -add_interface m_axi axi4 start -add_interface_port m_axi axi_awvalid awvalid output 1 -add_interface_port m_axi axi_awid awid output 4 -add_interface_port m_axi axi_awburst awburst output 2 -add_interface_port m_axi axi_awlock awlock output 1 -add_interface_port m_axi axi_awcache awcache output 4 -add_interface_port m_axi axi_awprot awprot output 3 -add_interface_port m_axi axi_awqos awqos output 4 -add_interface_port m_axi axi_awuser awuser output 4 -add_interface_port m_axi axi_awlen awlen output 8 -add_interface_port m_axi axi_awsize awsize output 3 -add_interface_port m_axi axi_awaddr awaddr output 32 -add_interface_port m_axi axi_awready awready input 1 -add_interface_port m_axi axi_wvalid wvalid output 1 -add_interface_port m_axi axi_wdata wdata output AXI_DATA_WIDTH -add_interface_port m_axi axi_wstrb wstrb output AXI_DATA_WIDTH/8 -add_interface_port m_axi axi_wlast wlast output 1 -add_interface_port m_axi axi_wready wready input 1 -add_interface_port m_axi axi_bvalid bvalid input 1 -add_interface_port m_axi axi_bid bid input 4 -add_interface_port m_axi axi_bresp bresp input 2 -add_interface_port m_axi axi_buser buser input 4 -add_interface_port m_axi axi_bready bready output 1 -add_interface_port m_axi axi_arvalid arvalid output 1 -add_interface_port m_axi axi_arid arid output 4 -add_interface_port m_axi axi_arburst arburst output 2 -add_interface_port m_axi axi_arlock arlock output 1 -add_interface_port m_axi axi_arcache arcache output 4 -add_interface_port m_axi axi_arprot arprot output 3 -add_interface_port m_axi axi_arqos arqos output 4 -add_interface_port m_axi axi_aruser aruser output 4 -add_interface_port m_axi axi_arlen arlen output 8 -add_interface_port m_axi axi_arsize arsize output 3 -add_interface_port m_axi axi_araddr araddr output 32 -add_interface_port m_axi axi_arready arready input 1 -add_interface_port m_axi axi_rvalid rvalid input 1 -add_interface_port m_axi axi_rid rid input 4 -add_interface_port m_axi axi_ruser ruser input 4 -add_interface_port m_axi axi_rresp rresp input 2 -add_interface_port m_axi axi_rlast rlast input 1 -add_interface_port m_axi axi_rdata rdata input AXI_DATA_WIDTH -add_interface_port m_axi axi_rready rready output 1 - -set_interface_property m_axi associatedclock axi_clock -set_interface_property m_axi associatedreset axi_reset_n - - diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_ip.tcl b/library/xilinx/axi_dacfifo/axi_dacfifo_ip.tcl index 8db958b02..ef6722db9 100644 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_ip.tcl +++ b/library/xilinx/axi_dacfifo/axi_dacfifo_ip.tcl @@ -9,12 +9,13 @@ adi_ip_files axi_dacfifo [list \ "$ad_hdl_dir/library/common/ad_g2b.v" \ "$ad_hdl_dir/library/common/ad_b2g.v" \ "$ad_hdl_dir/library/common/ad_mem_asym.v" \ + "$ad_hdl_dir/library/common/ad_mem.v" \ "$ad_hdl_dir/library/common/ad_axis_inf_rx.v" \ "$ad_hdl_dir/library/common/util_dacfifo_bypass.v" \ "axi_dacfifo_constr.xdc" \ - "axi_dacfifo_dac.v" \ "axi_dacfifo_wr.v" \ "axi_dacfifo_rd.v" \ + "axi_dacfifo_address_buffer.v" \ "axi_dacfifo.v"] adi_ip_properties_lite axi_dacfifo @@ -27,7 +28,6 @@ ipx::infer_bus_interface {\ axi_awcache \ axi_awprot \ axi_awqos \ - axi_awuser \ axi_awlen \ axi_awsize \ axi_awaddr \ @@ -36,12 +36,10 @@ ipx::infer_bus_interface {\ axi_wdata \ axi_wstrb \ axi_wlast \ - axi_wuser \ axi_wready \ axi_bvalid \ axi_bid \ axi_bresp \ - axi_buser \ axi_bready \ axi_arvalid \ axi_arid \ @@ -50,14 +48,12 @@ ipx::infer_bus_interface {\ axi_arcache \ axi_arprot \ axi_arqos \ - axi_aruser \ axi_arlen \ axi_arsize \ axi_araddr \ axi_arready \ axi_rvalid \ axi_rid \ - axi_ruser \ axi_rresp \ axi_rlast \ axi_rdata \ diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_rd.v b/library/xilinx/axi_dacfifo/axi_dacfifo_rd.v index 0e37c07de..77ea1ede7 100644 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_rd.v +++ b/library/xilinx/axi_dacfifo/axi_dacfifo_rd.v @@ -40,115 +40,200 @@ module axi_dacfifo_rd #( parameter AXI_DATA_WIDTH = 512, parameter AXI_SIZE = 2, parameter AXI_LENGTH = 15, - parameter AXI_ADDRESS = 32'h00000000) ( + parameter AXI_ADDRESS = 32'h00000000, + parameter DAC_DATA_WIDTH = 64, + parameter DAC_MEM_ADDRESS_WIDTH = 8) ( // xfer last for read/write synchronization - input axi_xfer_req, - input [31:0] axi_last_raddr, - input [ 7:0] axi_last_beats, + input axi_xfer_req, + input [31:0] axi_last_raddr, + input [ 7:0] axi_last_beats, // axi read address and read data channels - input axi_clk, - input axi_resetn, - output reg axi_arvalid, - output [ 3:0] axi_arid, - output [ 1:0] axi_arburst, - output axi_arlock, - output [ 3:0] axi_arcache, - output [ 2:0] axi_arprot, - output [ 3:0] axi_arqos, - output [ 3:0] axi_aruser, - output [ 7:0] axi_arlen, - output [ 2:0] axi_arsize, - output reg [31:0] axi_araddr, - input axi_arready, - input axi_rvalid, - input [ 3:0] axi_rid, - input [ 3:0] axi_ruser, - input [ 1:0] axi_rresp, - input axi_rlast, + input axi_clk, + input axi_resetn, + output reg axi_arvalid, + output [ 3:0] axi_arid, + output [ 1:0] axi_arburst, + output axi_arlock, + output [ 3:0] axi_arcache, + output [ 2:0] axi_arprot, + output [ 3:0] axi_arqos, + output [ 7:0] axi_arlen, + output [ 2:0] axi_arsize, + output reg [31:0] axi_araddr, + input axi_arready, + input axi_rvalid, + input [ 3:0] axi_rid, + input [ 1:0] axi_rresp, + input axi_rlast, input [(AXI_DATA_WIDTH-1):0] axi_rdata, - output reg axi_rready, + output reg axi_rready, // axi status - output reg axi_rerror, + output reg axi_rerror, - // fifo interface + // DAC interface - output reg axi_dvalid, - output reg [(AXI_DATA_WIDTH-1):0] axi_ddata, - input axi_dready, - output reg axi_dlast); + input [ 3:0] dma_last_beats, + + input dac_clk, + input dac_rst, + input dac_valid, + output [(DAC_DATA_WIDTH-1):0] dac_data, + output dac_xfer_out, + output reg dac_dunf); localparam AXI_BYTE_WIDTH = AXI_DATA_WIDTH/8; - localparam AXI_AWINCR = (AXI_LENGTH + 1) * AXI_BYTE_WIDTH; + localparam AXI_ARINCR = (AXI_LENGTH + 1) * AXI_BYTE_WIDTH; + localparam MEM_RATIO = AXI_DATA_WIDTH/DAC_DATA_WIDTH; + localparam AXI_MEM_ADDRESS_WIDTH = (MEM_RATIO == 1) ? DAC_MEM_ADDRESS_WIDTH : + (MEM_RATIO == 2) ? (DAC_MEM_ADDRESS_WIDTH - 1) : + (MEM_RATIO == 4) ? (DAC_MEM_ADDRESS_WIDTH - 2) : + (DAC_MEM_ADDRESS_WIDTH - 3); + localparam AXI_BUF_THRESHOLD_HI = 2 * (AXI_LENGTH+1); + localparam DAC_BUF_THRESHOLD_HI = 2 * (AXI_LENGTH+1) * MEM_RATIO; + + localparam IDLE = 5'b00001; + localparam XFER_STAGING = 5'b00010; + localparam XFER_FULL_BURST = 5'b00100; + localparam XFER_PARTIAL_BURST = 5'b01000; + localparam XFER_END = 5'b10000; // internal registers - reg axi_rnext = 1'b0; - reg axi_ractive = 1'b0; - reg [ 31:0] axi_araddr_prev = 32'b0; - reg [ 1:0] axi_xfer_req_m = 2'b0; - reg [ 7:0] axi_last_beats_cntr = 8'b0; + reg axi_ractive = 1'b0; + reg [ 1:0] axi_xfer_req_m = 2'b0; + reg [ 7:0] axi_last_beats_cntr = 8'b0; + reg axi_data_req = 1'b0; + reg [(AXI_DATA_WIDTH-1):0] axi_ddata = 'b0; + reg axi_dlast = 1'b0; + reg axi_dvalid = 1'b0; + reg [ 4:0] axi_read_state = 5'b0; + reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0; + reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_g = 'd0; + reg axi_mem_laddr_toggle = 1'b0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m1 = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m2 = 'd0; + reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'd0; + reg [31:0] axi_araddr_prev = 'd0; + + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr_g = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m1 = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m2 = 'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr = 'd0; + reg [ 3:0] dac_mem_laddr_toggle_m = 4'd0; + reg [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_b = 'd0; + reg dac_mem_valid = 1'b0; + reg dac_mem_enable = 1'b0; + reg [ 2:0] dac_xfer_req_m = 3'b0; + reg [ 3:0] dac_last_beats = 4'b0; + reg [ 3:0] dac_last_beats_m = 4'b0; + reg dac_dlast = 1'b0; + reg dac_dlast_m1 = 1'b0; + reg dac_dlast_m2 = 1'b0; // internal signals - wire axi_ready_s; - wire axi_xfer_req_init; - wire axi_dvalid_s; - wire axi_dlast_s; - wire [ 8:0] axi_last_beats_s; + wire axi_fifo_reset_s; + wire axi_dvalid_s; + wire axi_dlast_s; + wire [ AXI_MEM_ADDRESS_WIDTH:0] axi_mem_addr_diff_s; + wire [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_b2g_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_laddr_b2g_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_m2_g2b_s; - assign axi_ready_s = (~axi_arvalid | axi_arready) & axi_dready; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_raddr_b2g_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_waddr_m2_g2b_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_m2_g2b_s; + wire [ DAC_MEM_ADDRESS_WIDTH:0] dac_mem_addr_diff_s; + wire [(DAC_MEM_ADDRESS_WIDTH-1):0] dac_mem_laddr_s; + + // Asymmetric memory to transfer data from AXI_MM interface to DAC FIFO + // interface + + ad_mem_asym #( + .A_ADDRESS_WIDTH (AXI_MEM_ADDRESS_WIDTH), + .A_DATA_WIDTH (AXI_DATA_WIDTH), + .B_ADDRESS_WIDTH (DAC_MEM_ADDRESS_WIDTH), + .B_DATA_WIDTH (DAC_DATA_WIDTH)) + i_mem_asym ( + .clka (axi_clk), + .wea (axi_dvalid_s), + .addra (axi_mem_waddr), + .dina (axi_rdata), + .clkb (dac_clk), + .addrb (dac_mem_raddr), + .doutb (dac_data)); + + // reset signals + + assign axi_fifo_reset_s = (axi_resetn == 1'b0) || (axi_xfer_req == 1'b0); + assign dac_fifo_reset_s = (dac_rst == 1'b1) || (dac_xfer_req_m[2] == 1'b0); + + // FSM to generate the all the AXI Read transactions always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_rnext <= 1'b0; - axi_ractive <= 1'b0; - axi_xfer_req_m <= 2'b0; + if (axi_fifo_reset_s == 1'b1) begin + axi_read_state <= IDLE; end else begin - if (axi_ractive == 1'b1) begin - axi_rnext <= 1'b0; - if ((axi_rvalid == 1'b1) && (axi_rlast == 1'b1)) begin - axi_ractive <= 1'b0; + case (axi_read_state) + IDLE : begin + if (axi_data_req == 1'b1) begin + axi_read_state <= XFER_STAGING; + end else begin + axi_read_state <= IDLE; + end end - end else if ((axi_ready_s == 1'b1)) begin - axi_rnext <= axi_xfer_req; - axi_ractive <= axi_xfer_req; - end - axi_xfer_req_m <= {axi_xfer_req_m[0], axi_xfer_req}; + XFER_STAGING : begin + if (axi_araddr + AXI_ARINCR <= axi_last_raddr) begin + axi_read_state <= XFER_FULL_BURST; + end else begin + axi_read_state <= XFER_PARTIAL_BURST; + end + end + XFER_FULL_BURST : begin + if (axi_rready && axi_rvalid && axi_rlast) begin + if (axi_araddr_prev == axi_last_raddr) begin + axi_read_state <= XFER_END; + end else begin + axi_read_state <= IDLE; + end + end else begin + axi_read_state <= XFER_FULL_BURST; + end + end + XFER_PARTIAL_BURST : begin + if (axi_rready && axi_rvalid && axi_rlast) begin + axi_read_state <= XFER_END; + end else begin + axi_read_state <= XFER_PARTIAL_BURST; + end + end + XFER_END : begin + axi_read_state <= IDLE; + end + default : begin + axi_read_state <= IDLE; + end + endcase end end - assign axi_xfer_req_init = axi_xfer_req_m[0] & ~axi_xfer_req_m[1]; + // AXI read address channel always @(posedge axi_clk) begin - if ((axi_resetn == 1'b0) || (axi_xfer_req == 1'b0)) begin - axi_last_beats_cntr <= 0; - end else begin - if ((axi_rready == 1'b1) && (axi_rvalid == 1'b1)) begin - axi_last_beats_cntr <= (axi_rlast == 1'b1) ? 0 : axi_last_beats_cntr + 1; - end - end - end - - // address channel - - assign axi_arid = 4'b0000; - assign axi_arburst = 2'b01; - assign axi_arlock = 1'b0; - assign axi_arcache = 4'b0010; - assign axi_arprot = 3'b000; - assign axi_arqos = 4'b0000; - assign axi_aruser = 4'b0001; - assign axi_arlen = AXI_LENGTH; - assign axi_arsize = AXI_SIZE; - - always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin + if (axi_fifo_reset_s == 1'b1) begin axi_arvalid <= 'd0; axi_araddr <= AXI_ADDRESS; axi_araddr_prev <= AXI_ADDRESS; @@ -158,45 +243,239 @@ module axi_dacfifo_rd #( axi_arvalid <= 1'b0; end end else begin - if (axi_rnext == 1'b1) begin + if (axi_read_state == XFER_STAGING) begin axi_arvalid <= 1'b1; end end - if ((axi_xfer_req == 1'b1) && - (axi_arvalid == 1'b1) && - (axi_arready == 1'b1)) begin - axi_araddr <= (axi_araddr >= axi_last_raddr) ? AXI_ADDRESS : axi_araddr + AXI_AWINCR; + // AXI read address generation + if ((axi_arvalid == 1'b1) && (axi_arready == 1'b1)) begin + axi_araddr <= (axi_read_state == XFER_FULL_BURST) ? (axi_araddr + AXI_ARINCR) : + (axi_read_state == XFER_PARTIAL_BURST) ? AXI_ADDRESS : axi_araddr; axi_araddr_prev <= axi_araddr; end end end - // read data channel + assign axi_arid = 4'b0000; + assign axi_arburst = 2'b01; + assign axi_arlock = 1'b0; + assign axi_arcache = 4'b0010; + assign axi_arprot = 3'b000; + assign axi_arqos = 4'b0000; + assign axi_arlen = (axi_read_state == XFER_FULL_BURST) ? AXI_LENGTH : + (axi_read_state == XFER_PARTIAL_BURST) ? axi_last_beats : AXI_LENGTH; + assign axi_arsize = AXI_SIZE; - assign axi_last_beats_s = {1'b0, axi_last_beats} - 1; - assign axi_dvalid_s = ((axi_last_beats_cntr > axi_last_beats_s) && (axi_araddr_prev == axi_last_raddr)) ? 0 : axi_rvalid & axi_rready; - assign axi_dlast_s = (axi_araddr == axi_last_raddr) ? 1 : 0; + // AXI read data channel + + assign axi_dvalid_s = axi_rvalid & axi_rready & axi_xfer_req; + assign axi_dlast_s = (axi_araddr_prev == axi_last_raddr) ? axi_rlast : 0; always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_ddata <= 'd0; + if (axi_fifo_reset_s == 1'b1) begin axi_rready <= 1'b0; - axi_dvalid <= 1'b0; + axi_rerror <= 'd0; end else begin - axi_ddata <= axi_rdata; - axi_dvalid <= axi_dvalid_s; - axi_dlast <= axi_dlast_s & axi_rlast; - if (axi_xfer_req == 1'b1) begin - axi_rready <= axi_rvalid; + axi_rready <= axi_rvalid; + axi_rerror <= axi_rvalid & axi_rresp[1]; + end + end + + // ASYNC MEM write control + + always @(posedge axi_clk) begin + if (axi_fifo_reset_s == 1'b1) begin + axi_mem_waddr <= 'd0; + axi_mem_waddr_g <= 'd0; + axi_mem_laddr <= {AXI_MEM_ADDRESS_WIDTH{1'b1}}; + axi_mem_laddr_toggle <= 0; + end else begin + if (axi_dvalid_s == 1'b1) begin + axi_mem_waddr <= axi_mem_waddr + 1'b1; + if (axi_dlast_s == 1'b1) begin + axi_mem_laddr <= axi_mem_waddr; + axi_mem_laddr_toggle <= ~axi_mem_laddr_toggle; + end + end + axi_mem_waddr_g <= axi_mem_waddr_b2g_s; + end + end + + ad_b2g # ( + .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) + ) i_axi_mem_waddr_b2g ( + .din (axi_mem_waddr_s), + .dout (axi_mem_waddr_b2g_s)); + + assign axi_mem_raddr_s = (MEM_RATIO == 1) ? axi_mem_raddr : + (MEM_RATIO == 2) ? axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):1] : + (MEM_RATIO == 4) ? axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):2] : + axi_mem_raddr[(DAC_MEM_ADDRESS_WIDTH-1):3]; + assign axi_mem_waddr_s = (MEM_RATIO == 1) ? axi_mem_waddr : + (MEM_RATIO == 2) ? {axi_mem_waddr, 1'b0} : + (MEM_RATIO == 4) ? {axi_mem_waddr, 2'b0} : + {axi_mem_waddr, 3'b0}; + assign axi_mem_laddr_s = (MEM_RATIO == 1) ? axi_mem_laddr : + (MEM_RATIO == 2) ? {axi_mem_laddr, 1'b0} : + (MEM_RATIO == 4) ? {axi_mem_laddr, 2'b0} : + {axi_mem_laddr, 3'b0}; + assign axi_mem_addr_diff_s = {1'b1, axi_mem_waddr} - axi_mem_raddr_s; + + always @(posedge axi_clk) begin + if (axi_fifo_reset_s == 1'b1) begin + axi_mem_addr_diff <= 'd0; + axi_mem_raddr <= 'd0; + axi_mem_raddr_m1 <= 'd0; + axi_mem_raddr_m2 <= 'd0; + axi_data_req <= 'd0; + end else begin + axi_mem_raddr_m1 <= dac_mem_raddr_g; + axi_mem_raddr_m2 <= axi_mem_raddr_m1; + axi_mem_raddr <= axi_mem_raddr_m2_g2b_s; + axi_mem_addr_diff <= axi_mem_addr_diff_s[AXI_MEM_ADDRESS_WIDTH-1:0]; + // requesting AXI read access from the memory, if there is enough space + // for a full burst in the async buffer + if (axi_mem_addr_diff >= AXI_BUF_THRESHOLD_HI) begin + axi_data_req <= 1'b0; + end else begin + axi_data_req <= 1'b1; end end end - always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_rerror <= 'd0; + ad_g2b #( + .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) + ) i_axi_mem_raddr_m2_g2b ( + .din (axi_mem_raddr_m2), + .dout (axi_mem_raddr_m2_g2b_s)); + + // CDC for xfer_req signal + + always @(posedge dac_clk) begin + if (dac_rst == 1'b1) begin + dac_xfer_req_m <= 3'b0; end else begin - axi_rerror <= axi_rvalid & axi_rresp[1]; + dac_xfer_req_m <= {dac_xfer_req_m[1:0], axi_xfer_req}; + end + end + + assign dac_xfer_out = dac_xfer_req_m[2] & dac_mem_valid; + + // CDC for write addresses from the DDRx clock domain + always @(posedge dac_clk) begin + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_waddr <= 'b0; + dac_mem_waddr_m1 <= 'b0; + dac_mem_waddr_m2 <= 'b0; + dac_mem_laddr_toggle_m <= 4'b0; + dac_mem_laddr <= 'b0; + dac_dlast <= 1'b0; + dac_dlast_m1 <= 1'b0; + dac_dlast_m2 <= 1'b0; + end else begin + dac_mem_waddr_m1 <= axi_mem_waddr_g; + dac_mem_waddr_m2 <= dac_mem_waddr_m1; + dac_mem_waddr <= dac_mem_waddr_m2_g2b_s; + dac_mem_laddr_toggle_m <= {dac_mem_laddr_toggle_m[2:0], axi_mem_laddr_toggle}; + dac_mem_laddr <= (dac_mem_laddr_toggle_m[2] ^ dac_mem_laddr_toggle_m[1]) ? + axi_mem_laddr_s : + dac_mem_laddr; + dac_dlast_m1 <= axi_dlast; + dac_dlast_m2 <= dac_dlast_m1; + dac_dlast <= dac_dlast_m2; + end + end + + assign dac_laddr_wea = dac_mem_laddr_toggle_m[3] ^ dac_mem_laddr_toggle_m[2]; + assign dac_laddr_rea = ((dac_mem_raddr == dac_mem_laddr_b) && + (dac_xfer_out == 1'b1)) ? 1'b1 :1'b0; + + axi_dacfifo_address_buffer #( + .ADDRESS_WIDTH (4), + .DATA_WIDTH (DAC_MEM_ADDRESS_WIDTH)) + i_laddress_buffer ( + .clk (dac_clk), + .rst (dac_fifo_reset_s), + .wea (dac_laddr_wea), + .din (dac_mem_laddr), + .rea (dac_laddr_rea), + .dout (dac_mem_laddr_s)); + + ad_g2b #( + .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) + ) i_dac_mem_waddr_m2_g2b ( + .din (dac_mem_waddr_m2), + .dout (dac_mem_waddr_m2_g2b_s)); + + assign dac_mem_addr_diff_s = {1'b1, dac_mem_waddr} - dac_mem_raddr; + + // ASYNC MEM read control + + always @(posedge dac_clk) begin + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_enable <= 1'b0; + dac_mem_valid <= 1'b0; + end else begin + if (dac_mem_dunf_s == 1'b1) begin + dac_mem_enable <= 1'b0; + end else if (dac_mem_addr_diff_s[(DAC_MEM_ADDRESS_WIDTH-1):0] >= DAC_BUF_THRESHOLD_HI) begin + dac_mem_enable <= 1'b1; + end + dac_mem_valid <= (dac_mem_enable) ? dac_valid : 1'b0; + end + end + + // CDC for the dma_last_beats + + always @(posedge dac_clk) begin + if (dac_fifo_reset_s == 1'b1) begin + dac_last_beats <= 4'b0; + dac_last_beats_m <= 4'b0; + end else begin + dac_last_beats_m <= dma_last_beats; + dac_last_beats <= dac_last_beats_m; + end + end + + // If the MEM_RATIO is grater than one, it can happen that not all the DAC beats from + // an AXI beat are valid. In this case the invalid data is dropped. + // The axi_dlast indicates the last AXI beat. The valid number of DAC beats on the last AXI beat + // commes from the AXI write module. (axi_dacfifo_wr.v) + + always @(posedge dac_clk) begin + if (dac_fifo_reset_s == 1'b1) begin + dac_mem_raddr <= 'd0; + dac_mem_laddr_b <= 'd0; + dac_mem_raddr_g <= 'd0; + end else begin + dac_mem_laddr_b <= dac_mem_laddr_s; + if (dac_mem_valid == 1'b1) begin + if ((dac_last_beats > 0) && + (dac_mem_raddr == (dac_mem_laddr_b + dac_last_beats - 1))) begin + dac_mem_raddr <= dac_mem_raddr + (MEM_RATIO - (dac_last_beats - 1)); + end else begin + dac_mem_raddr <= dac_mem_raddr + 1; + end + end + dac_mem_raddr_g <= dac_mem_raddr_b2g_s; + end + end + + ad_b2g # ( + .DATA_WIDTH(DAC_MEM_ADDRESS_WIDTH) + ) i_dac_mem_raddr_b2g ( + .din (dac_mem_raddr), + .dout (dac_mem_raddr_b2g_s)); + + // underflow generation, there is no overflow + + assign dac_mem_dunf_s = (dac_mem_addr_diff_s[(DAC_MEM_ADDRESS_WIDTH-1):0] == 0) ? 1'b1 : 1'b0; + + always @(posedge dac_clk) begin + if(dac_fifo_reset_s == 1'b1) begin + dac_dunf <= 1'b0; + end else begin + dac_dunf <= dac_mem_dunf_s; end end @@ -204,4 +483,3 @@ endmodule // *************************************************************************** // *************************************************************************** - diff --git a/library/xilinx/axi_dacfifo/axi_dacfifo_wr.v b/library/xilinx/axi_dacfifo/axi_dacfifo_wr.v index e67ea50b2..27ca1b6cd 100644 --- a/library/xilinx/axi_dacfifo/axi_dacfifo_wr.v +++ b/library/xilinx/axi_dacfifo/axi_dacfifo_wr.v @@ -32,7 +32,6 @@ // // *************************************************************************** // *************************************************************************** - `timescale 1ns/100ps module axi_dacfifo_wr #( @@ -48,6 +47,7 @@ module axi_dacfifo_wr #( // dma fifo interface input dma_clk, + input dma_rst, input [(DMA_DATA_WIDTH-1):0] dma_data, input dma_ready, output reg dma_ready_out, @@ -59,7 +59,7 @@ module axi_dacfifo_wr #( input dma_xfer_last, output reg [ 3:0] dma_last_beats, - // syncronization for the read side + // last address for read side output reg [31:0] axi_last_addr, output reg [ 7:0] axi_last_beats, @@ -76,7 +76,6 @@ module axi_dacfifo_wr #( output [ 3:0] axi_awcache, output [ 2:0] axi_awprot, output [ 3:0] axi_awqos, - output [ 3:0] axi_awuser, output [ 7:0] axi_awlen, output [ 2:0] axi_awsize, output reg [31:0] axi_awaddr, @@ -85,17 +84,14 @@ module axi_dacfifo_wr #( output [(AXI_DATA_WIDTH-1):0] axi_wdata, output [((AXI_DATA_WIDTH/8)-1):0] axi_wstrb, output axi_wlast, - output [ 3:0] axi_wuser, input axi_wready, input axi_bvalid, input [ 3:0] axi_bid, input [ 1:0] axi_bresp, - input [ 3:0] axi_buser, output axi_bready, output reg axi_werror); - localparam MEM_RATIO = AXI_DATA_WIDTH/DMA_DATA_WIDTH; // Max supported MEM_RATIO is 16 localparam AXI_MEM_ADDRESS_WIDTH = (MEM_RATIO == 1) ? DMA_MEM_ADDRESS_WIDTH : (MEM_RATIO == 2) ? (DMA_MEM_ADDRESS_WIDTH - 1) : @@ -104,10 +100,21 @@ module axi_dacfifo_wr #( (DMA_MEM_ADDRESS_WIDTH - 4); localparam AXI_BYTE_WIDTH = AXI_DATA_WIDTH/8; - localparam DMA_BYTE_WIDTH = DMA_DATA_WIDTH/8; localparam AXI_AWINCR = (AXI_LENGTH + 1) * AXI_BYTE_WIDTH; localparam DMA_BUF_THRESHOLD_HI = {(DMA_MEM_ADDRESS_WIDTH){1'b1}} - 4; + // FSM state definition + + localparam IDLE = 9'b000000001; + localparam XFER_STAGING = 9'b000000010; + localparam XFER_FULL_BURST = 9'b000000100; + localparam XFER_FB_WLAST = 9'b000001000; + localparam XFER_PARTIAL_BURST = 9'b000010000; + localparam XFER_PB_WLAST = 9'b000100000; + localparam XFER_LAST_BURST = 9'b001000000; + localparam XFER_LB_WLAST = 9'b010000000; + localparam XFER_END = 9'b100000000; + // registers reg [(DMA_MEM_ADDRESS_WIDTH-1):0] dma_mem_waddr = 'd0; @@ -116,48 +123,43 @@ module axi_dacfifo_wr #( reg [(AXI_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr_m1 = 'd0; reg [(AXI_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr_m2 = 'd0; reg [(AXI_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr = 'd0; - reg dma_rst_m1 = 1'b0; - reg dma_rst_m2 = 1'b0; reg [ 2:0] dma_mem_last_read_toggle_m = 3'b0; reg [ 1:0] dma_xfer_req_d = 2'b0; - reg [ 4:0] axi_xfer_req_m = 3'b0; - reg [ 4:0] axi_xfer_last_m = 3'b0; - - reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_m1 = 'b0; - reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_m2 = 'b0; - reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'b0; + reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_m1 = 'd0; + reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_m2 = 'd0; + reg [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr = 'd0; reg axi_mem_rvalid = 1'b0; reg axi_mem_rvalid_d = 1'b0; reg axi_mem_last = 1'b0; reg axi_mem_last_d = 1'b0; - reg [(AXI_DATA_WIDTH-1):0] axi_mem_rdata = 'b0; + reg [(AXI_DATA_WIDTH-1):0] axi_mem_rdata = 'd0; reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr = 'd0; reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_g = 'd0; - reg axi_mem_read_en = 1'b0; reg axi_mem_read_en_d = 1'b0; - reg axi_mem_read_en_delay = 1'b0; - reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'b0; + reg [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_addr_diff = 'd0; reg axi_mem_last_read_toggle = 1'b0; - - reg axi_reset = 1'b0; - reg axi_xfer_init = 1'b0; - reg [ 7:0] axi_wvalid_counter = 4'b0; - - reg axi_endof_transaction = 1'b0; - reg axi_endof_transaction_d = 1'b0; + reg [ 2:0] axi_xfer_req_m = 3'b0; + reg axi_xfer_posedge = 1'b0; + reg [ 7:0] axi_wvalid_counter = 8'b0; + reg [ 7:0] axi_last_burst_length = 8'b0; + (* dont_touch = "true" *)reg [ 8:0] axi_writer_state = 9'b0; + reg [ 3:0] axi_dma_last_beats_m1 = 4'b0; + reg [ 3:0] axi_dma_last_beats_m2 = 4'b0; + reg axi_xlast; + reg [ 3:0] axi_xfer_pburst_offset = 4'b1111; // internal signals + wire dma_fifo_reset_s; wire [(DMA_MEM_ADDRESS_WIDTH):0] dma_mem_addr_diff_s; wire [(DMA_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr_s; wire dma_mem_last_read_s; - wire dma_xfer_init; + wire dma_xfer_posedge_s; wire dma_mem_wea_s; - wire dma_rst_s; wire [(DMA_MEM_ADDRESS_WIDTH-1):0] dma_mem_waddr_b2g_s; wire [(AXI_MEM_ADDRESS_WIDTH-1):0] dma_mem_raddr_m2_g2b_s; - + wire axi_mem_read_en_s; wire [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_s; wire [AXI_MEM_ADDRESS_WIDTH:0] axi_mem_addr_diff_s; wire [(AXI_DATA_WIDTH-1):0] axi_mem_rdata_s; @@ -165,13 +167,15 @@ module axi_dacfifo_wr #( wire axi_mem_last_s; wire [(DMA_MEM_ADDRESS_WIDTH-1):0] axi_mem_waddr_m2_g2b_s; wire [(AXI_MEM_ADDRESS_WIDTH-1):0] axi_mem_raddr_b2g_s; - + wire axi_fifo_reset_s; wire axi_waddr_ready_s; wire axi_wready_s; + wire axi_partial_burst_s; + wire axi_last_burst_s; + wire axi_xlast_s; + wire axi_reset_s; - // Instantiations - - // An asymmetric memory to transfer data from DMAC interface to AXI Memory Map + // Asymmetric memory to transfer data from DMAC interface to AXI Memory Map // interface ad_mem_asym #( @@ -188,9 +192,10 @@ module axi_dacfifo_wr #( .addrb (axi_mem_raddr), .doutb (axi_mem_rdata_s)); + assign axi_reset_s = ~axi_resetn; ad_axis_inf_rx #(.DATA_WIDTH(AXI_DATA_WIDTH)) i_axis_inf ( .clk (axi_clk), - .rst (axi_reset), + .rst (axi_reset_s), .valid (axi_mem_rvalid_d), .last (axi_mem_last_d), .data (axi_mem_rdata), @@ -199,37 +204,27 @@ module axi_dacfifo_wr #( .inf_data (axi_wdata), .inf_ready (axi_wready)); - // fifo needs a reset + // reset signals - all the registers reset at the positive edge of + // dma_xfer_req - always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_reset <= 1'b1; - end else begin - axi_reset <= 1'b0; - end - end - - always @(posedge dma_clk) begin - dma_rst_m1 <= ~axi_resetn; - dma_rst_m2 <= dma_rst_m1; - end - assign dma_rst_s = dma_rst_m2; + assign dma_xfer_posedge_s = ~dma_xfer_req_d[1] & dma_xfer_req_d[0]; + assign dma_fifo_reset_s = (dma_rst == 1'b1) || (dma_xfer_posedge_s == 1'b1); + assign axi_fifo_reset_s = (axi_resetn == 1'b0) || (axi_xfer_posedge == 1'b1); // DMA beat counter - assign dma_xfer_init = ~dma_xfer_req_d[1] & dma_xfer_req_d[0]; always @(posedge dma_clk) begin dma_xfer_req_d <= {dma_xfer_req_d[0], dma_xfer_req}; - if ((dma_rst_s == 1'b1) || (dma_xfer_init == 1'b1)) begin + if (dma_fifo_reset_s == 1'b1) begin dma_last_beats <= 4'b0; end else begin - if ((dma_ready == 1'b1) && (dma_valid == 1'b1)) begin + if (dma_mem_wea_s == 1'b1) begin dma_last_beats <= (dma_last_beats < MEM_RATIO-1) ? dma_last_beats + 4'b1 : 4'b0; end end end - // Write address generation for the asymmetric memory + // ASYNC MEM write control assign dma_mem_addr_diff_s = {1'b1, dma_mem_waddr} - dma_mem_raddr_s; assign dma_mem_raddr_s = (MEM_RATIO == 1) ? dma_mem_raddr : @@ -241,7 +236,7 @@ module axi_dacfifo_wr #( assign dma_mem_wea_s = dma_xfer_req & dma_valid & dma_ready; always @(posedge dma_clk) begin - if ((dma_rst_s == 1'b1) || (dma_xfer_init == 1'b1)) begin + if (dma_fifo_reset_s == 1'b1) begin dma_mem_waddr <= 'h0; dma_mem_waddr_g <= 'h0; dma_mem_last_read_toggle_m <= 3'b0; @@ -249,11 +244,6 @@ module axi_dacfifo_wr #( dma_mem_last_read_toggle_m = {dma_mem_last_read_toggle_m[1:0], axi_mem_last_read_toggle}; if (dma_mem_wea_s == 1'b1) begin dma_mem_waddr <= dma_mem_waddr + 1; - if (dma_xfer_last == 1'b1) begin - if (dma_last_beats != (MEM_RATIO - 1)) begin - dma_mem_waddr <= dma_mem_waddr + (MEM_RATIO - dma_last_beats); - end - end end if (dma_mem_last_read_s == 1'b1) begin dma_mem_waddr <= 'h0; @@ -268,10 +258,10 @@ module axi_dacfifo_wr #( .din (dma_mem_waddr), .dout (dma_mem_waddr_b2g_s)); - // The memory module request data until reaches the high threshold. + // The memory module request data until reaches the high threshold always @(posedge dma_clk) begin - if ((dma_rst_s == 1'b1) || (dma_xfer_init == 1'b1)) begin + if (dma_fifo_reset_s == 1'b1) begin dma_mem_addr_diff <= 'b0; dma_mem_raddr_m1 <= 'b0; dma_mem_raddr_m2 <= 'b0; @@ -296,25 +286,118 @@ module axi_dacfifo_wr #( .din (dma_mem_raddr_m2), .dout (dma_mem_raddr_m2_g2b_s)); - // Read address generation for the asymmetric memory + assign axi_xlast_s = axi_wready & axi_wvalid & axi_wlast; + + // FSM to generate the necessary AXI Write transactions + + always @(posedge axi_clk) begin + if (axi_fifo_reset_s == 1'b1) begin + axi_writer_state <= IDLE; + axi_xlast <= 1'b0; + end + else + axi_xlast <= axi_xlast_s; + case (axi_writer_state) + IDLE : begin + if (axi_xfer_req_m[2] == 1'b1) begin + axi_writer_state <= XFER_STAGING; + end else begin + axi_writer_state <= IDLE; + end + end + XFER_STAGING : begin + if (axi_xfer_req_m[2] == 1'b1) begin + // there are enough data for one transaction + if (axi_mem_addr_diff >= AXI_LENGTH) begin + axi_writer_state <= XFER_FULL_BURST; + end else begin + axi_writer_state <= XFER_STAGING; + end + end else if (axi_xfer_pburst_offset == 4'b0) begin // DMA transfer was finished + if ((axi_mem_addr_diff > 0) || + (axi_dma_last_beats_m2 > 0)) begin + axi_writer_state <= XFER_PARTIAL_BURST; + end else begin + axi_writer_state <= XFER_END; + end + end else begin + axi_writer_state <= XFER_STAGING; + end + end + // AXI transaction with full burst length + XFER_FULL_BURST : begin + if ((axi_wvalid_counter == axi_awlen) && (axi_mem_rvalid_s == 1'b1)) begin + axi_writer_state <= XFER_FB_WLAST; + end else begin + axi_writer_state <= XFER_FULL_BURST; + end + end + // Wait for the end of the transaction + XFER_FB_WLAST : begin + if (axi_xlast == 1'b1) begin + axi_writer_state <= XFER_STAGING; + end else begin + axi_writer_state <= XFER_FB_WLAST; + end + end + // AXI transaction with the remaining data, burst length is less than + // the maximum supported burst length + XFER_PARTIAL_BURST : begin + if ((axi_wvalid_counter == axi_awlen) && (axi_mem_rvalid_s == 1'b1)) begin + axi_writer_state <= XFER_PB_WLAST; + end else begin + axi_writer_state <= XFER_PARTIAL_BURST; + end + end + // Wait for the end of the transaction + XFER_PB_WLAST : begin + if (axi_xlast == 1'b1) begin + axi_writer_state <= XFER_END; + end else begin + axi_writer_state <= XFER_PB_WLAST; + end + end + XFER_END : begin + axi_writer_state <= IDLE; + end + default : begin + axi_writer_state <= IDLE; + end + endcase + end + + // FSM outputs + + assign axi_mem_read_en_s = ((axi_writer_state == XFER_FULL_BURST) || + (axi_writer_state == XFER_PARTIAL_BURST)) ? 1 : 0; + assign axi_partial_burst_s = ((axi_writer_state == XFER_PARTIAL_BURST) || + (axi_writer_state == XFER_PB_WLAST)) ? 1 : 0; // CDC for the memory write address, xfer_req and xfer_last always @(posedge axi_clk) begin if (axi_resetn == 1'b0) begin - axi_xfer_req_m <= 4'b0; - axi_xfer_last_m <= 5'b0; - axi_xfer_init <= 1'b0; + axi_xfer_req_m <= 3'b0; + axi_xfer_posedge <= 1'b0; + end else begin + axi_xfer_req_m <= {axi_xfer_req_m[1:0], dma_xfer_req}; + axi_xfer_posedge <= ~axi_xfer_req_m[2] & axi_xfer_req_m[1]; + end + end + + always @(posedge axi_clk) begin + if (axi_fifo_reset_s == 1'b1) begin axi_mem_waddr_m1 <= 'b0; axi_mem_waddr_m2 <= 'b0; axi_mem_waddr <= 'b0; + axi_xfer_pburst_offset <= 4'b1111; end else begin - axi_xfer_req_m <= {axi_xfer_req_m[3:0], dma_xfer_req}; - axi_xfer_last_m <= {axi_xfer_last_m[3:0], dma_xfer_last}; - axi_xfer_init = ~axi_xfer_req_m[2] & axi_xfer_req_m[1]; axi_mem_waddr_m1 <= dma_mem_waddr_g; axi_mem_waddr_m2 <= axi_mem_waddr_m1; axi_mem_waddr <= axi_mem_waddr_m2_g2b_s; + if ((axi_xfer_req_m[2] == 0) && (axi_xfer_pburst_offset > 0)) begin + axi_xfer_pburst_offset <= axi_xfer_pburst_offset - 4'b1; + end end end @@ -324,67 +407,32 @@ module axi_dacfifo_wr #( .din (axi_mem_waddr_m2), .dout (axi_mem_waddr_m2_g2b_s)); - // check if the AXI write channel is ready - - assign axi_wready_s = ~axi_wvalid | axi_wready; - - // check if there is enough data in the asymmetric memory + // ASYNC MEM read control assign axi_mem_waddr_s = (MEM_RATIO == 1) ? axi_mem_waddr : (MEM_RATIO == 2) ? axi_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):1] : (MEM_RATIO == 4) ? axi_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):2] : (MEM_RATIO == 8) ? axi_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):3] : axi_mem_waddr[(DMA_MEM_ADDRESS_WIDTH-1):4]; - assign axi_mem_addr_diff_s = {1'b1, axi_mem_waddr_s} - axi_mem_raddr; - always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_endof_transaction <= 1'b0; - axi_endof_transaction_d <= 1'b0; - end else begin - axi_endof_transaction_d <= axi_endof_transaction; - if ((axi_xfer_req_m[4] == 1'b1) && (axi_xfer_last_m[4] == 1'b1) && (axi_xfer_last_m[3] == 1'b0)) begin - axi_endof_transaction <= 1'b1; - end else if((axi_endof_transaction == 1'b1) && (axi_wlast == 1'b1) && ((axi_mem_addr_diff == 0) || (axi_mem_addr_diff > AXI_LENGTH))) begin - axi_endof_transaction <= 1'b0; - end - end - end - - // The asymmetric memory have to have enough data for at least one AXI burst, - // before the controller start an AXI write transaction. always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin - axi_mem_read_en <= 1'b0; - axi_mem_read_en_d <= 1'b0; - axi_mem_read_en_delay <= 1'b0; + if (axi_fifo_reset_s == 1'b1) begin axi_mem_addr_diff <= 'b0; + axi_mem_read_en_d <= 1'b0; end else begin axi_mem_addr_diff <= axi_mem_addr_diff_s[(AXI_MEM_ADDRESS_WIDTH-1):0]; - if ((axi_mem_read_en == 1'b0) && (axi_mem_read_en_delay == 1'b0)) begin - if (((axi_xfer_req_m[2] == 1'b1) && (axi_mem_addr_diff > AXI_LENGTH)) || - ((axi_endof_transaction == 1'b1) && (axi_mem_addr_diff > AXI_LENGTH)) || - ((axi_endof_transaction == 1'b1) && (axi_mem_addr_diff > 0))) begin - axi_mem_read_en <= 1'b1; - end - end else if (axi_mem_last_s == 1'b1) begin - axi_mem_read_en <= 1'b0; - axi_mem_read_en_delay <= 1; - end - if (axi_wlast == 1'b1) begin - axi_mem_read_en_delay <= 0; - end - axi_mem_read_en_d <= axi_mem_read_en; + axi_mem_read_en_d <= axi_mem_read_en_s; end end - assign axi_mem_rvalid_s = axi_mem_read_en & axi_wready_s; + assign axi_wready_s = ~axi_wvalid | axi_wready; + assign axi_mem_rvalid_s = axi_mem_read_en_s & axi_wready_s; assign axi_mem_last_s = (axi_wvalid_counter == axi_awlen) ? axi_mem_rvalid_s : 1'b0; always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin + if (axi_fifo_reset_s == 1'b1) begin axi_mem_rvalid <= 1'b0; axi_mem_rvalid_d <= 1'b0; axi_mem_last <= 1'b0; @@ -392,7 +440,7 @@ module axi_dacfifo_wr #( axi_mem_rdata <= 'b0; axi_mem_raddr <= 'b0; axi_wvalid_counter <= 8'b0; - axi_mem_last_read_toggle <= 1'b1; + axi_mem_last_read_toggle <= 1'b0; axi_mem_raddr_g <= 'b0; end else begin axi_mem_rvalid <= axi_mem_rvalid_s; @@ -402,9 +450,9 @@ module axi_dacfifo_wr #( axi_mem_rdata <= axi_mem_rdata_s; if (axi_mem_rvalid_s == 1'b1) begin axi_mem_raddr <= axi_mem_raddr + 1; - axi_wvalid_counter <= ((axi_wvalid_counter == axi_awlen) || (axi_xfer_init == 1'b1)) ? 8'b0 : axi_wvalid_counter + 8'b1; + axi_wvalid_counter <= (axi_wvalid_counter == axi_awlen) ? 0 : axi_wvalid_counter + 1; end - if ((axi_endof_transaction == 1'b0) && (axi_endof_transaction_d == 1'b1)) begin + if (axi_writer_state == XFER_END) begin axi_mem_raddr <= 'b0; axi_mem_last_read_toggle <= ~axi_mem_last_read_toggle; end @@ -420,23 +468,21 @@ module axi_dacfifo_wr #( // AXI Memory Map interface write address channel - assign axi_awid = 4'b0000; - assign axi_awburst = 2'b01; - assign axi_awlock = 1'b0; - assign axi_awcache = 4'b0010; - assign axi_awprot = 3'b000; - assign axi_awqos = 4'b0000; - assign axi_awuser = 4'b0001; - assign axi_awlen = AXI_LENGTH; - assign axi_awsize = AXI_SIZE; + assign axi_awid = 4'b0000; + assign axi_awburst = 2'b01; // INCR (Incrementing address burst) + assign axi_awlock = 1'b0; // Normal access + assign axi_awcache = 4'b0010; // Cacheable, but not allocate + assign axi_awprot = 3'b000; // Normal, secure, data access + assign axi_awqos = 4'b0000; // Not used + assign axi_awlen = (axi_partial_burst_s == 1'b1) ? axi_last_burst_length : AXI_LENGTH; + assign axi_awsize = AXI_SIZE; - assign axi_waddr_ready_s = axi_mem_read_en & ~axi_mem_read_en_d; + assign axi_waddr_ready_s = axi_mem_read_en_s & ~axi_mem_read_en_d; always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin + if (axi_fifo_reset_s == 1'b1) begin axi_awvalid <= 'd0; axi_awaddr <= AXI_ADDRESS; - axi_last_addr <= AXI_ADDRESS; axi_xfer_out <= 1'b0; end else begin if (axi_awvalid == 1'b1) begin @@ -448,48 +494,62 @@ module axi_dacfifo_wr #( axi_awvalid <= 1'b1; end end - if (axi_xfer_init == 1'b1) begin - axi_awaddr <= (axi_xfer_out == 1'b1) ? AXI_ADDRESS : axi_last_addr; - axi_xfer_out <= 1'b0; - end else if ((axi_awvalid == 1'b1) && (axi_awready == 1'b1)) begin - axi_awaddr <= axi_awaddr + AXI_AWINCR; + if ((axi_awvalid == 1'b1) && (axi_awready == 1'b1)) begin + axi_awaddr <= (axi_writer_state == XFER_FULL_BURST) ? (axi_awaddr + AXI_AWINCR) : + (axi_writer_state == XFER_PARTIAL_BURST) ? (axi_awaddr + axi_last_burst_length * AXI_BYTE_WIDTH) : + (axi_awaddr + AXI_AWINCR); end - if (axi_xfer_last_m[2] == 1'b1) begin + if (axi_writer_state == XFER_END) begin axi_xfer_out <= 1'b1; end - if ((axi_awvalid == 1'b1) && (axi_endof_transaction == 1'b1)) begin - axi_last_addr <= axi_awaddr; - end end end // write data channel controls assign axi_wstrb = {AXI_BYTE_WIDTH{1'b1}}; - assign axi_wuser = 4'b0000; // response channel assign axi_bready = 1'b1; always @(posedge axi_clk) begin - if (axi_resetn == 1'b0) begin + if (axi_fifo_reset_s == 1'b1) begin axi_werror <= 'd0; end else begin axi_werror <= axi_bvalid & axi_bresp[1]; end end - // AXI beat counter + // AXI last address and last burst length + + assign axi_dma_last_beats_active_s = (axi_dma_last_beats_m2 > 0) ? 1'b1 : 1'b0; + always @(posedge axi_clk) begin + if (axi_fifo_reset_s == 1'b1) begin + axi_dma_last_beats_m1 <= 0; + axi_dma_last_beats_m2 <= 0; + axi_last_burst_length <= AXI_LENGTH; + end else begin + axi_dma_last_beats_m1 <= dma_last_beats; + axi_dma_last_beats_m2 <= axi_dma_last_beats_m1; + axi_last_burst_length <= ((axi_partial_burst_s) && + (axi_waddr_ready_s) && + (axi_dma_last_beats_active_s)) ? axi_mem_addr_diff : + ((axi_partial_burst_s) && + (axi_waddr_ready_s) && + (~axi_dma_last_beats_active_s)) ? (axi_mem_addr_diff-1) : + axi_last_burst_length; + end + end always @(posedge axi_clk) begin - if(axi_resetn == 1'b0) begin + if(axi_fifo_reset_s == 1'b1) begin + axi_last_addr <= AXI_ADDRESS; axi_last_beats <= 8'b0; end else begin - if ((axi_endof_transaction == 1'b1) && (axi_awready == 1'b1) && (axi_awvalid == 1'b1)) begin - axi_last_beats <= axi_mem_addr_diff; - end else begin - axi_last_beats <= axi_last_beats; + if ((axi_awready == 1'b1) && (axi_awvalid == 1'b1)) begin + axi_last_addr <= axi_awaddr & (~AXI_AWINCR+1); + axi_last_beats <= axi_last_burst_length; end end end