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 statemain
parent
4de0a94e37
commit
85a7cebc0e
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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*]
|
||||
|
|
@ -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}]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
// ***************************************************************************
|
||||
// ***************************************************************************
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
|||
|
||||
// ***************************************************************************
|
||||
// ***************************************************************************
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue