avl_dacfifo: Add support for partial avalon transfers

By adding support for partial avalon transfers (data width < bus width),
valid data set size (DMA transfer length) will be dependent on the DMA bus
width only.
main
Istvan Csomortani 2017-05-19 11:22:51 +03:00
parent a993eefe57
commit e34e87e7f8
4 changed files with 345 additions and 18 deletions

View File

@ -92,6 +92,7 @@ module avl_dacfifo #(
wire [ 24:0] avl_wr_address_s;
wire [ 24:0] avl_rd_address_s;
wire [ 24:0] avl_last_address_s;
wire [ 63:0] avl_last_byteenable_s;
wire [ 5:0] avl_wr_burstcount_s;
wire [ 5:0] avl_rd_burstcount_s;
wire [ 63:0] avl_wr_byteenable_s;
@ -117,7 +118,7 @@ module avl_dacfifo #(
.dma_xfer_last (dma_xfer_last),
.dma_last_beat (),
.avl_last_address (avl_last_address_s),
.avl_last_byteenable (),
.avl_last_byteenable (avl_last_byteenable_s),
.avl_clk (avl_clk),
.avl_reset (avl_reset),
.avl_address (avl_wr_address_s),
@ -152,7 +153,7 @@ module avl_dacfifo #(
.avl_read(avl_read_s),
.avl_data(avl_readdata),
.avl_last_address(avl_last_address_s),
.avl_last_byteenable(),
.avl_last_byteenable(avl_last_byteenable_s),
.avl_xfer_req(avl_xfer_out_s));
// avalon address multiplexer and output registers

View File

