Skip to content

axi_dmac: Fix AXI transfers of one beat length #1844

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 0 additions & 13 deletions docs/library/axi_dmac/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -856,19 +856,6 @@ Analog Devices recommends to use the provided software drivers.
- :dokuwiki:`Analog Device AXI-DMAC DMA Controller Linux Driver
<resources/tools-software/linux-drivers/axi-dmac>`

Known Issues
--------------------------------------------------------------------------------

1. When max bytes per burst matches the data width of destination interface an
erroneous extra beat is inserted after every valid beat on the destination side.
Example configuration:

* axi mm -> axi stream
* max bytes per burst = 128
* destination width = 1024 bits

Workaround: increase the max bytes per burst to larger than 128

Technical Support
--------------------------------------------------------------------------------

Expand Down
4 changes: 2 additions & 2 deletions docs/regmap/adi_regmap_dmac.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ENDTITLE
REG
0x000
VERSION
Version of the peripheral. Follows semantic versioning. Current version 4.05.64.
Version of the peripheral. Follows semantic versioning. Current version 4.05.65.
ENDREG

FIELD
Expand All @@ -25,7 +25,7 @@ RO
ENDFIELD

FIELD
[7:0] 0x00000064
[7:0] 0x00000065
VERSION_PATCH
RO
ENDFIELD
Expand Down
12 changes: 6 additions & 6 deletions library/axi_dmac/address_generator.v
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2014-2024 Analog Devices, Inc. All rights reserved.
// Copyright (C) 2014-2025 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
Expand Down Expand Up @@ -58,7 +58,7 @@ module address_generator #(

input bl_valid,
output reg bl_ready,
input [BEATS_PER_BURST_WIDTH-1:0] measured_last_burst_length,
input [BEATS_PER_BURST_WIDTH:0] measured_last_burst_length,

input eot,

Expand Down Expand Up @@ -91,11 +91,11 @@ module address_generator #(
DMA_DATA_WIDTH == 32 ? 3'b010 :
DMA_DATA_WIDTH == 16 ? 3'b001 : 3'b000;

