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
main
Istvan Csomortani 2017-08-04 10:19:12 +01:00
parent 4de0a94e37
commit 85a7cebc0e
10 changed files with 691 additions and 766 deletions

View File

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

View File

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

View File

@ -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:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// 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

View File

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

View File

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

View File

@ -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:
// <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>
//
// 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
// ***************************************************************************
// ***************************************************************************

View File

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

View File

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

View File

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

View File

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