Skip to content

Commit

Permalink
axi_dmac: Add support for DMA Scatter-Gather
Browse files Browse the repository at this point in the history
This commit introduces a different interface to submit transfers, using
DMA descriptors.

The structure of the DMA descriptor is as follows:

struct dma_desc {
    u32 flags,
    u32 id,
    u64 dest_addr,
    u64 src_addr,
    u64 next_sg_addr,
    u32 y_len,
    u32 x_len,
    u32 src_stride,
    u32 dst_stride,
};

The 'flags' field currently offers two control bits:
- bit 0: if set, the transfer will complete after this last descriptor
  is processed, and the DMA core will go back to idle state; if cleared,
  the next DMA descriptor pointed to by 'next_sg_addr' will be loaded.
- bit 1: if set, an end-of-transfer interrupt will be raised after the
  memory segment pointed to by this descriptor has been transferred.

The 'id' field corresponds to an identifier of the descriptor.

The 'dest_addr' and 'src_addr' contain the destination and source
addresses to use for the transfer, respectively.

The 'x_len' field contains the number of bytes to transfer,
minus one.

The 'y_len', 'src_stride' and 'dst_stride' fields are only useful for
2D transfers, and should be set to zero if 2D transfers are not
required.

To start a transfer, the address of the first DMA descriptor must be
written to register 0x47c and the HWDESC bit of CONTROL register must
be set. The Scatter-Gather transfer is queued similarly to the simple
transfers, by writing 1 in TRANSFER_SUBMIT.

The Scatter-Gather interface has a dedicated AXI-MM bus configured for
read transfers, with its own dedicated clock, which can be asynchronous.

The Scatter-Gather reset is generated by the reset manager to reset the
logic after completing any pending transactions on the bus.

When the Scatter-Gather is enabled during runtime, the legacy cyclic
functionality of the DMA is disabled.

Signed-off-by: Ionut Podgoreanu <[email protected]>
  • Loading branch information
podgori committed Dec 4, 2023
1 parent 0f87d84 commit f41391f
Show file tree
Hide file tree
Showing 14 changed files with 1,051 additions and 94 deletions.
2 changes: 2 additions & 0 deletions library/axi_dmac/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ GENERIC_DEPS += dest_axi_mm.v
GENERIC_DEPS += dest_axi_stream.v
GENERIC_DEPS += dest_fifo_inf.v
GENERIC_DEPS += dmac_2d_transfer.v
GENERIC_DEPS += dmac_sg.v
GENERIC_DEPS += inc_id.vh
GENERIC_DEPS += request_arb.v
GENERIC_DEPS += request_generator.v
Expand Down Expand Up @@ -52,6 +53,7 @@ INTEL_DEPS += ../util_axis_fifo/util_axis_fifo.v
INTEL_DEPS += ../util_axis_fifo/util_axis_fifo_address_generator.v
INTEL_DEPS += ../util_cdc/sync_bits.v
INTEL_DEPS += ../util_cdc/sync_event.v
INTEL_DEPS += ../util_cdc/sync_gray.v
INTEL_DEPS += axi_dmac_constr.sdc
INTEL_DEPS += axi_dmac_hw.tcl

Expand Down
150 changes: 122 additions & 28 deletions library/axi_dmac/axi_dmac.v
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,31 @@ module axi_dmac #(
parameter ID = 0,
parameter DMA_DATA_WIDTH_SRC = 64,
parameter DMA_DATA_WIDTH_DEST = 64,
parameter DMA_DATA_WIDTH_SG = 64,
parameter DMA_LENGTH_WIDTH = 24,
parameter DMA_2D_TRANSFER = 0,
parameter DMA_SG_TRANSFER = 0,
parameter ASYNC_CLK_REQ_SRC = 1,
parameter ASYNC_CLK_SRC_DEST = 1,
parameter ASYNC_CLK_DEST_REQ = 1,
parameter ASYNC_CLK_REQ_SG = 1,
parameter ASYNC_CLK_SRC_SG = 1,
parameter ASYNC_CLK_DEST_SG = 1,
parameter AXI_SLICE_DEST = 0,
parameter AXI_SLICE_SRC = 0,
parameter SYNC_TRANSFER_START = 0,
parameter CYCLIC = 1,
parameter DMA_AXI_PROTOCOL_DEST = 0,
parameter DMA_AXI_PROTOCOL_SRC = 0,
parameter DMA_AXI_PROTOCOL_SG = 0,
parameter DMA_TYPE_DEST = 0,
parameter DMA_TYPE_SRC = 2,
parameter DMA_AXI_ADDR_WIDTH = 32,
parameter MAX_BYTES_PER_BURST = 128,
parameter FIFO_SIZE = 8, // In bursts
parameter AXI_ID_WIDTH_SRC = 1,
parameter AXI_ID_WIDTH_DEST = 1,
parameter AXI_ID_WIDTH_SG = 1,
parameter DMA_AXIS_ID_W = 8,
parameter DMA_AXIS_DEST_W = 4,
parameter DISABLE_DEBUG_REGISTERS = 0,
Expand Down Expand Up @@ -187,6 +194,52 @@ module axi_dmac #(
output [AXI_ID_WIDTH_SRC-1:0] m_src_axi_wid,
input [AXI_ID_WIDTH_SRC-1:0] m_src_axi_bid,

// Master AXI interface
input m_sg_axi_aclk,
input m_sg_axi_aresetn,

// Read address
input m_sg_axi_arready,
output m_sg_axi_arvalid,
output [DMA_AXI_ADDR_WIDTH-1:0] m_sg_axi_araddr,
output [7-(4*DMA_AXI_PROTOCOL_SG):0] m_sg_axi_arlen,
output [ 2:0] m_sg_axi_arsize,
output [ 1:0] m_sg_axi_arburst,
output [ 2:0] m_sg_axi_arprot,
output [ 3:0] m_sg_axi_arcache,
output [AXI_ID_WIDTH_SG-1:0] m_sg_axi_arid,
output [DMA_AXI_PROTOCOL_SG:0] m_sg_axi_arlock,

// Read data and response
input [DMA_DATA_WIDTH_SG-1:0] m_sg_axi_rdata,
output m_sg_axi_rready,
input m_sg_axi_rvalid,
input [ 1:0] m_sg_axi_rresp,
input [AXI_ID_WIDTH_SG-1:0] m_sg_axi_rid,
input m_sg_axi_rlast,

// Unused write interface
output m_sg_axi_awvalid,
output [DMA_AXI_ADDR_WIDTH-1:0] m_sg_axi_awaddr,
output [7-(4*DMA_AXI_PROTOCOL_SG):0] m_sg_axi_awlen,
output [ 2:0] m_sg_axi_awsize,
output [ 1:0] m_sg_axi_awburst,
output [ 3:0] m_sg_axi_awcache,
output [ 2:0] m_sg_axi_awprot,
input m_sg_axi_awready,
output m_sg_axi_wvalid,
output [DMA_DATA_WIDTH_SG-1:0] m_sg_axi_wdata,
output [(DMA_DATA_WIDTH_SG/8)-1:0] m_sg_axi_wstrb,
output m_sg_axi_wlast,
input m_sg_axi_wready,
input m_sg_axi_bvalid,
input [ 1:0] m_sg_axi_bresp,
output m_sg_axi_bready,
output [AXI_ID_WIDTH_SG-1:0] m_sg_axi_awid,
output [DMA_AXI_PROTOCOL_SG:0] m_sg_axi_awlock,
output [AXI_ID_WIDTH_SG-1:0] m_sg_axi_wid,
input [AXI_ID_WIDTH_SG-1:0] m_sg_axi_bid,

// Slave streaming AXI interface
input s_axis_aclk,
output s_axis_ready,
Expand Down Expand Up @@ -257,6 +310,14 @@ module axi_dmac #(
DMA_DATA_WIDTH_SRC > 32 ? 3 :
DMA_DATA_WIDTH_SRC > 16 ? 2 :
DMA_DATA_WIDTH_SRC > 8 ? 1 : 0;
localparam BYTES_PER_BEAT_WIDTH_SG = DMA_DATA_WIDTH_SG > 1024 ? 8 :
DMA_DATA_WIDTH_SG > 512 ? 7 :
DMA_DATA_WIDTH_SG > 256 ? 6 :
DMA_DATA_WIDTH_SG > 128 ? 5 :
DMA_DATA_WIDTH_SG > 64 ? 4 :
DMA_DATA_WIDTH_SG > 32 ? 3 :
DMA_DATA_WIDTH_SG > 16 ? 2 :
DMA_DATA_WIDTH_SG > 8 ? 1 : 0;
localparam ID_WIDTH = (FIFO_SIZE) > 64 ? 8 :
(FIFO_SIZE) > 32 ? 7 :
(FIFO_SIZE) > 16 ? 6 :
Expand Down Expand Up @@ -331,45 +392,22 @@ module axi_dmac #(
wire [31:0] dbg_ids0;
wire [31:0] dbg_ids1;

