summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axisgdma.v
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
committerAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
commit3038edc09a2eb15762f2e58533f429489107520b (patch)
treef7a45e424d39e6fef0d59e329c1bf6ea206e2886 /rtl/wb2axip/axisgdma.v
parent3b62399f92e9faa2602ac30865e5fc3c7c4e12b8 (diff)
rtl/wb2axip: add to version control
Diffstat (limited to 'rtl/wb2axip/axisgdma.v')
-rw-r--r--rtl/wb2axip/axisgdma.v1120
1 files changed, 1120 insertions, 0 deletions
diff --git a/rtl/wb2axip/axisgdma.v b/rtl/wb2axip/axisgdma.v
new file mode 100644
index 0000000..dac2cbc
--- /dev/null
+++ b/rtl/wb2axip/axisgdma.v
@@ -0,0 +1,1120 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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<<LGMAXBURST);
+ //
+ localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3;
+ localparam AXILLSB= $clog2(C_AXIL_DATA_WIDTH)-3;
+ // localparam LGLENW= LGLEN-ADDRLSB;
+
+ localparam [1:0] CTRL_ADDR = 2'b00,
+ // UNUSED_ADDR = 2'b01,
+ TBLLO_ADDR = 2'b10,
+ TBLHI_ADDR = 2'b11;
+ localparam CTRL_START_BIT = 0,
+ CTRL_BUSY_BIT = 0,
+ CTRL_INT_BIT = 1,
+ CTRL_INTEN_BIT = 2,
+ CTRL_ABORT_BIT = 3,
+ CTRL_ERR_BIT = 4;
+ // CTRL_INTERIM_BIT= 5;
+ localparam [1:0] AXI_INCR = 2'b01, AXI_OKAY = 2'b00;
+
+`ifdef AXI3
+ localparam LENWIDTH = 4;
+`else
+ localparam LENWIDTH = 8;
+`endif
+
+ // DMA device internal addresses
+ // {{{
+ localparam [4:0] DMA_CONTROL= 5'b00000;
+ // }}}
+
+ // localparam [C_AXI_ADDR_WIDTH-1:0] TBL_SIZE
+ // = (C_AXI_ADDR_WIDTH < 30) ? (4*5) : (4*7);
+
+ // }}}
+
+ // Register/net declarations
+ // {{{
+ reg axil_write_ready, axil_read_ready;
+ reg [2*C_AXIL_DATA_WIDTH-1:0] wide_tbl, new_widetbl;
+ reg [C_AXI_ADDR_WIDTH-1:0] tbl_addr, r_tbl_addr;
+ reg r_int_enable, r_int, r_err, r_abort;
+ wire w_int, fsm_err;
+
+ reg [3:0] r_qos;
+ reg [2:0] r_prot;
+ reg r_start;
+ wire r_done, r_busy;
+
+ wire awskd_valid;
+ wire [C_AXIL_ADDR_WIDTH-AXILLSB-1:0] awskd_addr;
+ wire wskd_valid;
+ wire [C_AXIL_DATA_WIDTH-1:0] wskd_data;
+ wire [C_AXIL_DATA_WIDTH/8-1:0] wskd_strb;
+
+ wire arskd_valid;
+ wire [C_AXIL_ADDR_WIDTH-AXILLSB-1:0] arskd_addr;
+
+ // Prefetch interface registers
+ // {{{
+ wire new_pc, pf_ready, pf_clear_cache;
+ wire [C_AXI_ADDR_WIDTH-1:0] ipc;
+ wire [31:0] pf_insn;
+ wire pf_valid, pf_illegal;
+ wire pf_axi_arvalid;
+ reg pf_axi_arready;
+ wire [C_AXI_ADDR_WIDTH-1:0] pf_axi_araddr, pf_pc;
+ wire pf_axi_rready_ignored;
+ wire [C_AXI_ID_WIDTH-1:0] pf_axi_arid;
+ wire [LENWIDTH-1:0] pf_axi_arlen;
+ wire [2:0] pf_axi_arsize;
+ wire [1:0] pf_axi_arburst;
+ wire [3:0] pf_axi_arcache;
+ wire [2:0] pf_axi_arprot;
+ wire [3:0] pf_axi_arqos;
+ // }}}
+
+ // DMA control registers/AXI-lite interface
+ // {{{
+ wire dmac_awready_ignored;
+ reg [4:0] dmac_waddr;
+ //
+ reg dmac_wvalid;
+ wire dmac_wready;
+ reg [31:0] dmac_wdata;
+ reg [3:0] dmac_wstrb;
+ //
+ wire dmac_bvalid;
+ wire [1:0] dmac_bresp;
+ //
+ wire dmac_arready;
+ wire dmac_rvalid;
+ wire [31:0] dmac_rdata;
+ wire [1:0] dmac_rresp;
+ // }}}
+
+ // DMA AXI nets
+ // {{{
+ wire sdma_arvalid;
+ wire [C_AXI_ID_WIDTH-1:0] sdma_arid;
+ wire [C_AXI_ADDR_WIDTH-1:0] sdma_araddr;
+ wire [LENWIDTH-1:0] sdma_arlen;
+ wire [2:0] sdma_arsize;
+ wire [1:0] sdma_arburst;
+ wire [0:0] sdma_arlock;
+ wire [3:0] sdma_arcache;
+ wire [2:0] sdma_arprot;
+ wire [3:0] sdma_arqos;
+ reg sdma_arready;
+ wire sdma_rready_ignored;
+ wire dma_complete;
+
+ wire unused_dma_lock;
+ // }}}
+
+ // Combined AXI nets
+ // {{{
+ reg m_axi_arvalid;
+ reg [C_AXI_ID_WIDTH-1:0] m_axi_arid;
+ reg [C_AXI_ADDR_WIDTH-1:0] m_axi_araddr;
+ reg [LENWIDTH-1:0] m_axi_arlen;
+ reg [2:0] m_axi_arsize;
+ reg [1:0] m_axi_arburst;
+ reg [3:0] m_axi_arcache;
+ reg [2:0] m_axi_arprot;
+ reg [3:0] m_axi_arqos;
+ // }}}
+
+ reg pf_wins_arbitration;
+ wire m_axi_arready;
+
+ // }}}
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-Lite control interface
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Write control logic
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // axil AW skid buffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB)
+ // }}}
+ ) axilawskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+ .i_data(S_AXIL_AWADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+ .o_valid(awskd_valid), .i_ready(axil_write_ready),
+ .o_data(awskd_addr)
+ // }}}
+ );
+ // }}}
+
+ // axil W skid buffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0), .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8)
+ // }}}
+ ) axilwskid (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+ .i_data({ S_AXIL_WSTRB, S_AXIL_WDATA }),
+ .o_valid(wskd_valid), .i_ready(axil_write_ready),
+ .o_data({ wskd_strb, wskd_data })
+ // }}}
+ );
+ // }}}
+
+ // axil_write_ready
+ // {{{
+ always @(*)
+ begin
+ axil_write_ready = !S_AXIL_BVALID || S_AXIL_BREADY;
+ if (!awskd_valid || !wskd_valid)
+ axil_write_ready = 0;
+ end
+ // }}}
+
+ // S_AXIL_BVALID
+ // {{{
+ initial S_AXIL_BVALID = 1'b0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ S_AXIL_BVALID <= 1'b0;
+ else if (!S_AXIL_BVALID || S_AXIL_BREADY)
+ S_AXIL_BVALID <= axil_write_ready;
+ // }}}
+
+ // S_AXIL_BRESP
+ // {{{
+ assign S_AXIL_BRESP = AXI_OKAY;
+ // }}}
+
+ // r_start
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_start <= 1'b0;
+ else begin
+ r_start <= !r_busy && axil_write_ready && wskd_strb[0]
+ && wskd_data[CTRL_START_BIT]
+ && (awskd_addr == CTRL_ADDR);
+ if (r_err && !wskd_data[CTRL_ERR_BIT])
+ r_start <= 0;
+ if (r_abort && !wskd_data[CTRL_ABORT_BIT])
+ r_start <= 0;
+ end
+ // }}}
+
+ // r_err
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_err <= 1'b0;
+ else if (!r_busy)
+ begin
+ if (axil_write_ready)
+ r_err <= (r_err) && (!wskd_strb[0]
+ || !wskd_data[CTRL_ERR_BIT]);
+ end else begin
+ r_err <= r_err || fsm_err;
+ end
+ // }}}
+
+ // o_int
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !r_int_enable || !r_busy)
+ o_int <= 0;
+ else if (w_int)
+ o_int <= 1'b1;
+ // }}}
+
+ // r_int
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_int <= 0;
+ else if (!r_busy)
+ begin
+ if (axil_write_ready && awskd_addr == CTRL_ADDR
+ && wskd_strb[0])
+ begin
+ if (wskd_data[CTRL_START_BIT])
+ r_int <= 0;
+ else if (wskd_data[CTRL_INT_BIT])
+ r_int <= 0;
+ end
+ end else if (w_int)
+ r_int <= 1'b1;
+ // }}}
+
+ // r_abort
+ // {{{
+ initial r_abort = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_abort <= 1'b0;
+ else if (!r_busy)
+ begin
+ if (axil_write_ready && awskd_addr == CTRL_ADDR && wskd_strb[0])
+ begin
+ if(wskd_data[CTRL_START_BIT]
+ ||wskd_data[CTRL_ABORT_BIT]
+ ||wskd_data[CTRL_ERR_BIT])
+ r_abort <= 0;
+ end
+ end else if (!r_abort)
+ r_abort <= (axil_write_ready && awskd_addr == CTRL_ADDR)
+ &&(wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+ // }}}
+
+ // wide_tbl, new_widetbl
+ // {{{
+ always @(*)
+ begin
+ wide_tbl = 0;
+ wide_tbl[C_AXI_ADDR_WIDTH-1:0] = r_tbl_addr;
+
+ new_widetbl = wide_tbl;
+ if (awskd_addr == TBLLO_ADDR)
+ new_widetbl[31:0] = apply_wstrb(wide_tbl[31:0],
+ wskd_data, wskd_strb);
+ if (awskd_addr == TBLHI_ADDR)
+ new_widetbl[63:32] = apply_wstrb(wide_tbl[63:32],
+ wskd_data, wskd_strb);
+ end
+ // }}}
+
+ // r_prot, r_qos, r_int_enable, r_tbl_addr
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ r_prot <= 0;
+ r_qos <= 0;
+ r_int_enable <= 0;
+ end else if (!r_busy && axil_write_ready)
+ begin
+ case(awskd_addr)
+ CTRL_ADDR: begin
+ if (wskd_strb[2])
+ begin
+ r_prot <= wskd_data[22:20];
+ r_qos <= wskd_data[19:16];
+ end
+ if (wskd_strb[0])
+ begin
+ r_int_enable <= wskd_data[CTRL_INTEN_BIT];
+ end end
+ TBLLO_ADDR: begin
+ r_tbl_addr <= new_widetbl[C_AXI_ADDR_WIDTH-1:0];
+ end
+ TBLHI_ADDR: if (C_AXI_ADDR_WIDTH > 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<C_AXIL_DATA_WIDTH/8; k=k+1)
+ begin
+ apply_wstrb[k*8 +: 8] = wstrb[k] ? new_data[k*8 +: 8]
+ : prior_data[k*8 +: 8];
+ end
+ endfunction
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-lite control read interface
+ // {{{
+
+ // AXI-lite AR skid buffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0), .DW(C_AXIL_ADDR_WIDTH-AXILLSB)
+ // }}}
+ ) axilarskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIL_ARVALID), .o_ready(S_AXIL_ARREADY),
+ .i_data(S_AXIL_ARADDR[C_AXIL_ADDR_WIDTH-1:AXILLSB]),
+ .o_valid(arskd_valid), .i_ready(axil_read_ready),
+ .o_data(arskd_addr)
+ // }}}
+ );
+ // }}}
+
+ // axil_read_ready
+ // {{{
+ always @(*)
+ begin
+ axil_read_ready = !S_AXIL_RVALID || S_AXIL_RREADY;
+ if (!arskd_valid)
+ axil_read_ready = 1'b0;
+ end
+ // }}}
+
+ // S_AXIL_RVALID
+ // {{{
+ initial S_AXIL_RVALID = 1'b0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ S_AXIL_RVALID <= 1'b0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ S_AXIL_RVALID <= axil_read_ready;
+ // }}}
+
+ // S_AXIL_RDATA
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ S_AXIL_RDATA <= 0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ begin
+ S_AXIL_RDATA <= 0;
+ case(arskd_addr)
+ CTRL_ADDR: begin
+ S_AXIL_RDATA[CTRL_ERR_BIT] <= r_err;
+ S_AXIL_RDATA[CTRL_ABORT_BIT] <= r_abort;
+ S_AXIL_RDATA[CTRL_INTEN_BIT] <= r_int_enable;
+ S_AXIL_RDATA[CTRL_INT_BIT] <= r_int;
+ S_AXIL_RDATA[CTRL_BUSY_BIT] <= r_busy;
+ end
+ // Unused:
+ TBLLO_ADDR:
+ S_AXIL_RDATA <= wide_tbl[C_AXIL_DATA_WIDTH-1:0];
+ TBLHI_ADDR:
+ S_AXIL_RDATA <= wide_tbl[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ default: begin end
+ endcase
+
+ if (OPT_LOWPOWER && (!axil_read_ready || !arskd_valid))
+ S_AXIL_RDATA <= 0;
+ end
+ // }}}
+
+ // S_AXIL_RRESP
+ // {{{
+ assign S_AXIL_RRESP = AXI_OKAY;
+ // }}}
+ // }}} // AXI-lite read
+ // }}} // AXI-lite (all)
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // DMA wrapper
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // Prefix: dmac for the sub DMA control interface
+ // Prefix: sdma for the sub DMA master interface
+ axidma #(
+ // {{{
+ .C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+ .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .OPT_UNALIGNED(OPT_UNALIGNED),
+ .OPT_WRAPMEM(OPT_WRAPMEM),
+ .LGMAXBURST(LGMAXBURST),
+ .LGFIFO(LGFIFO),
+ .LGLEN(LGLEN),
+ .AXI_READ_ID(DMA_READ_ID),
+ .AXI_WRITE_ID(DMA_WRITE_ID),
+ .ABORT_KEY(ABORT_KEY)
+ // }}}
+ ) subdma(
+ // {{{
+ .S_AXI_ACLK(S_AXI_ACLK),
+ .S_AXI_ARESETN(S_AXI_ARESETN),
+ //
+ // The AXI4-lite control interface
+ // {{{
+ .S_AXIL_AWVALID(dmac_wvalid), // Merge AW & W channels:DMA ok w/
+ .S_AXIL_AWREADY(dmac_awready_ignored),
+ .S_AXIL_AWADDR( dmac_waddr),
+ .S_AXIL_AWPROT( 3'h0), // Internally ignored
+ //
+ .S_AXIL_WVALID(dmac_wvalid),
+ .S_AXIL_WREADY(dmac_wready),
+ .S_AXIL_WDATA( dmac_wdata),
+ .S_AXIL_WSTRB( dmac_wstrb),
+ //
+ .S_AXIL_BVALID(dmac_bvalid),
+ .S_AXIL_BREADY(1'b1),
+ .S_AXIL_BRESP( dmac_bresp),
+ //
+ .S_AXIL_ARVALID(!S_AXI_ARESETN),
+ .S_AXIL_ARREADY(dmac_arready),
+ .S_AXIL_ARADDR( DMA_CONTROL),
+ .S_AXIL_ARPROT( 3'h0), // Internally ignored
+ //
+ .S_AXIL_RVALID(dmac_rvalid),
+ .S_AXIL_RREADY(1'b1),
+ .S_AXIL_RDATA( dmac_rdata),
+ .S_AXIL_RRESP( dmac_rresp),
+ // }}}
+ //
+ // The AXI Master (DMA) interface
+ // {{{
+ .M_AXI_AWVALID(M_AXI_AWVALID),
+ .M_AXI_AWREADY(M_AXI_AWREADY),
+ .M_AXI_AWID( M_AXI_AWID),
+ .M_AXI_AWADDR( M_AXI_AWADDR),
+ .M_AXI_AWLEN( M_AXI_AWLEN),
+ .M_AXI_AWSIZE( M_AXI_AWSIZE),
+ .M_AXI_AWBURST(M_AXI_AWBURST),
+ .M_AXI_AWLOCK( unused_dma_lock),
+ .M_AXI_AWCACHE(M_AXI_AWCACHE),
+ .M_AXI_AWPROT( M_AXI_AWPROT),
+ .M_AXI_AWQOS( M_AXI_AWQOS),
+ //
+ //
+ .M_AXI_WVALID(M_AXI_WVALID),
+ .M_AXI_WREADY(M_AXI_WREADY),
+`ifdef AXI3
+ .M_AXI_WID(M_AXI_WID),
+`endif
+ .M_AXI_WDATA(M_AXI_WDATA),
+ .M_AXI_WSTRB(M_AXI_WSTRB),
+ .M_AXI_WLAST(M_AXI_WLAST),
+ //
+ //
+ .M_AXI_BVALID(M_AXI_BVALID),
+ .M_AXI_BREADY(M_AXI_BREADY),
+ .M_AXI_BID( M_AXI_BID),
+ .M_AXI_BRESP( M_AXI_BRESP),
+ // }}}
+ // AXI master read interface
+ // {{{
+ // The read channel needs to be arbitrated
+ .M_AXI_ARVALID(sdma_arvalid),
+ .M_AXI_ARREADY(sdma_arready),
+ .M_AXI_ARID(sdma_arid),
+ .M_AXI_ARADDR(sdma_araddr),
+ .M_AXI_ARLEN(sdma_arlen),
+ .M_AXI_ARSIZE(sdma_arsize),
+ .M_AXI_ARBURST(sdma_arburst),
+ .M_AXI_ARLOCK(sdma_arlock),
+ .M_AXI_ARCACHE(sdma_arcache),
+ .M_AXI_ARPROT(sdma_arprot),
+ .M_AXI_ARQOS(sdma_arqos),
+ //
+ .M_AXI_RVALID(M_AXI_RVALID && M_AXI_RID == DMA_READ_ID),
+ .M_AXI_RREADY(sdma_rready_ignored), // Known to be one
+ .M_AXI_RID( DMA_READ_ID),
+ .M_AXI_RDATA(M_AXI_RDATA),
+ .M_AXI_RLAST(M_AXI_RLAST),
+ .M_AXI_RRESP(M_AXI_RRESP),
+ // }}}
+ .o_int(dma_complete)
+ // }}}
+ );
+
+ assign M_AXI_AWLOCK = 0;
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-Lite prefetch
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // The AXI_lite fetch submodule
+ // {{{
+ axilfetch #(
+ // {{{
+ .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .FETCH_LIMIT(4)
+ // }}}
+ ) pf (
+ // {{{
+ .S_AXI_ACLK(S_AXI_ACLK),
+ .S_AXI_ARESETN(S_AXI_ARESETN),
+ //
+ // "CPU" interface
+ // {{{
+ .i_cpu_reset(!S_AXI_ARESETN),
+ .i_new_pc(new_pc),
+ .i_clear_cache(pf_clear_cache),
+ .i_ready(pf_ready),
+ .i_pc(ipc),
+ .o_insn(pf_insn),
+ .o_valid(pf_valid),
+ .o_pc(pf_pc),
+ .o_illegal(pf_illegal),
+ // }}}
+ // AXI-lite interface
+ // {{{
+ .M_AXI_ARVALID(pf_axi_arvalid),
+ .M_AXI_ARREADY(pf_axi_arready),
+ .M_AXI_ARADDR( pf_axi_araddr),
+ .M_AXI_ARPROT( pf_axi_arprot),
+ //
+ .M_AXI_RVALID( M_AXI_RVALID && M_AXI_RID == PF_READ_ID),
+ .M_AXI_RREADY( pf_axi_rready_ignored), // Always 1'b1
+ .M_AXI_RDATA( M_AXI_RDATA),
+ .M_AXI_RRESP( M_AXI_RRESP)
+ // }}}
+ // }}}
+ );
+ // }}}
+
+ assign pf_axi_arid = PF_READ_ID;
+ assign pf_axi_arlen = 0; // Only read singletons
+ assign pf_axi_arsize = ADDRLSB[2:0];
+ assign pf_axi_arburst = AXI_INCR;
+ assign pf_axi_arcache = 4'b0011;
+ // assign pf_axi_arprot = 3'b100;
+ assign pf_axi_arqos = 4'h0;
+
+ assign M_AXI_RREADY = 1'b1;
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // PF vs DMA arbiter
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // pf_wins_arbitration
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!m_axi_arvalid || m_axi_arready)
+ begin
+ if (pf_axi_arvalid && !sdma_arvalid)
+ pf_wins_arbitration <= 1'b1;
+ else
+ pf_wins_arbitration <= 1'b0;
+ end
+ // }}}
+
+ // m_axi_*
+ // {{{
+ always @(*)
+ begin
+ if (pf_wins_arbitration)
+ begin
+ m_axi_arvalid = pf_axi_arvalid;
+ m_axi_arid = pf_axi_arid;
+ m_axi_araddr = pf_axi_araddr;
+ m_axi_arlen = pf_axi_arlen;
+ m_axi_arsize = pf_axi_arsize;
+ m_axi_arburst = pf_axi_arburst;
+ m_axi_arcache = pf_axi_arcache;
+ m_axi_arprot = pf_axi_arprot;
+ m_axi_arqos = pf_axi_arqos;
+ end else begin
+ m_axi_arvalid = sdma_arvalid;
+ m_axi_arid = sdma_arid;
+ m_axi_araddr = sdma_araddr;
+ m_axi_arlen = sdma_arlen;
+ m_axi_arsize = sdma_arsize;
+ m_axi_arburst = sdma_arburst;
+ m_axi_arcache = sdma_arcache;
+ m_axi_arprot = sdma_arprot;
+ m_axi_arqos = sdma_arqos;
+ end
+ end
+ // }}}
+
+ // *_arready
+ // {{{
+ always @(*)
+ begin
+ sdma_arready = m_axi_arready && !pf_wins_arbitration;
+ pf_axi_arready = m_axi_arready && pf_wins_arbitration;
+ end
+ // }}}
+
+ // Outgoing AR skid buffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_OUTREG(1'b1),
+ .DW(C_AXI_ID_WIDTH + C_AXI_ADDR_WIDTH + LENWIDTH
+ + 3 + 2 + 4 +3 + 4)
+ // }}}
+ ) marskd(
+ // {{{
+ S_AXI_ACLK, !S_AXI_ARESETN, m_axi_arvalid, m_axi_arready,
+ { m_axi_arid, m_axi_araddr, m_axi_arlen, m_axi_arsize,
+ m_axi_arburst, m_axi_arcache,
+ m_axi_arprot, m_axi_arqos },
+ M_AXI_ARVALID, M_AXI_ARREADY,
+ { M_AXI_ARID, M_AXI_ARADDR, M_AXI_ARLEN, M_AXI_ARSIZE,
+ M_AXI_ARBURST, M_AXI_ARCACHE,
+ M_AXI_ARPROT, M_AXI_ARQOS }
+ // }}}
+ );
+
+`ifdef AXI3
+ assign M_AXI_ARLOCK = 2'b00; // We don't use lock anyway
+`else
+ assign M_AXI_ARLOCK = 1'b0;
+`endif
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // FSM Control states
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ axisgfsm #(
+ // {{{
+ .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .ABORT_KEY(ABORT_KEY)
+ // }}}
+ ) fsm (
+ // {{{
+ .S_AXI_ACLK(S_AXI_ACLK),
+ .S_AXI_ARESETN(S_AXI_ARESETN),
+ // Control interface
+ // {{{
+ .i_start(r_start),
+ .i_abort(r_abort),
+ .i_tbl_addr(r_tbl_addr),
+ .i_qos(r_qos),
+ .i_prot(r_prot),
+ .o_done(r_done),
+ .o_busy(r_busy),
+ .o_int(w_int),
+ .o_err(fsm_err),
+ .o_tbl_addr(tbl_addr),
+ // }}}
+ // Prefetch interface
+ // {{{
+ .o_new_pc(new_pc),
+ .o_pf_clear_cache(pf_clear_cache),
+ .o_pf_ready(pf_ready),
+ .o_pf_pc(ipc),
+ .i_pf_valid(pf_valid),
+ .i_pf_insn(pf_insn),
+ .i_pf_pc(pf_pc),
+ .i_pf_illegal(pf_illegal),
+ // }}}
+ // DMA AXI-lite control interface
+ // {{{
+ .o_dmac_wvalid(dmac_wvalid),
+ .i_dmac_wready(dmac_wready),
+ .o_dmac_waddr(dmac_waddr),
+ .o_dmac_wdata(dmac_wdata),
+ .o_dmac_wstrb(dmac_wstrb),
+ .i_dmac_rdata(dmac_rdata),
+ .i_dma_complete(dma_complete)
+ // }}}
+
+ // }}}
+ );
+
+ // }}}
+
+ // Make Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, dmac_awready_ignored, dmac_bvalid,
+ dmac_bresp, dmac_rvalid, dmac_rresp,
+ S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_AWPROT,
+ S_AXIL_ARADDR[AXILLSB-1:0], S_AXIL_ARPROT,
+ M_AXI_RREADY, r_done,
+ new_widetbl[63:C_AXI_ADDR_WIDTH],
+ unused_dma_lock,
+ sdma_arlock, sdma_rready_ignored,
+ pf_axi_rready_ignored, dmac_arready };
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties (neither written, nor tested)
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The full formal verification of this core has not been completed.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ reg f_past_valid;
+
+ initial f_past_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ f_past_valid <= 1;
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The control interface
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ faxil_slave #(
+ .C_AXI_DATA_WIDTH(C_AXIL_DATA_WIDTH),
+ .C_AXI_ADDR_WIDTH(C_AXIL_ADDR_WIDTH)
+ //
+ // ...
+ //
+ )
+ faxil(
+ .i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(S_AXIL_AWVALID),
+ .i_axi_awready(S_AXIL_AWREADY),
+ .i_axi_awaddr(S_AXIL_AWADDR),
+ .i_axi_awprot(S_AXIL_AWPROT),
+ //
+ .i_axi_wvalid(S_AXIL_WVALID),
+ .i_axi_wready(S_AXIL_WREADY),
+ .i_axi_wdata( S_AXIL_WDATA),
+ .i_axi_wstrb( S_AXIL_WSTRB),
+ //
+ .i_axi_bvalid(S_AXIL_BVALID),
+ .i_axi_bready(S_AXIL_BREADY),
+ .i_axi_bresp( S_AXIL_BRESP),
+ //
+ .i_axi_arvalid(S_AXIL_ARVALID),
+ .i_axi_arready(S_AXIL_ARREADY),
+ .i_axi_araddr( S_AXIL_ARADDR),
+ .i_axi_arprot( S_AXIL_ARPROT),
+ //
+ .i_axi_rvalid(S_AXIL_RVALID),
+ .i_axi_rready(S_AXIL_RREADY),
+ .i_axi_rdata( S_AXIL_RDATA),
+ .i_axi_rresp( S_AXIL_RRESP)
+ //
+ // ...
+ //
+ );
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The main AXI data interface
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Formal contract checking
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover checks
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Careless assumptions (i.e. constraints)
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // None (currently)
+
+ // }}}
+`endif
+// }}}
+endmodule