//////////////////////////////////////////////////////////////////////////////// // // Filename: axisgdma.v // {{{ // Project: WB2AXIPSP: bus bridges and other odds and ends // // Purpose: Scripts an AXI DMA via in-memory tables: reads from the tables, // commands the DMA. // // Registers: // // 0. Control // 8b KEY // 3'b PROT // 4'b QOS // 1b Abort: Either aborting or aborted // 1b Err: Ended on an error // 1b Busy // 1b Interrupt Enable // 1b Interrupt Set // 1b Start // 1. Reserved // 2-3. First table entry address // (Current) table entry address on read, if in progress // (Optional) // 4-5. Current read address // 6-7. Current write address // 1. Remaining amount to be written (this entry) // // Table entries (must be 32-bit aligned): // If (address_width > 30) // 64b: { 2'bflags, 62'b SOURCE ADDRESS (bytes) } // 00: Continue after this to next // 01: Skip this address // 10: Jump to new address // 11: Last item in chain // 64b: { int_en, 1'b0, DESTINATION ADDRESS (bytes) } // 32b LENGTH (in bytes) // else // 32b: { 2'bflags, 30'b SOURCE ADDRESS (bytes) } // 32b: { int_en, 1'b0, 30'b DESTINATION ADDRESS (bytes) } // 32b LENGTH (in bytes) // // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2020-2024, Gisselquist Technology, LLC // {{{ // This file is part of the WB2AXIP project. // // The WB2AXIP project contains free software and gateware, licensed under the // Apache License, Version 2.0 (the "License"). You may not use this project, // or this file, except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // //////////////////////////////////////////////////////////////////////////////// // // `default_nettype none // `define AXI3 // }}} module axisgdma #( // {{{ parameter C_AXI_ID_WIDTH = 1, parameter C_AXI_ADDR_WIDTH = 32, parameter C_AXI_DATA_WIDTH = 64, // localparam C_AXIL_ADDR_WIDTH = 4, localparam C_AXIL_DATA_WIDTH = 32, // // OPT_UNALIGNED turns on support for unaligned addresses, // whether source, destination, or length parameters. parameter [0:0] OPT_UNALIGNED = 1'b1, // // OPT_WRAPMEM controls what happens if the transfer runs off // of the end of memory. If set, the transfer will continue // again from the beginning of memory. If clear, the transfer // will be aborted with an error if either read or write // address ever get this far. parameter [0:0] OPT_WRAPMEM = 1'b1, // // LGMAXBURST controls the size of the maximum burst produced // by this core. Specifically, its the log (based 2) of that // maximum size. Hence, for AXI4, this size must be 8 // (i.e. 2^8 or 256 beats) or less. For AXI3, the size must // be 4 or less. Tests have verified performance for // LGMAXBURST as low as 2. While I expect it to fail at // LGMAXBURST=0, I haven't verified at what value this burst // parameter is too small. `ifdef AXI3 parameter LGMAXBURST=4, // 16 beats max `else parameter LGMAXBURST=8, // 256 beats `endif // // LGFIFO: This is the (log-based-2) size of the internal FIFO. // Hence if LGFIFO=8, the internal FIFO will have 256 elements // (words) in it. High throughput transfers are accomplished // by first storing data into a FIFO, then once a full burst // size is available bursting that data over the bus. In // order to be able to keep receiving data while bursting it // out, the FIFO size must be at least twice the size of the // maximum burst size. Larger sizes are possible as well. parameter LGFIFO = LGMAXBURST+1, // 512 element FIFO // // LGLEN: specifies the number of bits in the transfer length // register. If a transfer cannot be specified in LGLEN bits, // it won't happen. LGLEN must be less than or equal to the // address width. parameter LGLEN = C_AXI_ADDR_WIDTH, // // AXI uses ID's to transfer information. This core rather // ignores them. Instead, it uses a constant ID for all // transfers. The following two parameters control that ID. parameter [C_AXI_ID_WIDTH-1:0] DMA_READ_ID = 0, parameter [C_AXI_ID_WIDTH-1:0] DMA_WRITE_ID = 0, parameter [C_AXI_ID_WIDTH-1:0] PF_READ_ID = DMA_READ_ID+1, // // The "ABORT_KEY" is a byte that, if written to the control // word while the core is running, will cause the data transfer // to be aborted. parameter [7:0] ABORT_KEY = 8'h6d, // // OPT_LOWPOWER parameter [0:0] OPT_LOWPOWER = 1'b0 // }}} ) ( // {{{ input wire S_AXI_ACLK, input wire S_AXI_ARESETN, // // The AXI4-lite control interface input wire S_AXIL_AWVALID, output wire S_AXIL_AWREADY, input wire [C_AXIL_ADDR_WIDTH-1:0] S_AXIL_AWADDR, input wire [2:0] S_AXIL_AWPROT, // input wire S_AXIL_WVALID, output wire S_AXIL_WREADY, input wire [C_AXIL_DATA_WIDTH-1:0] S_AXIL_WDATA, input wire [C_AXIL_DATA_WIDTH/8-1:0] S_AXIL_WSTRB, // output reg S_AXIL_BVALID, input wire S_AXIL_BREADY, output wire [1:0] S_AXIL_BRESP, // input wire S_AXIL_ARVALID, output wire S_AXIL_ARREADY, input wire [C_AXIL_ADDR_WIDTH-1:0] S_AXIL_ARADDR, input wire [2:0] S_AXIL_ARPROT, // output reg S_AXIL_RVALID, input wire S_AXIL_RREADY, output reg [C_AXIL_DATA_WIDTH-1:0] S_AXIL_RDATA, output wire [1:0] S_AXIL_RRESP, // // // The AXI Master (DMA) interface output wire M_AXI_AWVALID, input wire M_AXI_AWREADY, output wire [C_AXI_ID_WIDTH-1:0] M_AXI_AWID, output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, `ifdef AXI3 output wire [3:0] M_AXI_AWLEN, `else output wire [7:0] M_AXI_AWLEN, `endif output wire [2:0] M_AXI_AWSIZE, output wire [1:0] M_AXI_AWBURST, `ifdef AXI3 output wire [1:0] M_AXI_AWLOCK, `else output wire M_AXI_AWLOCK, `endif output wire [3:0] M_AXI_AWCACHE, output wire [2:0] M_AXI_AWPROT, output wire [3:0] M_AXI_AWQOS, // // output wire M_AXI_WVALID, input wire M_AXI_WREADY, `ifdef AXI3 output wire [C_AXI_ID_WIDTH-1:0] M_AXI_WID, `endif output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA, output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB, output wire M_AXI_WLAST, // // input wire M_AXI_BVALID, output reg M_AXI_BREADY, input wire [C_AXI_ID_WIDTH-1:0] M_AXI_BID, input wire [1:0] M_AXI_BRESP, // // output wire M_AXI_ARVALID, input wire M_AXI_ARREADY, output wire [C_AXI_ID_WIDTH-1:0] M_AXI_ARID, output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, `ifdef AXI3 output wire [3:0] M_AXI_ARLEN, `else output wire [7:0] M_AXI_ARLEN, `endif output wire [2:0] M_AXI_ARSIZE, output wire [1:0] M_AXI_ARBURST, `ifdef AXI3 output wire [1:0] M_AXI_ARLOCK, `else output wire M_AXI_ARLOCK, `endif output wire [3:0] M_AXI_ARCACHE, output wire [2:0] M_AXI_ARPROT, output wire [3:0] M_AXI_ARQOS, // input wire M_AXI_RVALID, output wire M_AXI_RREADY, input wire [C_AXI_ID_WIDTH-1:0] M_AXI_RID, input wire [C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA, input wire M_AXI_RLAST, input wire [1:0] M_AXI_RRESP, // output reg o_int // }}} ); // Local parameter definitions // {{{ // The number of beats in this maximum burst size is // automatically determined from LGMAXBURST, and so its // forced to be a power of two this way. // localparam MAXBURST=(1< C_AXIL_DATA_WIDTH) begin r_tbl_addr <= new_widetbl[C_AXI_ADDR_WIDTH-1:0]; end default: begin end endcase end else if (r_busy) begin r_tbl_addr <= tbl_addr; end // }}} // apply_wstrb function // {{{ function [C_AXIL_DATA_WIDTH-1:0] apply_wstrb; input [C_AXIL_DATA_WIDTH-1:0] prior_data; input [C_AXIL_DATA_WIDTH-1:0] new_data; input [C_AXIL_DATA_WIDTH/8-1:0] wstrb; integer k; for(k=0; k