assign m_dest_axi_araddr = 'd0;
assign m_dest_axi_arlen = 'd0;
assign m_dest_axi_arsize = 'd0;
assign m_dest_axi_arburst = 'd0;
assign m_dest_axi_arcache = 'd0;
assign m_dest_axi_arprot = 'd0;
assign m_dest_axi_awid = 'h0;
assign m_dest_axi_awlock = 'h0;
assign m_dest_axi_wid = 'h0;
assign m_dest_axi_arid = 'h0;
assign m_dest_axi_arlock = 'h0;
assign m_src_axi_awaddr = 'd0;
assign m_src_axi_awlen = 'd0;
assign m_src_axi_awsize = 'd0;
assign m_src_axi_awburst = 'd0;
assign m_src_axi_awcache = 'd0;
assign m_src_axi_awprot = 'd0;
assign m_src_axi_wdata = 'd0;
assign m_src_axi_wstrb = 'd0;
assign m_src_axi_wlast = 'd0;
assign m_src_axi_awid = 'h0;
assign m_src_axi_awlock = 'h0;
assign m_src_axi_wid = 'h0;
assign m_src_axi_arid = 'h0;
assign m_src_axi_arlock = 'h0;

wire up_req_eot;
wire [31:0] up_req_sg_desc_id;
wire [BYTES_PER_BURST_WIDTH-1:0] up_req_measured_burst_length;
wire up_response_partial;
wire up_response_valid;
wire up_response_ready;

wire ctrl_enable;
wire ctrl_pause;
wire ctrl_hwdesc;