reg [LENGTH_WIDTH-1:0] length = 'h0;
reg [BEATS_PER_BURST_WIDTH-1:0] length = 'h0;
reg [DMA_ADDR_WIDTH-BYTES_PER_BEAT_WIDTH-1:0] address = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] last_burst_len = 'h00;
reg [BEATS_PER_BURST_WIDTH:0] last_burst_len = 'h00;
assign addr = {address, {BYTES_PER_BEAT_WIDTH{1'b0}}};
assign len = length;
assign len = {{(LENGTH_WIDTH-BEATS_PER_BURST_WIDTH){1'b0}}, length};

reg addr_valid_d1;
reg last = 1'b0;
Expand All @@ -122,7 +122,7 @@ module address_generator #(
if (addr_valid == 1'b0) begin
last <= eot;
if (eot == 1'b1) begin
length <= last_burst_len;
length <= last_burst_len[BEATS_PER_BURST_WIDTH-1:0];
end else begin
length <= MAX_LENGTH;
end
Expand Down
76 changes: 50 additions & 26 deletions library/axi_dmac/axi_dmac_burst_memory.v
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2014-2023 Analog Devices, Inc. All rights reserved.
// Copyright (C) 2014-2025 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
Expand Down Expand Up @@ -93,7 +93,8 @@ module axi_dmac_burst_memory #(
BURST_LEN > 16 ? 5 :
BURST_LEN > 8 ? 4 :
BURST_LEN > 4 ? 3 :
BURST_LEN > 2 ? 2 : 1;
BURST_LEN > 2 ? 2 :
BURST_LEN > 1 ? 1 : 0;

localparam AUX_FIFO_SIZE = 2**(ID_WIDTH-1);

Expand Down Expand Up @@ -144,14 +145,11 @@ module axi_dmac_burst_memory #(
reg [ID_WIDTH-1:0] src_id_next;
reg [ID_WIDTH-1:0] src_id = 'h0;
reg src_id_reduced_msb = 1'b0;
reg [BURST_LEN_WIDTH_SRC-1:0] src_beat_counter = 'h00;

reg [ID_WIDTH-1:0] dest_id_next = 'h0;
reg dest_id_reduced_msb_next = 1'b0;
reg dest_id_reduced_msb = 1'b0;
reg [ID_WIDTH-1:0] dest_id = 'h0;
reg [BURST_LEN_WIDTH_DEST-1:0] dest_beat_counter = 'h00;
wire [BURST_LEN_WIDTH_DEST-1:0] dest_burst_len;
reg dest_valid = 1'b0;
reg dest_mem_data_valid = 1'b0;
reg dest_mem_data_last = 1'b0;
Expand Down Expand Up @@ -201,7 +199,6 @@ module axi_dmac_burst_memory #(

assign src_beat = src_mem_data_valid;
assign src_last_beat = src_beat & src_mem_data_last;
assign src_waddr = {src_id_reduced,src_beat_counter};

assign src_data_request_id = src_dest_id;

Expand All @@ -223,13 +220,31 @@ module axi_dmac_burst_memory #(
end
end

always @(posedge src_clk) begin
if (src_reset == 1'b1 || src_last_beat == 1'b1) begin
src_beat_counter <= 'h00;
end else if (src_beat == 1'b1) begin
src_beat_counter <= src_beat_counter + 1'b1;
/*
* When the burst is only one beat wide, the src_beat_counter logic can be removed,
* since the current beat is actually the last in the burst. This scenario happens
* when the MAX_BYTES_PER_BURST value matches the DATA_WIDTH_SRC value in bytes.
*/
generate if (BURST_LEN_WIDTH_SRC > 0) begin
reg [BURST_LEN_WIDTH_SRC-1:0] src_beat_counter = 'h00;

always @(posedge src_clk) begin
if (src_reset == 1'b1 || src_last_beat == 1'b1) begin
src_beat_counter <= 'h00;
end else if (src_beat == 1'b1) begin
src_beat_counter <= src_beat_counter + 1'b1;
end
end
end

assign src_burst_len_data = {src_mem_data_partial_burst,
src_beat_counter,
src_mem_data_valid_bytes};
assign src_waddr = {src_id_reduced,src_beat_counter};
end else begin
assign src_burst_len_data = {src_mem_data_partial_burst,
src_mem_data_valid_bytes};
assign src_waddr = src_id_reduced;
end endgenerate

always @(posedge src_clk) begin
if (src_last_beat == 1'b1) begin
Expand All @@ -238,11 +253,9 @@ module axi_dmac_burst_memory #(
end

assign dest_ready = ~dest_mem_data_valid | dest_mem_data_ready;
assign dest_last = dest_beat_counter == dest_burst_len;

assign dest_beat = dest_valid & dest_ready;
assign dest_last_beat = dest_last & dest_beat;
assign dest_raddr = {dest_id_reduced,dest_beat_counter};

assign dest_burst_valid = dest_data_request_id != dest_id_next;
assign dest_burst_ready = ~dest_valid | dest_last_beat;
Expand Down Expand Up @@ -332,13 +345,30 @@ module axi_dmac_burst_memory #(
end
end

always @(posedge dest_clk) begin
if (dest_reset == 1'b1 || dest_last_beat == 1'b1) begin
dest_beat_counter <= 'h00;
end else if (dest_beat == 1'b1) begin
dest_beat_counter <= dest_beat_counter + 1'b1;
/*
* When the burst is only one beat wide, the dest_beat_counter logic can be removed,
* since the current beat is actually the last in the burst. This scenario happens
* when the MAX_BYTES_PER_BURST value matches the DATA_WIDTH_DEST value in bytes.
*/
generate if (BURST_LEN_WIDTH_DEST > 0) begin
reg [BURST_LEN_WIDTH_DEST-1:0] dest_beat_counter = 'h00;
wire [BURST_LEN_WIDTH_DEST-1:0] dest_burst_len;

always @(posedge dest_clk) begin
if (dest_reset == 1'b1 || dest_last_beat == 1'b1) begin
dest_beat_counter <= 'h00;
end else if (dest_beat == 1'b1) begin
dest_beat_counter <= dest_beat_counter + 1'b1;
end
end
end

assign dest_burst_len = dest_burst_len_data[BYTES_PER_BURST_WIDTH-1 -: BURST_LEN_WIDTH_DEST];
assign dest_last = dest_beat_counter == dest_burst_len;
assign dest_raddr = {dest_id_reduced,dest_beat_counter};
end else begin
assign dest_last = 1'b1;
assign dest_raddr = dest_id_reduced;
end endgenerate

assign dest_burst_info_length = dest_burst_len_data[BYTES_PER_BURST_WIDTH-1:0];
assign dest_burst_info_partial = dest_burst_len_data[BYTES_PER_BURST_WIDTH];
Expand All @@ -348,8 +378,6 @@ module axi_dmac_burst_memory #(
dest_burst_info_write <= (dest_burst_valid == 1'b1 && dest_burst_ready == 1'b1);
end

assign dest_burst_len = dest_burst_len_data[BYTES_PER_BURST_WIDTH-1 -: BURST_LEN_WIDTH_DEST];

axi_dmac_resize_src #(
.DATA_WIDTH_SRC (DATA_WIDTH_SRC),
.BYTES_PER_BEAT_WIDTH_SRC (BYTES_PER_BEAT_WIDTH_SRC),
Expand All @@ -371,10 +399,6 @@ module axi_dmac_burst_memory #(
.mem_data_valid_bytes (src_mem_data_valid_bytes),
.mem_data_partial_burst (src_mem_data_partial_burst));

assign src_burst_len_data = {src_mem_data_partial_burst,
src_beat_counter,
src_mem_data_valid_bytes};

ad_mem_asym #(
.A_ADDRESS_WIDTH (ADDRESS_WIDTH_SRC),
.A_DATA_WIDTH (DATA_WIDTH_MEM_SRC),
Expand Down
77 changes: 46 additions & 31 deletions library/axi_dmac/data_mover.v
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2014-2024 Analog Devices, Inc. All rights reserved.
// Copyright (C) 2014-2025 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
Expand Down Expand Up @@ -55,7 +55,7 @@ module data_mover #(

output reg bl_valid = 'b0,
input bl_ready,
output reg [BEATS_PER_BURST_WIDTH-1:0] measured_last_burst_length,
output [BEATS_PER_BURST_WIDTH:0] measured_last_burst_length,

output block_descr_to_dst,

Expand All @@ -77,7 +77,7 @@ module data_mover #(

input req_valid,
output req_ready,
input [BEATS_PER_BURST_WIDTH-1:0] req_last_burst_length,
input [BEATS_PER_BURST_WIDTH:0] req_last_burst_length,
input req_sync_transfer_start,
input req_xlast
);
Expand All @@ -86,16 +86,11 @@ module data_mover #(

`include "inc_id.vh"

reg [BEATS_PER_BURST_WIDTH-1:0] last_burst_length = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter_minus_one = 'h0;
reg [ID_WIDTH-1:0] id = 'h00;
reg [ID_WIDTH-1:0] id_next = 'h00;

reg pending_burst = 1'b0;
reg active = 1'b0;
reg last_eot = 1'b0;
reg last_non_eot = 1'b0;
reg needs_sync = 1'b0;

wire has_sync;
Expand All @@ -109,7 +104,6 @@ module data_mover #(
assign response_id = id;
assign source_id = id;
assign source_eot = eot || early_tlast;
assign last = eot ? last_eot : last_non_eot;

assign has_sync = ~needs_sync | s_axi_sync;

Expand Down Expand Up @@ -197,40 +191,61 @@ module data_mover #(
// request got accepted.
// In case the data mover is not active accept a new descriptor only when the
// upstream logic incremented its id (pending_burst is set).
assign last_load = m_axi_valid && last_eot && eot;
assign req_ready = (last_load && ~early_tlast) ||
((~active && ~transfer_abort_s) && pending_burst) ||
(transfer_abort_s && rewind_req_ready);

always @(posedge clk) begin
if (req_ready) begin
last_eot <= req_last_burst_length == 'h0;
last_non_eot <= 1'b0;
beat_counter <= 'h1;
end else if (m_axi_valid == 1'b1) begin
last_eot <= beat_counter == last_burst_length;
last_non_eot <= beat_counter == BEAT_COUNTER_MAX;
beat_counter <= beat_counter + 1'b1;
generate if (BEATS_PER_BURST_WIDTH > 0) begin
reg last_eot = 1'b0;
reg last_non_eot = 1'b0;
reg [BEATS_PER_BURST_WIDTH-1:0] _measured_last_burst_length = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] last_burst_length = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter = 'h00;
reg [BEATS_PER_BURST_WIDTH-1:0] beat_counter_minus_one = 'h0;

always @(posedge clk) begin
if (req_ready) begin
last_eot <= req_last_burst_length == 'h0;
last_non_eot <= 1'b0;
beat_counter <= 'h1;
end else if (m_axi_valid == 1'b1) begin
last_eot <= beat_counter == last_burst_length;
last_non_eot <= beat_counter == BEAT_COUNTER_MAX;
beat_counter <= beat_counter + 1'b1;
end
end
end

always @(posedge clk) begin
if (req_ready)
last_burst_length <= req_last_burst_length;
end
always @(posedge clk) begin
if (req_ready)
last_burst_length <= req_last_burst_length[BEATS_PER_BURST_WIDTH-1:0];
end

always @(posedge clk) begin
if (req_ready) begin
beat_counter_minus_one <= 'h0;
end else if (m_axi_valid == 1'b1) begin
beat_counter_minus_one <= beat_counter;
always @(posedge clk) begin
if (req_ready) begin
beat_counter_minus_one <= 'h0;
end else if (m_axi_valid == 1'b1) begin
beat_counter_minus_one <= beat_counter;
end
end
end

always @(posedge clk) begin
if (last_load || early_tlast) begin
_measured_last_burst_length <= beat_counter_minus_one;
end
end

assign last = eot ? last_eot : last_non_eot;
assign last_load = m_axi_valid & last_eot & eot;
assign measured_last_burst_length = {1'b0, _measured_last_burst_length};
end else begin
assign last = 1'b1;
assign last_load = m_axi_valid & eot;
assign measured_last_burst_length = 1'b0;
end endgenerate

always @(posedge clk) begin
if (last_load || early_tlast) begin
bl_valid <= 1'b1;
measured_last_burst_length <= beat_counter_minus_one;
end else if (bl_ready) begin
bl_valid <= 1'b0;
end
Expand Down
4 changes: 2 additions & 2 deletions library/axi_dmac/dest_axi_mm.v
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// ***************************************************************************
// ***************************************************************************
// Copyright (C) 2014-2024 Analog Devices, Inc. All rights reserved.
// Copyright (C) 2014-2025 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
Expand Down Expand Up @@ -57,7 +57,7 @@ module dest_axi_mm #(

input bl_valid,
output bl_ready,
input [BEATS_PER_BURST_WIDTH-1:0] measured_last_burst_length,
input [BEATS_PER_BURST_WIDTH:0] measured_last_burst_length,

input enable,
output enabled,
Expand Down
Loading