@ -0,0 +1,276 @@
// ***************************************************************************
// ***************************************************************************
// Copyright 2016(c) Analog Devices, Inc.
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
// - Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// - Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
// - Neither the name of Analog Devices, Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
// - The use of this software may or may not infringe the patent rights
// of one or more patent holders. This license does not release you
// from the requirement that you obtain separate licenses from these
// patent holders to use this software.
// - Use of the software either in source or binary form, must be run
// on or directly connected to an Analog Devices Inc. component.
//
// THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
// INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED.
//
// IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, INTELLECTUAL PROPERTY
// RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// ***************************************************************************
// ***************************************************************************
`timescale 1ns/100ps
module avl_dacfifo_byteenable_decoder #(
parameter MEM_RATIO = 8,
parameter LAST_BEATS_WIDTH = 3) (
input avl_clk,
input [ 63:0] avl_byteenable,
input avl_enable,
output reg [LAST_BEATS_WIDTH-1:0] avl_last_beats
);
always @(posedge avl_clk) begin
if (avl_enable == 1'b1) begin
case (avl_byteenable)
64'b0000000000000000000000000000000000000000000000000000000000000011: begin
case (MEM_RATIO)
32 : avl_last_beats <= 0;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000000000000001111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 1;
16 : avl_last_beats <= 0;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000000000000111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 2;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000000000011111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 3;
16 : avl_last_beats <= 1;
8 : avl_last_beats <= 0;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000000001111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 4;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000000111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 5;
16 : avl_last_beats <= 2;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000000011111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 6;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000001111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 7;
16 : avl_last_beats <= 3;
8 : avl_last_beats <= 1;
4 : avl_last_beats <= 0;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000000111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 8;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000000011111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 9;
16 : avl_last_beats <= 4;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000001111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 10;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000000111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 11;
16 : avl_last_beats <= 5;
8 : avl_last_beats <= 2;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000000011111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 12;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000001111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 13;
16 : avl_last_beats <= 6;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000000111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 14;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000000011111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 15;
16 : avl_last_beats <= 7;
8 : avl_last_beats <= 3;
4 : avl_last_beats <= 1;
2 : avl_last_beats <= 0;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000001111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 16;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000000111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 17;
16 : avl_last_beats <= 8;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000000011111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 18;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000001111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 19;
16 : avl_last_beats <= 9;
8 : avl_last_beats <= 4;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000000111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 20;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000000011111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 21;
16 : avl_last_beats <= 10;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000001111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 22;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000000111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 23;
16 : avl_last_beats <= 11;
8 : avl_last_beats <= 5;
4 : avl_last_beats <= 2;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000000011111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 24;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000001111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 25;
16 : avl_last_beats <= 12;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000000111111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 26;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000000011111111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 27;
16 : avl_last_beats <= 13;
8 : avl_last_beats <= 6;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000001111111111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 28;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0000111111111111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 29;
16 : avl_last_beats <= 14;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
64'b0011111111111111111111111111111111111111111111111111111111111111: begin
case (MEM_RATIO)
32 : avl_last_beats <= 30;
default : avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end
default: avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
endcase
end else begin
avl_last_beats <= {LAST_BEATS_WIDTH{1'b1}};
end
end
endmodule

View File

@ -11,6 +11,7 @@ ad_ip_files avl_dacfifo [list\
$ad_hdl_dir/library/common/ad_b2g.v \
$ad_hdl_dir/library/common/ad_g2b.v \
avl_dacfifo_byteenable_coder.v \
avl_dacfifo_byteenable_decoder.v \
avl_dacfifo_wr.v \
avl_dacfifo_rd.v \
avl_dacfifo.v \

View File

@ -63,6 +63,11 @@ module avl_dacfifo_rd #(
localparam AVL_MEM_THRESHOLD_LO = 8;
localparam AVL_MEM_THRESHOLD_HI = {(AVL_MEM_ADDRESS_WIDTH){1'b1}} - 7;
localparam MEM_WIDTH_DIFF = (MEM_RATIO > 16) ? 5 :
(MEM_RATIO > 8) ? 4 :
(MEM_RATIO > 4) ? 3 :
(MEM_RATIO > 2) ? 2 :
(MEM_RATIO > 1) ? 1 : 1;
// internal register
reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_wr_address;
@ -74,28 +79,33 @@ module avl_dacfifo_rd #(
reg avl_mem_request_data;
reg [AVL_DATA_WIDTH-1:0] avl_mem_data;
reg [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_address_diff;
reg avl_xfer_req_d;
reg avl_xfer_req_dd;
reg avl_read_inprogress;
reg avl_last_transfer;
reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address;
reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_m2;
reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_m1;
reg [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_m2;
reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_last_address;
reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_address;
reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_address_g;
reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_address_diff;
reg [DAC_MEM_ADDRESS_WIDTH-1:0] dac_mem_rd_last_address;
reg dac_mem_last_transfer_active;
reg dac_avl_xfer_req;
reg dac_avl_xfer_req_m1;
reg dac_avl_xfer_req_m2;
reg dac_avl_last_transfer_m1;
reg dac_avl_last_transfer_m2;
reg dac_avl_last_transfer;
// internal signals
wire [AVL_MEM_ADDRESS_WIDTH-1:0] avl_mem_rd_address_s;
wire [AVL_MEM_ADDRESS_WIDTH:0] avl_mem_address_diff_s;
wire [AVL_MEM_ADDRESS_WIDTH:0] avl_mem_wr_address_b2g_s;
wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_address_diff_s;
wire avl_xfer_req_init_s;
wire [DAC_MEM_ADDRESS_WIDTH:0] dac_mem_wr_address_s;
wire [AVL_MEM_ADDRESS_WIDTH-1:0] dac_mem_wr_address_g2b_s;
@ -104,6 +114,8 @@ module avl_dacfifo_rd #(
wire dac_mem_rd_enable_s;
wire [DAC_DATA_WIDTH-1:0] dac_mem_data_s;
wire [MEM_WIDTH_DIFF-1:0] avl_last_beats_s;
wire avl_last_transfer_s;
// ==========================================================================
// An asymmetric memory to transfer data from Avalon interface to DAC
@ -131,7 +143,7 @@ module avl_dacfifo_rd #(
// Avalon address generation and read control signaling
always @(posedge avl_clk) begin
if (avl_reset == 1'b1) begin
if ((avl_reset == 1'b1) || (avl_xfer_req == 1'b0)) begin
avl_address <= AVL_DDR_BASE_ADDRESS;
end else begin
if (avl_readdatavalid == 1'b1) begin
@ -159,9 +171,11 @@ module avl_dacfifo_rd #(
end
end
assign avl_last_transfer_s = (avl_address == avl_last_address) ? 1'b1 : 1'b0;
always @(posedge avl_clk) begin
avl_burstcount <= 1'b1;
avl_byteenable <= {64{1'b1}};
avl_byteenable <= (avl_last_transfer_s) ? avl_last_byteenable : {64{1'b1}};
avl_last_transfer <= avl_last_transfer_s;
end
// write data from Avalon interface into the async FIFO
@ -180,13 +194,7 @@ module avl_dacfifo_rd #(
end
always @(posedge avl_clk) begin
avl_xfer_req_d <= avl_xfer_req;
avl_xfer_req_dd <= avl_xfer_req_d;
end
assign avl_xfer_req_init_s = avl_xfer_req_d & ~avl_xfer_req_dd;
always @(posedge avl_clk) begin
if ((avl_reset == 1'b1) || (avl_xfer_req_init_s == 1'b1)) begin
if ((avl_reset == 1'b1) || (avl_xfer_req == 1'b0)) begin
avl_mem_wr_address <= 0;
avl_mem_wr_address_g <= 0;
end else begin
@ -241,6 +249,17 @@ module avl_dacfifo_rd #(
) i_avl_mem_rd_address_g2b (
.din (avl_mem_rd_address_m2),
.dout (avl_mem_rd_address_g2b_s));
avl_dacfifo_byteenable_decoder #(
.MEM_RATIO (MEM_RATIO),
.LAST_BEATS_WIDTH (MEM_WIDTH_DIFF)
) i_byteenable_decoder (
.avl_clk (avl_clk),
.avl_byteenable (avl_last_byteenable),
.avl_enable (1'b1),
.avl_last_beats (avl_last_beats_s)
);
// ==========================================================================
// Push data from the async FIFO to the DAC
// Data flow is controlled by the DAC, no back-pressure. If FIFO is not
@ -261,10 +280,12 @@ module avl_dacfifo_rd #(
dac_mem_wr_address_m2 <= 0;
dac_mem_wr_address_m1 <= 0;
dac_mem_wr_address <= 0;
dac_mem_wr_last_address <= 0;
end else begin
dac_mem_wr_address_m1 <= avl_mem_wr_address_g;
dac_mem_wr_address_m2 <= dac_mem_wr_address_m1;
dac_mem_wr_address <= dac_mem_wr_address_g2b_s;
dac_mem_wr_last_address <= (dac_avl_last_transfer == 1'b1) ? dac_mem_wr_address_s : dac_mem_wr_last_address;
end
end
@ -274,6 +295,18 @@ module avl_dacfifo_rd #(
.din (dac_mem_wr_address_m2),
.dout (dac_mem_wr_address_g2b_s));
always @(posedge dac_clk) begin
if (dac_reset == 1'b1) begin
dac_avl_last_transfer_m1 <= 0;
dac_avl_last_transfer_m2 <= 0;
dac_avl_last_transfer <= 0;
end else begin
dac_avl_last_transfer_m1 <= (avl_last_transfer & avl_readdatavalid);
dac_avl_last_transfer_m2 <= dac_avl_last_transfer_m1;
dac_avl_last_transfer <= dac_avl_last_transfer_m2;
end
end
always @(posedge dac_clk) begin
if (dac_reset == 1'b1) begin
dac_avl_xfer_req_m2 <= 0;
@ -282,20 +315,36 @@ module avl_dacfifo_rd #(
end else begin
dac_avl_xfer_req_m1 <= avl_xfer_req;
dac_avl_xfer_req_m2 <= dac_avl_xfer_req_m1;
dac_avl_xfer_req <= dac_avl_xfer_req_m1;
dac_avl_xfer_req <= dac_avl_xfer_req_m2;
end
end
assign dac_mem_rd_enable_s = (dac_xfer_req == 1'b1) ? dac_valid : 0;
always @(posedge dac_clk) begin
if (dac_reset == 1'b1) begin
dac_mem_last_transfer_active <= 1'b0;
end else begin
if (dac_avl_last_transfer == 1'b1) begin
dac_mem_last_transfer_active <= 1'b1;
end else if (dac_mem_rd_address == dac_mem_rd_last_address) begin
dac_mem_last_transfer_active <= 1'b0;
end
end
end
assign dac_mem_rd_enable_s = (dac_mem_address_diff[DAC_MEM_ADDRESS_WIDTH-1:0] == 1'b0) ? 0 : (dac_xfer_req & dac_valid);
always @(posedge dac_clk) begin
if ((dac_reset == 1'b1) || ((dac_avl_xfer_req == 1'b0) && (dac_xfer_req == 1'b0))) begin
dac_mem_rd_address <= 0;
dac_mem_rd_address_g <= 0;
dac_mem_address_diff <= 0;
dac_mem_rd_last_address <= 0;
end else begin
dac_mem_address_diff <= dac_mem_address_diff_s[DAC_MEM_ADDRESS_WIDTH-1:0];
dac_mem_rd_last_address <= dac_mem_wr_last_address + avl_last_beats_s;
if (dac_mem_rd_enable_s == 1'b1) begin
dac_mem_rd_address <= dac_mem_rd_address + 1;
dac_mem_rd_address <= ((dac_mem_rd_address == dac_mem_rd_last_address) && (dac_mem_last_transfer_active == 1'b1)) ?
(dac_mem_wr_last_address + {MEM_WIDTH_DIFF{1'b1}} + 1) :
(dac_mem_rd_address + 1);
end
dac_mem_rd_address_g <= dac_mem_rd_address_b2g_s;
end