wire up_dma_req_valid;
wire up_dma_req_ready;
wire [DMA_AXI_ADDR_WIDTH-1:BYTES_PER_BEAT_WIDTH_DEST] up_dma_req_dest_address;
wire [DMA_AXI_ADDR_WIDTH-1:BYTES_PER_BEAT_WIDTH_SRC] up_dma_req_src_address;
wire [DMA_AXI_ADDR_WIDTH-1:BYTES_PER_BEAT_WIDTH_SG] up_dma_req_sg_address;
wire [DMA_LENGTH_WIDTH-1:0] up_dma_req_x_length;
wire [DMA_LENGTH_WIDTH-1:0] up_dma_req_y_length;
wire [DMA_LENGTH_WIDTH-1:0] up_dma_req_dest_stride;
Expand All @@ -396,6 +434,7 @@ module axi_dmac #(
.DISABLE_DEBUG_REGISTERS(DISABLE_DEBUG_REGISTERS),
.BYTES_PER_BEAT_WIDTH_DEST(BYTES_PER_BEAT_WIDTH_DEST),
.BYTES_PER_BEAT_WIDTH_SRC(BYTES_PER_BEAT_WIDTH_SRC),
.BYTES_PER_BEAT_WIDTH_SG(BYTES_PER_BEAT_WIDTH_SG),
.BYTES_PER_BURST_WIDTH(BYTES_PER_BURST_WIDTH),
.DMA_TYPE_DEST(DMA_TYPE_DEST),
.DMA_TYPE_SRC(DMA_TYPE_SRC),
Expand All @@ -406,6 +445,7 @@ module axi_dmac #(
.HAS_DEST_ADDR(HAS_DEST_ADDR),
.HAS_SRC_ADDR(HAS_SRC_ADDR),
.DMA_2D_TRANSFER(DMA_2D_TRANSFER),
.DMA_SG_TRANSFER(DMA_SG_TRANSFER),
.SYNC_TRANSFER_START(SYNC_TRANSFER_START),
.CACHE_COHERENT_DEST(CACHE_COHERENT_DEST)
) i_regmap (
Expand Down Expand Up @@ -438,12 +478,14 @@ module axi_dmac #(
// Control interface
.ctrl_enable(ctrl_enable),
.ctrl_pause(ctrl_pause),
.ctrl_hwdesc(ctrl_hwdesc),

// Request interface
.request_valid(up_dma_req_valid),
.request_ready(up_dma_req_ready),
.request_dest_address(up_dma_req_dest_address),
.request_src_address(up_dma_req_src_address),
.request_sg_address(up_dma_req_sg_address),
.request_x_length(up_dma_req_x_length),
.request_y_length(up_dma_req_y_length),
.request_dest_stride(up_dma_req_dest_stride),
Expand All @@ -453,6 +495,7 @@ module axi_dmac #(

// DMA response interface
.response_eot(up_req_eot),
.response_sg_desc_id(up_req_sg_desc_id),
.response_measured_burst_length(up_req_measured_burst_length),
.response_partial(up_response_partial),
.response_valid(up_response_valid),
Expand All @@ -468,25 +511,30 @@ module axi_dmac #(
axi_dmac_transfer #(
.DMA_DATA_WIDTH_SRC(DMA_DATA_WIDTH_SRC),
.DMA_DATA_WIDTH_DEST(DMA_DATA_WIDTH_DEST),
.DMA_DATA_WIDTH_SG(DMA_DATA_WIDTH_SG),
.DMA_LENGTH_WIDTH(DMA_LENGTH_WIDTH),
.DMA_LENGTH_ALIGN(DMA_LENGTH_ALIGN),
.BYTES_PER_BEAT_WIDTH_DEST(BYTES_PER_BEAT_WIDTH_DEST),
.BYTES_PER_BEAT_WIDTH_SRC(BYTES_PER_BEAT_WIDTH_SRC),
.BYTES_PER_BEAT_WIDTH_SG(BYTES_PER_BEAT_WIDTH_SG),
.BYTES_PER_BURST_WIDTH(BYTES_PER_BURST_WIDTH),
.DMA_TYPE_DEST(DMA_TYPE_DEST),
.DMA_TYPE_SRC(DMA_TYPE_SRC),
.DMA_AXI_ADDR_WIDTH(DMA_AXI_ADDR_WIDTH),
.DMA_2D_TRANSFER(DMA_2D_TRANSFER),
.DMA_SG_TRANSFER(DMA_SG_TRANSFER),
.ASYNC_CLK_REQ_SRC(ASYNC_CLK_REQ_SRC),
.ASYNC_CLK_SRC_DEST(ASYNC_CLK_SRC_DEST),
.ASYNC_CLK_DEST_REQ(ASYNC_CLK_DEST_REQ),
.ASYNC_CLK_REQ_SG(ASYNC_CLK_REQ_SG),
.AXI_SLICE_DEST(AXI_SLICE_DEST),
.AXI_SLICE_SRC(AXI_SLICE_SRC),
.MAX_BYTES_PER_BURST(REAL_MAX_BYTES_PER_BURST),
.FIFO_SIZE(FIFO_SIZE),
.ID_WIDTH(ID_WIDTH),
.AXI_LENGTH_WIDTH_SRC(8-(4*DMA_AXI_PROTOCOL_SRC)),
.AXI_LENGTH_WIDTH_DEST(8-(4*DMA_AXI_PROTOCOL_DEST)),
.AXI_LENGTH_WIDTH_SG(8-(4*DMA_AXI_PROTOCOL_SG)),
.ENABLE_DIAGNOSTICS_IF(ENABLE_DIAGNOSTICS_IF),
.ALLOW_ASYM_MEM(ALLOW_ASYM_MEM),
.CACHE_COHERENT_DEST(CACHE_COHERENT_DEST)
Expand All @@ -496,11 +544,13 @@ module axi_dmac #(

.ctrl_enable(ctrl_enable),
.ctrl_pause(ctrl_pause),
.ctrl_hwdesc(ctrl_hwdesc),

.req_valid(up_dma_req_valid),
.req_ready(up_dma_req_ready),
.req_dest_address(up_dma_req_dest_address),
.req_src_address(up_dma_req_src_address),
.req_sg_address(up_dma_req_sg_address),
.req_x_length(up_dma_req_x_length),
.req_y_length(up_dma_req_y_length),
.req_dest_stride(up_dma_req_dest_stride),
Expand All @@ -509,6 +559,7 @@ module axi_dmac #(
.req_last(up_dma_req_last),

.req_eot(up_req_eot),
.req_sg_desc_id(up_req_sg_desc_id),
.req_measured_burst_length(up_req_measured_burst_length),
.req_response_partial(up_response_partial),
.req_response_valid(up_response_valid),
Expand All @@ -518,6 +569,8 @@ module axi_dmac #(
.m_dest_axi_aresetn(m_dest_axi_aresetn),
.m_src_axi_aclk(m_src_axi_aclk),
.m_src_axi_aresetn(m_src_axi_aresetn),
.m_sg_axi_aclk(m_sg_axi_aclk),
.m_sg_axi_aresetn(m_sg_axi_aresetn),

.m_axi_awaddr(m_dest_axi_awaddr),
.m_axi_awlen(m_dest_axi_awlen),
Expand Down Expand Up @@ -553,6 +606,21 @@ module axi_dmac #(
.m_axi_rlast(m_src_axi_rlast),
.m_axi_rresp(m_src_axi_rresp),

.m_sg_axi_arready(m_sg_axi_arready),
.m_sg_axi_arvalid(m_sg_axi_arvalid),
.m_sg_axi_araddr(m_sg_axi_araddr),
.m_sg_axi_arlen(m_sg_axi_arlen),
.m_sg_axi_arsize(m_sg_axi_arsize),
.m_sg_axi_arburst(m_sg_axi_arburst),
.m_sg_axi_arprot(m_sg_axi_arprot),
.m_sg_axi_arcache(m_sg_axi_arcache),

.m_sg_axi_rdata(m_sg_axi_rdata),
.m_sg_axi_rready(m_sg_axi_rready),
.m_sg_axi_rvalid(m_sg_axi_rvalid),
.m_sg_axi_rlast(m_sg_axi_rlast),
.m_sg_axi_rresp(m_sg_axi_rresp),

.s_axis_aclk(s_axis_aclk),
.s_axis_ready(s_axis_ready),
.s_axis_valid(s_axis_valid),
Expand Down Expand Up @@ -603,21 +671,47 @@ module axi_dmac #(
assign m_dest_axi_arburst = 'h0;
assign m_dest_axi_arcache = 'h0;
assign m_dest_axi_arprot = 'h0;
assign m_dest_axi_awid = 'h0;
assign m_dest_axi_awlock = 'h0;
assign m_dest_axi_wid = 'h0;
assign m_dest_axi_arid = 'h0;
assign m_dest_axi_arlock = 'h0;

assign m_src_axi_awvalid = 1'b0;
assign m_src_axi_wvalid = 1'b0;
assign m_src_axi_bready = 1'b0;
assign m_src_axi_awvalid = 'h0;
assign m_src_axi_awaddr = 'h0;
assign m_src_axi_awlen = 'h0;
assign m_src_axi_awsize = 'h0;
assign m_src_axi_awburst = 'h0;
assign m_src_axi_awcache = 'h0;
assign m_src_axi_awprot = 'h0;
assign m_src_axi_wvalid = 'h0;
assign m_src_axi_wdata = 'h0;
assign m_src_axi_wstrb = 'h0;
assign m_src_axi_wlast = 'h0;
assign m_src_axi_awid = 'h0;
assign m_src_axi_awlock = 'h0;
assign m_src_axi_wid = 'h0;
assign m_src_axi_arid = 'h0;
assign m_src_axi_arlock = 'h0;

assign m_sg_axi_awvalid = 1'b0;
assign m_sg_axi_wvalid = 1'b0;
assign m_sg_axi_bready = 1'b0;
assign m_sg_axi_awaddr = 'h0;
assign m_sg_axi_awlen = 'h0;
assign m_sg_axi_awsize = 'h0;
assign m_sg_axi_awburst = 'h0;
assign m_sg_axi_awcache = 'h0;
assign m_sg_axi_awprot = 'h0;
assign m_sg_axi_wdata = 'h0;
assign m_sg_axi_wstrb = 'h0;
assign m_sg_axi_wlast = 'h0;
assign m_sg_axi_awid = 'h0;
assign m_sg_axi_awlock = 'h0;
assign m_sg_axi_wid = 'h0;
assign m_sg_axi_arid = 'h0;
assign m_sg_axi_arlock = 'h0;

assign m_axis_keep = {DMA_DATA_WIDTH_DEST/8{1'b1}};
assign m_axis_strb = {DMA_DATA_WIDTH_DEST/8{1'b1}};
Expand Down
Loading

0 comments on commit f41391f

Please sign in to comment.