summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/aximm2s.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/aximm2s.v
parent3b62399f92e9faa2602ac30865e5fc3c7c4e12b8 (diff)
rtl/wb2axip: add to version control
Diffstat (limited to 'rtl/wb2axip/aximm2s.v')
-rw-r--r--rtl/wb2axip/aximm2s.v2158
1 files changed, 2158 insertions, 0 deletions
diff --git a/rtl/wb2axip/aximm2s.v b/rtl/wb2axip/aximm2s.v
new file mode 100644
index 0000000..b4c1056
--- /dev/null
+++ b/rtl/wb2axip/aximm2s.v
@@ -0,0 +1,2158 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: aximm2s
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: Converts an AXI (full) memory port to an AXI-stream
+// interface.
+// // {{{
+// While I am aware that other vendors sell similar components, if you
+// look under the hood you'll find no relation to anything but my own
+// work here.
+//
+// Registers:
+//
+// 0: CMD_CONTROL
+// Controls the transaction via either starting or aborting an
+// ongoing transaction, provides feedback regarding the current
+// status.
+//
+// [31] r_busy
+// True if the core is in the middle of a transaction
+//
+// [30] r_err
+// True if the core has detected an error, a bus error
+// while the FIFO is reading.
+//
+// Writing a '1' to this bit while the core is idle will clear it.
+// New transfers will not start until this bit is cleared.
+//
+// [29] r_complete
+// True if the transaction has completed, whether normally or
+// abnormally (error or abort).
+//
+// Any write to the CMD_CONTROL register will clear this flag.
+//
+// [28] r_continuous
+// Normally the FIFO gets cleared and reset between operations.
+// However, if you set r_continuous, the core will then expect
+// a second operation to take place following the first one.
+// In this case, the operation will complete but the FIFO won't
+// get cleared. During this time, the FIFO will not fill further.
+//
+// Any write to the CMD_CONTROL register while the core is not
+// busy will adjust this bit.
+//
+// [27] !r_increment
+//
+// If clear, the core reads from subsequent and incrementing
+// addresses. If set, the core reads from the same address
+// throughout a transaction.
+//
+// Writes to CMD_CONTROL while the core is idle will adjust this
+// bit.
+//
+// [20:16] LGFIFO
+// These are read-only bits, returning the size of the FIFO.
+//
+// ABORT
+// If the core is busy, and ABORT_KEY (currently set to 8'h6d
+// below) is written to the top 8-bits of this register,
+// the current transfer will be aborted. Any pending reads
+// will be completed, but nothing more will be written to the
+// stream.
+//
+// Alternatively, the core will enter into an abort state
+// following any returned bus error indications.
+//
+// 4: (Unused and reserved)
+//
+// 8-c: CMD_ADDRLO, CMD_ADDR_HI
+// [C_AXI_ADDR_WIDTH-1:($clog2(C_AXI_DATA_WIDTH)-3)]
+// If idle, the address the core will read from when it starts.
+// If busy, the address the core is currently reading from.
+// Upon completion, the address either returns to the starting
+// address (if r_continuous is clear), or otherwise becomes the
+// address where the core left off. In the case of an abort or an
+// error, this will be (near) the address that was last read.
+//
+// Why "near"? Because this address records the reads that have
+// been issued while no error is pending. If a bus error return
+// comes back, there may have been several more reads issued before
+// that error address.
+//
+// 10-14: (Unused and reserved)
+//
+// 18-1c: CMD_LENLO, CMD_LENHI
+// [LGLEN-1:0]
+// The size of the transfer in bytes. Only accepts aligned
+// addresses, therefore bits [($clog2(C_AXI_DATA_WIDTH)-3):0]
+// will always be forced to zero. To find out what size bus
+// this core is conencted to, or the maximum transfer length,
+// write a -1 to this value and read the returning result.
+// Only the active bits will be set.
+//
+// While the core is busy, reads from this address will return
+// the number of items still to be read from the bus.
+//
+// I hope to eventually add support for unaligned bursts. Such
+// support is not currently part of this core.
+//
+// }}}
+//
+// Status:
+// {{{
+// 1. The core passes both cover checks and formal property (assertion)
+// based checks. It has not (yet) been tested in real hardware.
+//
+// 2. I'd like to support unaligned addresses and lengths. This will
+// require aligning the data coming out of the FIFO as well.
+// As written, the core doesn't yet support these.
+//
+// }}}
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-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
+// }}}
+module aximm2s #(
+ // {{{
+ parameter C_AXI_ADDR_WIDTH = 32,
+ parameter C_AXI_DATA_WIDTH = 32,
+ parameter C_AXI_ID_WIDTH = 1,
+ //
+ // We support five 32-bit AXI-lite registers, requiring 5-bits
+ // of AXI-lite addressing
+ localparam C_AXIL_ADDR_WIDTH = 5,
+ localparam C_AXIL_DATA_WIDTH = 32,
+ //
+ // The bottom ADDRLSB bits of any AXI address are subword bits
+ localparam ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3,
+ localparam AXILLSB = $clog2(C_AXIL_DATA_WIDTH)-3,
+ //
+ // OPT_UNALIGNED: Allow unaligned accesses, address requests
+ // and sizes which may or may not match the underlying data
+ // width. If set, the core will quietly align these requests.
+ parameter [0:0] OPT_UNALIGNED = 1'b0,
+ //
+ // OPT_TKEEP [Future]: If set, will also add TKEEP signals to
+ // the outgoing slave interface. This is necessary if ever you
+ // wish to output partial stream words, such as might happen if
+ // the length were ever something other than a full number of
+ // words. (Not yet implemented)
+ // parameter [0:0] OPT_TKEEP = 1'b0,
+ //
+ // OPT_TLAST: If enabled, will embed TLAST=1 at the end of every
+ // commanded burst. If disabled, TLAST will be set to a
+ // constant 1'b1.
+ parameter [0:0] OPT_TLAST = 1'b0,
+ //
+ parameter [0:0] OPT_LOWPOWER = 1'b0,
+ parameter [0:0] OPT_CLKGATE = OPT_LOWPOWER,
+ //
+ // ABORT_KEY is the value that, when written to the top 8-bits
+ // of the control word, will abort any ongoing operation.
+ parameter [7:0] ABORT_KEY = 8'h6d,
+ //
+ // The size of the FIFO
+ parameter LGFIFO = 9,
+ //
+ // Maximum number of bytes that can ever be transferred, in
+ // log-base 2
+ parameter LGLEN = 20,
+ //
+ // AXI_ID is the ID we will use for all of our AXI transactions
+ parameter AXI_ID = 0
+ // }}}
+ ) (
+ // {{{
+ input wire S_AXI_ACLK,
+ input wire S_AXI_ARESETN,
+ //
+ // The stream interface
+ // {{{
+ output wire M_AXIS_TVALID,
+ input wire M_AXIS_TREADY,
+ output wire [C_AXI_DATA_WIDTH-1:0] M_AXIS_TDATA,
+ output wire M_AXIS_TLAST,
+ // }}}
+ //
+ // The 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 wire 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 wire S_AXIL_RVALID,
+ input wire S_AXIL_RREADY,
+ output wire [C_AXIL_DATA_WIDTH-1:0] S_AXIL_RDATA,
+ output wire [1:0] S_AXIL_RRESP,
+ // }}}
+ //
+
+ //
+ // The AXI (full) read interface
+ // {{{
+ 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,
+ output wire [7:0] M_AXI_ARLEN,
+ output wire [2:0] M_AXI_ARSIZE,
+ output wire [1:0] M_AXI_ARBURST,
+ output wire M_AXI_ARLOCK,
+ 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_DATA_WIDTH-1:0] M_AXI_RDATA,
+ input wire M_AXI_RLAST,
+ input wire [C_AXI_ID_WIDTH-1:0] M_AXI_RID,
+ input wire [1:0] M_AXI_RRESP,
+ // }}}
+ //
+ //
+ // Create an output signal to indicate that we've finished
+ output reg o_int
+ // }}}
+ );
+
+ // Local parameter declarations
+ // {{{
+ localparam [2:0] CMD_CONTROL = 3'b000,
+ // CMD_UNUSED_1 = 3'b001,
+ CMD_ADDRLO = 3'b010,
+ CMD_ADDRHI = 3'b011,
+ // CMD_UNUSED_2 = 3'b100,
+ // CMD_UNUSED_3 = 3'b101,
+ CMD_LENLO = 3'b110,
+ CMD_LENHI = 3'b111;
+ localparam CBIT_BUSY = 31,
+ CBIT_ERR = 30,
+ CBIT_COMPLETE = 29,
+ CBIT_CONTINUOUS = 28,
+ CBIT_INCREMENT = 27;
+ localparam TMP_LGMAXBURST=(LGFIFO > 8) ? 8 : LGFIFO-1;
+ localparam LGMAXBURST = ((4096/(C_AXI_DATA_WIDTH/8))
+ > (1<<TMP_LGMAXBURST))
+ ? TMP_LGMAXBURST : $clog2(4096 * 8 / C_AXI_DATA_WIDTH);
+ localparam LGMAX_FIXED_BURST = (LGMAXBURST < 4) ? LGMAXBURST : 4,
+ MAX_FIXED_BURST = (1<<LGMAX_FIXED_BURST);
+ localparam LGLENW = LGLEN - ($clog2(C_AXI_DATA_WIDTH)-3),
+ LGLENWA = LGLENW + (OPT_UNALIGNED ? 1:0);
+ // localparam LGFIFOB = LGFIFO + ($clog2(C_AXI_DATA_WIDTH)-3);
+ // localparam [ADDRLSB-1:0] LSBZEROS = 0;
+ // }}}
+
+ // Signal declarations
+ // {{{
+ wire clk_active, gated_clk;
+ wire i_clk = gated_clk;
+ wire i_reset = !S_AXI_ARESETN;
+
+ reg r_busy, r_err, r_complete, r_continuous, r_increment,
+ cmd_abort, zero_length,
+ w_cmd_start, w_complete, w_cmd_abort, r_pre_start;
+ // reg cmd_start;
+ reg axi_abort_pending;
+
+ reg [LGLENWA-1:0] ar_requests_remaining,
+ ar_bursts_outstanding,
+ ar_next_remaining;
+ reg [LGMAXBURST:0] r_max_burst;
+ reg [C_AXI_ADDR_WIDTH-1:0] axi_raddr;
+
+ reg [C_AXI_ADDR_WIDTH-1:0] cmd_addr;
+ reg [LGLENW-1:0] cmd_length_w;
+ reg [LGLENWA-1:0] cmd_length_aligned_w;
+ reg unaligned_cmd_addr;
+
+ // FIFO signals
+ wire reset_fifo, write_to_fifo,
+ read_from_fifo;
+ wire [C_AXI_DATA_WIDTH-1:0] write_data;
+ wire [LGFIFO:0] fifo_fill;
+ wire fifo_full, fifo_empty;
+
+ wire awskd_valid, axil_write_ready;
+ 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;
+ reg axil_bvalid;
+ //
+ wire arskd_valid, axil_read_ready;
+ wire [C_AXIL_ADDR_WIDTH-AXILLSB-1:0] arskd_addr;
+ reg [C_AXIL_DATA_WIDTH-1:0] axil_read_data;
+ reg axil_read_valid;
+ reg [C_AXIL_DATA_WIDTH-1:0] w_status_word;
+ reg [2*C_AXIL_DATA_WIDTH-1:0] wide_address, wide_length,
+ new_wideaddr, new_widelen;
+ wire [C_AXIL_DATA_WIDTH-1:0] new_cmdaddrlo, new_cmdaddrhi,
+ new_lengthlo, new_lengthhi;
+
+
+
+ reg axi_arvalid;
+ reg [C_AXI_ADDR_WIDTH-1:0] axi_araddr;
+ reg [7:0] axi_arlen;
+
+ // Speed up checking for zeros
+ reg ar_none_remaining,
+ ar_none_outstanding,
+ phantom_start, start_burst;
+ reg ar_multiple_full_bursts,
+ ar_multiple_fixed_bursts,
+ ar_multiple_bursts_remaining,
+ ar_needs_alignment;
+ wire partial_burst_requested;
+ reg [LGMAXBURST-1:0] addralign;
+ reg [LGFIFO:0] rd_uncommitted;
+ reg [LGMAXBURST:0] initial_burstlen;
+ reg [LGLENWA-1:0] rd_reads_remaining;
+ reg rd_none_remaining,
+ rd_last_remaining;
+
+ wire realign_last_valid;
+/*
+ wr_none_pending, r_none_remaining;
+
+ reg w_phantom_start, phantom_start;
+ reg [LGFIFO:0] next_fill;
+*/
+
+ // }}}
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-lite signaling
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // This is mostly the skidbuffer logic, and handling of the VALID
+ // and READY signals for the AXI-lite control logic in the next
+ // section.
+ //
+
+ //
+ // Write signaling
+ //
+ // {{{
+
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0),
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .DW(C_AXIL_ADDR_WIDTH-AXILLSB)
+ // }}}
+ ) axilawskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(i_reset),
+ .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)
+ // }}}
+ );
+
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0),
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .DW(C_AXIL_DATA_WIDTH+C_AXIL_DATA_WIDTH/8)
+ // }}}
+ ) axilwskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(i_reset),
+ .i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+ .i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+ .o_valid(wskd_valid), .i_ready(axil_write_ready),
+ .o_data({ wskd_data, wskd_strb })
+ // }}}
+ );
+
+ assign axil_write_ready = clk_active && awskd_valid && wskd_valid
+ && (!S_AXIL_BVALID || S_AXIL_BREADY);
+
+ initial axil_bvalid = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ axil_bvalid <= 0;
+ else if (axil_write_ready)
+ axil_bvalid <= 1;
+ else if (S_AXIL_BREADY)
+ axil_bvalid <= 0;
+
+ assign S_AXIL_BVALID = axil_bvalid;
+ assign S_AXIL_BRESP = 2'b00;
+ // }}}
+
+ //
+ // Read signaling
+ //
+ // {{{
+
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0),
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .DW(C_AXIL_ADDR_WIDTH-AXILLSB)
+ // }}}
+ ) axilarskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(i_reset),
+ .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)
+ // }}}
+ );
+
+ assign axil_read_ready = clk_active && arskd_valid
+ && (!axil_read_valid || S_AXIL_RREADY);
+
+ initial axil_read_valid = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ axil_read_valid <= 1'b0;
+ else if (axil_read_ready)
+ axil_read_valid <= 1'b1;
+ else if (S_AXIL_RREADY)
+ axil_read_valid <= 1'b0;
+
+ assign S_AXIL_RVALID = axil_read_valid;
+ assign S_AXIL_RDATA = axil_read_data;
+ assign S_AXIL_RRESP = 2'b00;
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-lite controlled logic
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // w_cmd_abort, cmd_abort : Abort transaction
+ // {{{
+ always @(*)
+ begin
+ w_cmd_abort = 0;
+ w_cmd_abort = (axil_write_ready && awskd_addr == CMD_CONTROL)
+ && (wskd_strb[3] && wskd_data[31:24] == ABORT_KEY);
+ if (!r_busy)
+ w_cmd_abort = 0;
+ end
+
+ initial cmd_abort = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ cmd_abort <= 0;
+ else
+ cmd_abort <= (cmd_abort && r_busy)||w_cmd_abort;
+ // }}}
+
+ // w_cmd_start: Start command
+ // {{{
+ always @(*)
+ if (r_busy)
+ w_cmd_start = 0;
+ else begin
+ w_cmd_start = 0;
+ if ((axil_write_ready && awskd_addr == CMD_CONTROL)
+ && (wskd_strb[3] && wskd_data[CBIT_BUSY]))
+ w_cmd_start = 1;
+ if (r_err && !wskd_data[CBIT_ERR])
+ w_cmd_start = 0;
+ if (zero_length)
+ w_cmd_start = 0;
+ if (OPT_UNALIGNED && unaligned_cmd_addr
+ && wskd_data[CBIT_INCREMENT])
+ w_cmd_start = 0;
+ end
+ // }}}
+
+ // r_busy, r_complete: Calculate busy or complete flags
+ // {{{
+ initial r_busy = 0;
+ initial r_complete = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ r_busy <= 0;
+ r_complete <= 0;
+ end else if (!r_busy)
+ begin
+ if (w_cmd_start)
+ r_busy <= 1'b1;
+ if (axil_write_ready && awskd_addr == CMD_CONTROL)
+ // Any write to the control register will clear the
+ // completion flag
+ r_complete <= 1'b0;
+ end else if (r_busy)
+ begin
+ if (w_complete)
+ begin
+ r_complete <= 1;
+ r_busy <= 1'b0;
+ end
+ end
+ // }}}
+
+ // o_int: Interrupts
+ // {{{
+ initial o_int = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ o_int <= 0;
+ else
+ o_int <= (r_busy && w_complete);
+ // }}}
+
+ // r_err : Error conditions
+ // {{{
+ always @(posedge i_clk)
+ if (i_reset)
+ r_err <= 0;
+ else if (!r_busy)
+ begin
+ if (axil_write_ready && awskd_addr == CMD_CONTROL)
+ begin
+ if (!w_cmd_abort)
+ r_err <= r_err && (!wskd_strb[3] || !wskd_data[CBIT_ERR]);
+ // On any request to start a transfer with an unaligned
+ // address, that's not incrementing--declare an
+ // immediate error
+ if (wskd_strb[3] && wskd_data[CBIT_BUSY]
+ && wskd_data[CBIT_INCREMENT]
+ && (OPT_UNALIGNED && unaligned_cmd_addr))
+ r_err <= 1'b1;
+ end
+ end else // if (r_busy)
+ begin
+ if (M_AXI_RVALID && M_AXI_RREADY && M_AXI_RRESP[1])
+ r_err <= 1'b1;
+ end
+ // }}}
+
+ // r_continuous
+ // {{{
+ initial r_continuous = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ r_continuous <= 0;
+ else begin
+ if (!r_busy && axil_write_ready && awskd_addr == CMD_CONTROL
+ && !w_cmd_abort)
+ r_continuous <= wskd_strb[3] && wskd_data[CBIT_CONTINUOUS];
+ end
+ // }}}
+
+ // wide_address, wide_length
+ // {{{
+ always @(*)
+ begin
+ wide_address = 0;
+ wide_address[C_AXI_ADDR_WIDTH-1:0] = cmd_addr;
+ if (!OPT_UNALIGNED)
+ wide_address[ADDRLSB-1:0] = 0;
+
+ wide_length = 0;
+ wide_length[ADDRLSB +: LGLENW] = cmd_length_w;
+ end
+ // }}}
+
+ // new_cmdaddr*
+ // {{{
+ assign new_cmdaddrlo = apply_wstrb(
+ wide_address[C_AXIL_DATA_WIDTH-1:0],
+ wskd_data, wskd_strb);
+
+ assign new_cmdaddrhi = apply_wstrb(
+ wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+ wskd_data, wskd_strb);
+ // }}}
+
+ // new_length*
+ // {{{
+ assign new_lengthlo = apply_wstrb(
+ wide_length[C_AXIL_DATA_WIDTH-1:0],
+ wskd_data, wskd_strb);
+
+ assign new_lengthhi = apply_wstrb(
+ wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+ wskd_data, wskd_strb);
+ // }}}
+
+ always @(*)
+ begin
+ new_wideaddr = wide_address;
+
+ if (awskd_addr == CMD_ADDRLO)
+ new_wideaddr[C_AXIL_DATA_WIDTH-1:0] = new_cmdaddrlo;
+ if (awskd_addr == CMD_ADDRHI)
+ new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_cmdaddrhi;
+ if (!OPT_UNALIGNED)
+ new_wideaddr[ADDRLSB-1:0] = 0;
+ new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+
+
+ new_widelen = wide_length;
+ if (awskd_addr == CMD_LENLO)
+ new_widelen[C_AXIL_DATA_WIDTH-1:0] = new_lengthlo;
+ if (awskd_addr == CMD_LENHI)
+ new_widelen[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH] = new_lengthhi;
+ new_widelen[ADDRLSB-1:0] = 0;
+ new_widelen[2*C_AXIL_DATA_WIDTH-1:ADDRLSB+LGLENW] = 0;
+ end
+
+
+ initial r_increment = 1'b1;
+ initial cmd_addr = 0;
+ initial cmd_length_w = 0; // Counts in bytes
+ initial zero_length = 1;
+ initial cmd_length_aligned_w = 0;
+ initial unaligned_cmd_addr = 1'b0;
+ initial ar_multiple_full_bursts = 0;
+ initial ar_multiple_fixed_bursts = 0;
+ always @(posedge i_clk)
+ begin
+ if (axil_write_ready && !r_busy)
+ begin
+ case(awskd_addr)
+ CMD_CONTROL:
+ r_increment <= !wskd_data[CBIT_INCREMENT];
+ CMD_ADDRLO: begin
+ cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+ unaligned_cmd_addr <= |new_wideaddr[ADDRLSB-1:0];
+ if (OPT_UNALIGNED)
+ cmd_length_aligned_w <= cmd_length_w
+ + (|new_wideaddr[ADDRLSB-1:0] ? 1:0);
+ // ERR: What if !r_increment? In that case, we can't
+ // support unaligned addressing
+ end
+ CMD_ADDRHI: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH)
+ begin
+ cmd_addr <= new_wideaddr[C_AXI_ADDR_WIDTH-1:0];
+ end
+ CMD_LENLO: begin
+ cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+ zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+ cmd_length_aligned_w <= new_widelen[ADDRLSB +: LGLENW]
+ + (unaligned_cmd_addr ? 1:0);
+ ar_multiple_full_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAXBURST)];
+ ar_multiple_fixed_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAX_FIXED_BURST)];
+ end
+ CMD_LENHI: begin
+ cmd_length_w <= new_widelen[ADDRLSB +: LGLENW];
+ zero_length <= (new_widelen[ADDRLSB +: LGLENW] == 0);
+ cmd_length_aligned_w <= new_widelen[ADDRLSB +: LGLENW]
+ + (unaligned_cmd_addr ? 1:0);
+ ar_multiple_full_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAXBURST)];
+ ar_multiple_fixed_bursts <= |new_widelen[LGLEN-1:(ADDRLSB+LGMAX_FIXED_BURST)];
+ end
+ default: begin end
+ endcase
+ end else if(r_busy && r_continuous && !axi_abort_pending
+ && r_increment)
+ cmd_addr <= axi_raddr
+ + ((M_AXI_RVALID && !M_AXI_RRESP[1]
+ && (!unaligned_cmd_addr || realign_last_valid))
+ ? (1<<ADDRLSB) : 0);
+
+ if (i_reset)
+ begin
+ r_increment <= 1'b1;
+ cmd_addr <= 0;
+ cmd_length_w <= 0;
+ zero_length <= 1;
+ unaligned_cmd_addr <= 0;
+ cmd_length_aligned_w <= 0;
+ ar_multiple_full_bursts <= 0;
+ ar_multiple_fixed_bursts <= 0;
+ end
+
+ if (!OPT_UNALIGNED)
+ unaligned_cmd_addr <= 0;
+ end
+
+ // w_status_word
+ // {{{
+ always @(*)
+ begin
+ w_status_word = 0;
+ w_status_word[CBIT_BUSY] = r_busy;
+ w_status_word[CBIT_ERR] = r_err;
+ w_status_word[CBIT_COMPLETE] = r_complete;
+ w_status_word[CBIT_CONTINUOUS] = r_continuous;
+ w_status_word[CBIT_INCREMENT] = !r_increment;
+ w_status_word[20:16] = LGFIFO;
+ end
+ // }}}
+
+ // axil_read_data
+ // {{{
+ always @(posedge i_clk)
+ if (!axil_read_valid || S_AXIL_RREADY)
+ begin
+ axil_read_data <= 0;
+ case(arskd_addr)
+ CMD_CONTROL: axil_read_data <= w_status_word;
+ CMD_ADDRLO: axil_read_data <= wide_address[C_AXIL_DATA_WIDTH-1:0];
+ CMD_ADDRHI: axil_read_data <= wide_address[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ CMD_LENLO: axil_read_data <= wide_length[C_AXIL_DATA_WIDTH-1:0];
+ CMD_LENHI: axil_read_data <= wide_length[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ default axil_read_data <= 0;
+ endcase
+
+ if (OPT_LOWPOWER && !axil_read_ready)
+ axil_read_data <= 0;
+ end
+ // }}}
+
+ 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
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The data FIFO section
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ assign reset_fifo = i_reset || (!r_busy && (!r_continuous || r_err));
+
+ // Realign the data (if OPT_UNALIGN) before sending it to the FIFO
+ // {{{
+ // This allows us to handle unaligned addresses.
+ generate if (OPT_UNALIGNED)
+ begin : REALIGN_DATA
+
+ reg r_write_to_fifo;
+ reg [C_AXI_DATA_WIDTH-1:0] last_data,
+ r_write_data;
+ reg [ADDRLSB-1:0] corollary_shift;
+ reg last_valid;
+ reg [ADDRLSB-1:0] realignment;
+
+ always @(*)
+ realignment = cmd_addr[ADDRLSB-1:0];
+
+ initial last_data = 0;
+ always @(posedge i_clk)
+ if (reset_fifo || !unaligned_cmd_addr)
+ last_data <= 0;
+ else if (M_AXI_RVALID && M_AXI_RREADY)
+ last_data <= M_AXI_RDATA >> (realignment * 8);
+
+ initial last_valid = 1'b0;
+ always @(posedge i_clk)
+ if (reset_fifo)
+ last_valid <= 0;
+ else if (M_AXI_RVALID && M_AXI_RREADY)
+ last_valid <= 1'b1;
+ else if (!r_busy)
+ last_valid <= 1'b0;
+
+ assign realign_last_valid = last_valid;
+
+ always @(*)
+ corollary_shift = -realignment;
+
+ always @(posedge i_clk)
+ if (M_AXI_RVALID && M_AXI_RREADY)
+ r_write_data <= (M_AXI_RDATA << (corollary_shift*8))
+ | last_data;
+ else if (!fifo_full)
+ r_write_data <= last_data;
+
+ initial r_write_to_fifo = 1'b0;
+ always @(posedge i_clk)
+ if (reset_fifo)
+ r_write_to_fifo <= 1'b0;
+ else if (M_AXI_RVALID && M_AXI_RREADY)
+ r_write_to_fifo <= last_valid || !unaligned_cmd_addr;
+ else if (!fifo_full)
+ r_write_to_fifo <= 1'b0;
+
+ assign write_to_fifo = r_write_to_fifo;
+ assign write_data = r_write_data;
+
+ end else begin : ALIGNED_DATA
+
+ assign write_to_fifo = M_AXI_RVALID && M_AXI_RREADY;
+ assign write_data = M_AXI_RDATA;
+ assign realign_last_valid = 0;
+
+ end endgenerate
+ // }}}
+
+ assign read_from_fifo = M_AXIS_TVALID && M_AXIS_TREADY;
+ assign M_AXIS_TVALID = !fifo_empty;
+
+ // Write the results to the FIFO
+ // {{{
+ generate if (OPT_TLAST)
+ begin : FIFO_W_TLAST
+ // FIFO section--used if we have to add a TLAST signal to the
+ // data stream
+ // {{{
+ reg pre_tlast;
+ wire tlast;
+
+ // tlast will be set on the last data word of any commanded
+ // burst.
+
+ // Appropriately, pre_tlast = (something) && M_AXI_RVALID
+ // && M_AXI_RREADY && M_AXI_RLAST
+ // We can simplify this greatly, since any time M_AXI_RVALID is
+ // true, we also know that M_AXI_RREADY will be true. This
+ // allows us to get rid of the RREADY condition. Next, we can
+ // simplify the RVALID condition since we'll never write to the
+ // FIFO if RVALID isn't also true. Finally, we can get rid of
+ // M_AXI_RLAST since this is captured by rd_last_remaining.
+ always @(*)
+ pre_tlast = rd_last_remaining;
+
+ if (OPT_UNALIGNED)
+ begin : GEN_UNALIGNED_TLAST
+ reg r_tlast;
+
+ // REALIGN delays the data by one clock period. We'll
+ // also need to delay the last as well.
+ // Note that no one cares what tlast is if write_to_fifo
+ // is zero, allowing us to massively simplify this.
+ always @(posedge i_clk)
+ r_tlast <= pre_tlast;
+
+ assign tlast = r_tlast;
+
+ end else begin : NO_UNALIGNED_TLAST
+
+ assign tlast = pre_tlast;
+ end
+
+
+ sfifo #(
+ // {{{
+ .BW(C_AXI_DATA_WIDTH+1), .LGFLEN(LGFIFO)
+ // }}}
+ ) sfifo(
+ // {{{
+ i_clk, reset_fifo,
+ write_to_fifo, { tlast, write_data }, fifo_full, fifo_fill,
+ read_from_fifo, { M_AXIS_TLAST, M_AXIS_TDATA }, fifo_empty
+ // }}}
+ );
+ // }}}
+ end else begin : NO_TLAST_FIFO
+
+ // FIFO section, where TLAST is held at 1'b1
+ // {{{
+ sfifo #(
+ // {{{
+ .BW(C_AXI_DATA_WIDTH), .LGFLEN(LGFIFO)
+ // }}}
+ ) sfifo(
+ // {{{
+ i_clk, reset_fifo,
+ write_to_fifo, write_data, fifo_full, fifo_fill,
+ read_from_fifo, M_AXIS_TDATA, fifo_empty
+ // }}}
+ );
+
+ assign M_AXIS_TLAST = 1'b1;
+ // }}}
+ end endgenerate
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The incoming AXI (full) protocol section
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ //
+
+ // Some counters to keep track of our state
+ // {{{
+
+
+ // Count the number of word writes left to be requested, starting
+ // with the overall command length and then reduced by M_AWLEN on
+ // each address write
+ // {{{
+ always @(*)
+ begin
+ ar_next_remaining = ar_requests_remaining;
+ ar_next_remaining = ar_requests_remaining
+ + { {(LGLENWA-8){phantom_start}},
+ (phantom_start) ? ~M_AXI_ARLEN : 8'h00};
+ end
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ r_pre_start <= 1;
+ else
+ r_pre_start <= 0;
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ ar_needs_alignment <= 0;
+
+ if (|new_wideaddr[ADDRLSB +: LGMAXBURST])
+ begin
+ if (|new_widelen[LGLEN-1:(LGMAXBURST+ADDRLSB)])
+ ar_needs_alignment <= 1;
+ if (~new_wideaddr[ADDRLSB +: LGMAXBURST]
+ < new_widelen[ADDRLSB +: LGMAXBURST])
+ ar_needs_alignment <= 1;
+ end
+ end
+
+ initial ar_none_remaining = 1;
+ initial ar_requests_remaining = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ ar_requests_remaining <= cmd_length_aligned_w;
+ ar_none_remaining <= zero_length;
+ ar_multiple_bursts_remaining
+ <= |cmd_length_aligned_w[LGLENWA-1:LGMAXBURST+1];
+ end else if (cmd_abort || axi_abort_pending)
+ begin
+ ar_requests_remaining <= 0;
+ ar_none_remaining <= 1;
+ ar_multiple_bursts_remaining <= 0;
+
+ end else if (phantom_start)
+ begin
+ // Verilator lint_off WIDTH
+ ar_requests_remaining
+ <= ar_next_remaining;
+ ar_none_remaining <= (ar_next_remaining == 0);
+ ar_multiple_bursts_remaining
+ <= |ar_next_remaining[LGLENWA-1:LGMAXBURST+1];
+ // Verilator lint_on WIDTH
+ end
+ // }}}
+
+ // Calculate the maximum possible burst length, ignoring 4kB boundaries
+ // {{{
+ always @(*)
+ addralign = 1+(~cmd_addr[ADDRLSB +: LGMAXBURST]);
+
+ always @(*)
+ begin
+ initial_burstlen = (1<<LGMAXBURST);
+ if (!r_increment)
+ begin
+ initial_burstlen = MAX_FIXED_BURST;
+ if (!ar_multiple_fixed_bursts
+ && !cmd_length_aligned_w[LGMAX_FIXED_BURST])
+ begin
+ initial_burstlen = 0;
+ initial_burstlen[LGMAX_FIXED_BURST-1:0]
+ = cmd_length_aligned_w[
+ LGMAX_FIXED_BURST-1:0];
+ end
+ end else if (ar_needs_alignment)
+ initial_burstlen = { 1'b0, addralign };
+ else if (!ar_multiple_full_bursts
+ && !cmd_length_aligned_w[LGMAXBURST])
+ initial_burstlen = { 1'b0, cmd_length_aligned_w[
+ LGMAXBURST-1:0] };
+ end
+
+ initial r_max_burst = 0;
+ always @(posedge i_clk)
+ if (!r_busy || r_pre_start)
+ begin
+ // Force us to align ourself early
+ // That way we don't need to check for
+ // alignment (again) later
+ r_max_burst <= initial_burstlen;
+ end else if (phantom_start)
+ begin
+ // Verilator lint_off WIDTH
+ if (r_increment || LGMAXBURST <= LGMAX_FIXED_BURST)
+ begin : LIMIT_BY_LGMAXBURST
+ r_max_burst <= (1<<LGMAXBURST);
+
+ if (!ar_multiple_bursts_remaining
+ && ar_next_remaining[LGMAXBURST:0] < (1<<LGMAXBURST))
+ r_max_burst <= { 1'b0, ar_next_remaining[8:0] };
+ end else begin : LIMIT_BY_SIXTEEN
+ r_max_burst <= MAX_FIXED_BURST;
+
+ if (!ar_multiple_bursts_remaining
+ && ar_next_remaining[LGMAXBURST:0] < MAX_FIXED_BURST)
+ r_max_burst <= { 1'b0, ar_next_remaining[LGMAXBURST:0] };
+ end
+ // Verilator lint_on WIDTH
+ end
+ // }}}
+
+ // Count the number of bursts outstanding--these are the number of
+ // ARVALIDs that have been accepted, but for which the RVALID && RLAST
+ // has not (yet) been returned.
+ // {{{
+ initial ar_none_outstanding = 1;
+ initial ar_bursts_outstanding = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ ar_bursts_outstanding <= 0;
+ ar_none_outstanding <= 1;
+ end else case ({ phantom_start,
+ M_AXI_RVALID && M_AXI_RREADY && M_AXI_RLAST })
+ 2'b01: begin
+ ar_bursts_outstanding <= ar_bursts_outstanding - 1;
+ ar_none_outstanding <= (ar_bursts_outstanding == 1);
+ end
+ 2'b10: begin
+ ar_bursts_outstanding <= ar_bursts_outstanding + 1;
+ ar_none_outstanding <= 0;
+ end
+ default: begin end
+ endcase
+ // }}}
+
+ // Are we there yet?
+ // {{{
+ initial rd_reads_remaining = 0;
+ initial rd_none_remaining = 1;
+ initial rd_last_remaining = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ rd_reads_remaining <= cmd_length_aligned_w;
+ rd_last_remaining <= (cmd_length_aligned_w == 1);
+ rd_none_remaining <= (cmd_length_aligned_w == 0);
+ end else if (M_AXI_RVALID && M_AXI_RREADY)
+ begin
+ rd_reads_remaining <= rd_reads_remaining - 1;
+ rd_last_remaining <= (rd_reads_remaining == 2);
+ rd_none_remaining <= (rd_reads_remaining == 1);
+ end
+
+ always @(*)
+ if (!r_busy)
+ w_complete = 0;
+ else if (axi_abort_pending && ar_none_outstanding && !M_AXI_ARVALID)
+ w_complete = 1;
+ else if (r_continuous)
+ w_complete = (rd_none_remaining)||((rd_last_remaining) && M_AXI_RVALID && M_AXI_RREADY);
+ else // if !r_continuous
+ w_complete = (rd_none_remaining && fifo_empty);
+
+ // }}}
+
+ // Are we stopping early? Aborting something ongoing?
+ // {{{
+ initial axi_abort_pending = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ axi_abort_pending <= 0;
+ else begin
+ if (M_AXI_RVALID && M_AXI_RREADY && M_AXI_RRESP[1])
+ axi_abort_pending <= 1;
+ if (cmd_abort)
+ axi_abort_pending <= 1;
+ end
+ // }}}
+
+ // Count the number of uncommited spaces in the FIFO
+ // {{{
+ generate if (OPT_UNALIGNED)
+ begin : GEN_UNALIGNED_BREQ_COUNT
+ reg r_partial_burst_requested;
+
+ initial r_partial_burst_requested = 1'b1;
+ always @(posedge i_clk)
+ if (!r_busy)
+ r_partial_burst_requested <= !unaligned_cmd_addr;
+ else if (phantom_start)
+ r_partial_burst_requested <= 1'b1;
+
+ assign partial_burst_requested = r_partial_burst_requested;
+ end else begin : NO_UNALIGNED_BREQ_COUNT
+
+ assign partial_burst_requested = 1'b1;
+ end endgenerate
+
+ initial rd_uncommitted = (1<<LGFIFO);
+ always @(posedge i_clk)
+ if (reset_fifo)
+ begin
+ rd_uncommitted <= (1<<LGFIFO);
+ end else case ({ phantom_start,
+ M_AXIS_TVALID && M_AXIS_TREADY })
+ 2'b00: begin end
+ 2'b01: begin
+ rd_uncommitted <= rd_uncommitted + 1;
+ end
+ 2'b10: begin
+ // Verilator lint_off WIDTH
+ rd_uncommitted <= rd_uncommitted - (M_AXI_ARLEN + 1)
+ + (partial_burst_requested ? 0 :1);
+ end
+ 2'b11: begin
+ rd_uncommitted <= rd_uncommitted - (M_AXI_ARLEN)
+ + (partial_burst_requested ? 0 :1);
+ // Verilator lint_on WIDTH
+ end
+ endcase
+ // }}}
+
+ // So that we can monitor where we are at, and perhaps restart it
+ // later, keep track of the current address used by the R-channel
+ // {{{
+
+ initial axi_raddr = 0;
+ always @(posedge i_clk)
+ begin
+ if (!r_busy)
+ axi_raddr <= cmd_addr;
+ else if (axi_abort_pending || !r_increment)
+ // Stop incrementing tthe address following an abort
+ axi_raddr <= axi_raddr;
+ else begin
+ if (M_AXI_RVALID && M_AXI_RREADY && !M_AXI_RRESP[1]
+ && (!unaligned_cmd_addr || realign_last_valid))
+ axi_raddr <= axi_raddr + (1<<ADDRLSB);
+ end
+
+ if (!OPT_UNALIGNED)
+ axi_raddr[ADDRLSB-1:0] <= 0;
+ end
+
+ // }}}
+
+ //
+ // }}}
+
+ // start_burst, phantom_start
+ // {{{
+ always @(*)
+ begin
+ start_burst = !ar_none_remaining;
+ if ((rd_uncommitted[LGFIFO:LGMAXBURST] == 0)
+ && ({ 1'b0, rd_uncommitted[LGMAXBURST-1:0] }
+ < r_max_burst))
+ start_burst = 0;
+ if (phantom_start || r_pre_start)
+ // Insist on a minimum of one clock between burst
+ // starts, so we can get our lengths right
+ start_burst = 0;
+ if (M_AXI_ARVALID && !M_AXI_ARREADY)
+ start_burst = 0;
+ if (!r_busy || cmd_abort || axi_abort_pending)
+ start_burst = 0;
+ end
+
+ initial phantom_start = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ phantom_start <= 0;
+ else
+ phantom_start <= start_burst;
+ // }}}
+
+
+ // Calculate ARLEN and ARADDR for the next ARVALID
+ // {{{
+ generate if (LGMAXBURST >= 8)
+ begin : GEN_BIG_AWLEN
+ // Verilator lint_off WIDTH
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ axi_arlen <= initial_burstlen - 1;
+ else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ axi_arlen <= r_max_burst - 1;
+
+ // Verilator lint_on WIDTH
+ end else begin : GEN_SHORT_AWLEN
+
+ always @(posedge i_clk)
+ begin
+ axi_arlen[7:LGMAXBURST] <= 0;
+ if (!r_busy)
+ axi_arlen[LGMAXBURST:0] <= initial_burstlen - 1;
+ else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ axi_arlen[LGMAXBURST:0] <= r_max_burst - 1;
+ end
+
+ end endgenerate
+ // }}}
+
+ // Calculate ARADDR for the next ARVALID
+ // {{{
+ initial axi_araddr = 0;
+ always @(posedge i_clk)
+ begin
+ if (M_AXI_ARVALID && M_AXI_ARREADY)
+ begin
+ if (r_increment)
+ // Verilator lint_off WIDTH
+ axi_araddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ <= axi_araddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ + (M_AXI_ARLEN + 1);
+ // Verilator lint_on WIDTH
+
+ axi_araddr[ADDRLSB-1:0] <= 0;
+ end
+
+ if (!r_busy)
+ begin
+ axi_araddr <= cmd_addr;
+ end
+
+ if (!OPT_UNALIGNED)
+ axi_araddr[ADDRLSB-1:0] <= 0;
+ end
+ // }}}
+
+ // ARVALID
+ // {{{
+ initial axi_arvalid = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ axi_arvalid <= 0;
+ else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ axi_arvalid <= start_burst;
+ // }}}
+
+ // Set the constant M_AXI_* signals
+ // {{{
+ assign M_AXI_ARVALID= axi_arvalid;
+ assign M_AXI_ARID = AXI_ID;
+ assign M_AXI_ARADDR = axi_araddr;
+ assign M_AXI_ARLEN = axi_arlen;
+ // Verilator lint_off WIDTH
+ assign M_AXI_ARSIZE = $clog2(C_AXI_DATA_WIDTH)-3;
+ // Verilator lint_on WIDTH
+ assign M_AXI_ARBURST= { 1'b0, r_increment };
+ assign M_AXI_ARLOCK = 0;
+ assign M_AXI_ARCACHE= 4'b0011;
+ assign M_AXI_ARPROT = 0;
+ assign M_AXI_ARQOS = 0;
+
+ assign M_AXI_RREADY = 1;
+ // }}}
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // (Optional) clock gating
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ generate if (OPT_CLKGATE)
+ begin : CLK_GATING
+ // {{{
+ reg gatep, r_clk_active;
+ reg gaten /* verilator clock_enable */;
+
+ // clk_active
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_clk_active <= 1'b1;
+ else begin
+ r_clk_active <= 1'b0;
+
+ if (r_busy)
+ r_clk_active <= 1'b1;
+ if (awskd_valid || wskd_valid || arskd_valid)
+ r_clk_active <= 1'b1;
+ if (S_AXIL_BVALID || S_AXIL_RVALID)
+ r_clk_active <= 1'b1;
+
+ if (M_AXIS_TVALID)
+ r_clk_active <= 1'b1;
+ end
+
+ assign clk_active = r_clk_active;
+ // }}}
+ // Gate the clock here locally
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ gatep <= 1'b1;
+ else
+ gatep <= clk_active;
+
+ always @(negedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ gaten <= 1'b1;
+ else
+ gaten <= gatep;
+
+ assign gated_clk = S_AXI_ACLK && gaten;
+
+ assign clk_active = r_clk_active;
+ // }}}
+ // }}}
+ end else begin : NO_CLK_GATING
+ // {{{
+ // Always active
+ assign clk_active = 1'b1;
+ assign gated_clk = S_AXI_ACLK;
+ // }}}
+ end endgenerate
+ // }}}
+
+ // Keep Verilator happy
+ // {{{
+ // Verilator coverage_off
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_RID,
+ M_AXI_RRESP[0], fifo_full, wskd_strb[2:0], fifo_fill,
+ ar_none_outstanding, S_AXIL_AWADDR[AXILLSB-1:0],
+ S_AXIL_ARADDR[AXILLSB-1:0],
+ new_wideaddr[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+ new_widelen
+ };
+ // Verilator coverage_on
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ //
+ // The formal properties for this unit are maintained elsewhere.
+ // This core does, however, pass a full prove (w/ induction) for all
+ // bus properties.
+ //
+ // ...
+ //
+
+
+ initial f_past_valid = 0;
+ always @(posedge i_clk)
+ f_past_valid <= 1;
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Properties of the AXI-stream data interface
+ // {{{
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // (These are captured by the FIFO within)
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The AXI-lite 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),
+ //
+ // ...
+ // }}}
+ );
+
+ //
+ // ...
+ //
+
+ always @(posedge i_clk)
+ if (f_past_valid && $past(S_AXI_ARESETN))
+ begin
+ if ($past(r_busy)||$past(w_cmd_start))
+ begin
+ assert($stable(cmd_length_b));
+ assert($stable(cmd_length_w));
+ assert($stable(cmd_length_aligned_w));
+ end
+ if ($past(r_busy))
+ begin
+ assert($stable(r_increment));
+ assert($stable(r_continuous));
+ end
+ if ($past(r_busy) && $past(r_busy,2))
+ assert($stable(fv_start_addr));
+ end
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The AXI master memory interface
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ //
+ // ...
+ //
+
+ faxi_master #(
+ // {{{
+ .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_EXCLUSIVE(1'b0),
+ .OPT_NARROW_BURST(1'b0),
+ //
+ // ...
+ // }}}
+ ) faxi(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(1'b0),
+ .i_axi_awready(1'b0),
+ .i_axi_awid( AXI_ID),
+ .i_axi_awaddr( 0),
+ .i_axi_awlen( 0),
+ .i_axi_awsize( 0),
+ .i_axi_awburst(0),
+ .i_axi_awlock( 0),
+ .i_axi_awcache(0),
+ .i_axi_awprot( 0),
+ .i_axi_awqos( 0),
+ //
+ .i_axi_wvalid(0),
+ .i_axi_wready(0),
+ .i_axi_wdata( 0),
+ .i_axi_wstrb( 0),
+ .i_axi_wlast( 0),
+ //
+ .i_axi_bvalid(1'b0),
+ .i_axi_bready(1'b0),
+ .i_axi_bid( AXI_ID),
+ .i_axi_bresp( 2'b00),
+ //
+ .i_axi_arvalid(M_AXI_ARVALID),
+ .i_axi_arready(M_AXI_ARREADY),
+ .i_axi_arid( M_AXI_ARID),
+ .i_axi_araddr( M_AXI_ARADDR),
+ .i_axi_arlen( M_AXI_ARLEN),
+ .i_axi_arsize( M_AXI_ARSIZE),
+ .i_axi_arburst(M_AXI_ARBURST),
+ .i_axi_arlock( M_AXI_ARLOCK),
+ .i_axi_arcache(M_AXI_ARCACHE),
+ .i_axi_arprot( M_AXI_ARPROT),
+ .i_axi_arqos( M_AXI_ARQOS),
+ //
+ .i_axi_rvalid(M_AXI_RVALID),
+ .i_axi_rready(M_AXI_RREADY),
+ .i_axi_rdata( M_AXI_RDATA),
+ .i_axi_rlast( M_AXI_RLAST),
+ .i_axi_rresp( M_AXI_RRESP),
+ //
+ // ...
+ //
+ // }}}
+ );
+
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ //
+ // ...
+ //
+ end else begin
+ //
+ // ...
+ //
+
+ assert(rd_uncommitted
+ + ((OPT_UNALIGNED && write_to_fifo) ? 1:0)
+ + fifo_fill == (1<<LGFIFO));
+ if (!r_continuous)
+ assert(fifo_fill == 0 || reset_fifo);
+ end
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (!OPT_UNALIGNED)
+ begin
+ assert(M_AXI_ARADDR[ADDRLSB-1:0] == 0);
+ end else
+ assert((M_AXI_ARADDR[ADDRLSB-1:0] == 0)
+ ||(M_AXI_ARADDR == fv_start_addr));
+ end
+
+ always @(*)
+ if (!OPT_UNALIGNED || (r_busy && !r_increment))
+ begin
+ assert(cmd_addr[ADDRLSB-1:0] == 0);
+ assert(fv_start_addr[ADDRLSB-1:0] == 0);
+ assert(axi_araddr[ADDRLSB-1:0] == 0);
+ assert(axi_raddr[ADDRLSB-1:0] == 0);
+ end
+
+ //
+ // f_last_addr is the (aligned) address one following the last valid
+ // address read. Once all reading is done, all (aligned) address
+ // pointers should point there.
+ always @(*)
+ begin
+ f_last_addr = { fv_start_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB],
+ {(ADDRLSB){1'b0}} };
+
+ if (r_increment)
+ f_last_addr = f_last_addr + cmd_length_b;
+ if (unaligned_cmd_addr) // Only true if r_increment as well
+ f_last_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ = f_last_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]+1;
+
+ f_last_addr[ADDRLSB-1:0] = 0;
+
+ f_next_start = fv_start_addr;
+ if (r_increment)
+ f_next_start = f_next_start + cmd_length_b;
+ if (!OPT_UNALIGNED)
+ assert(f_next_start == f_last_addr);
+ end
+
+
+ //
+ // ...
+ //
+
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Other formal properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ //
+ // Define some helper metrics
+ //
+ initial fv_start_addr = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ fv_start_addr <= cmd_addr;
+
+ always @(*)
+ begin
+ // Metrics defining M_AXI_ARADDR
+ f_araddr_is_aligned = (M_AXI_ARADDR[ADDRLSB+LGMAXBURST-1:0]==0);
+ f_araddr_is_initial = (M_AXI_ARADDR == fv_start_addr);
+ f_araddr_is_final = (M_AXI_ARADDR == f_last_addr);
+
+ //
+ // Metrics to check ARADDR, assuming it had been accepted
+ //
+
+ //
+ // ...
+ //
+ end
+
+ //
+ // fv_ar_requests_remaining ... shadows ar_requests_remaining
+ //
+ // Since ar_requests_remaining drops to zero suddenly on any
+ // axi_abort_pending, we need another counter that we can use
+ // which doesn't have this feature, but which can also be used
+ // to check assertions and intermediate logic against until the
+ // abort takes effect.
+ initial fv_ar_requests_remaining = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ fv_ar_requests_remaining <= cmd_length_aligned_w;
+ end else if (phantom_start)
+ begin
+ // Verilator lint_off WIDTH
+ fv_ar_requests_remaining
+ <= fv_ar_requests_remaining - (M_AXI_ARLEN + 1);
+ // Verilator lint_on WIDTH
+ end
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (!axi_abort_pending)
+ begin
+ assert(fv_ar_requests_remaining == ar_requests_remaining);
+ end else
+ assert((ar_requests_remaining == 0)
+ ||(fv_ar_requests_remaining
+ == ar_requests_remaining));
+ end
+
+ always @(*)
+ if(r_busy)
+ begin
+ assert(fv_ar_requests_remaining <= cmd_length_aligned_w);
+ //
+ // ...
+ //
+ end
+
+ //
+ // fv_axi_raddr ... shadows axi_raddr
+ //
+ // The low order bits will match the low order bits of the initial
+ // cmd_addr
+ //
+ initial fv_axi_raddr = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ fv_axi_raddr <= cmd_addr;
+ else if (!r_increment)
+ fv_axi_raddr <= fv_start_addr;
+ else begin
+ if (M_AXI_RVALID && M_AXI_RREADY
+ && (!unaligned_cmd_addr || realign_last_valid))
+ fv_axi_raddr <= fv_axi_raddr + (1<<ADDRLSB);
+ if (!OPT_UNALIGNED)
+ fv_axi_raddr[ADDRLSB-1:0] <= 0;
+ end
+
+ // Constrain start <= axi_raddr <= fv_axi_raddr <= f_last_addr
+ // in spite of any address wrapping
+ always @(*)
+ if (r_busy)
+ begin
+ assert(axi_raddr[ADDRLSB-1:0] == cmd_addr[ADDRLSB-1:0]);
+ assert(axi_abort_pending || fv_axi_raddr == axi_raddr);
+ if (!r_increment)
+ begin
+ assert(fv_axi_raddr == fv_start_addr);
+ assert(axi_raddr == fv_start_addr);
+ end if (!axi_abort_pending)
+ begin
+ if (fv_start_addr <= f_last_addr)
+ begin
+ // Natural order: start < f_raddr < last
+ assert(fv_axi_raddr <= f_last_addr);
+ assert(fv_axi_raddr >= fv_start_addr);
+ end else begin
+ // Reverse order
+ // Either: last < start <= f_raddr
+ // or: f_raddr < last < start
+ assert((fv_axi_raddr >= fv_start_addr)
+ ||(fv_axi_raddr <= f_last_addr));
+ end
+
+ if (fv_start_addr <= fv_axi_raddr)
+ begin
+ // Natural order: start < rad < f_rad < last
+ // or even: last < start < rad < f_rad
+ assert(axi_raddr <= fv_axi_raddr);
+ assert(fv_start_addr <= axi_raddr);
+ end else if (fv_axi_raddr <= f_last_addr)
+ begin
+ // Reverse order: f_raddr < last < start
+ // so either: last < start < raddr
+ // or: raddr < f_raddr < last < start
+ //
+ assert((axi_raddr >= fv_start_addr)
+ || (axi_raddr <= fv_axi_raddr));
+ end
+ end
+ end
+
+ always @(*)
+ if (!r_busy)
+ begin
+ assert(!M_AXI_ARVALID);
+ assert(!M_AXI_RVALID);
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ assert(zero_length == (cmd_length_w == 0));
+
+ always @(*)
+ if (phantom_start)
+ assert(rd_uncommitted >= (M_AXI_ARLEN + 1));
+
+ always @(*)
+ if (zero_length)
+ assert(!r_busy);
+ always @(*)
+ if (r_busy)
+ assert(ar_none_remaining == (ar_requests_remaining == 0));
+ always @(*)
+ assert(ar_none_outstanding == (ar_bursts_outstanding == 0));
+ always @(*)
+ assert(rd_none_remaining == (rd_reads_remaining == 0));
+ always @(*)
+ assert(rd_last_remaining == (rd_reads_remaining == 1));
+
+ always @(*)
+ if (r_complete)
+ assert(!r_busy);
+
+ //
+ // ...
+ //
+
+ //
+ // fifo_availability is a measure of (1<<LGFIFO) minus the current
+ // fifo fill. This does not include what's in the pre-FIFO
+ // logic when OPT_UNALIGNED is true.
+ always @(*)
+ f_fifo_availability = rd_uncommitted;
+
+ always @(*)
+ assert(f_fifo_committed <= (1<<LGFIFO));
+
+ always @(*)
+ assert(f_fifo_availability <= (1<<LGFIFO));
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (!reset_fifo)
+ assert(f_fifo_committed + f_fifo_availability + fifo_fill
+ == (1<<LGFIFO));
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_busy)
+ assert(r_max_burst <= (1<<LGMAXBURST));
+
+ always @(*)
+ if (r_busy && !r_pre_start)
+ assert((r_max_burst > 0) || (ar_requests_remaining == 0));
+
+
+ always @(*)
+ if (phantom_start)
+ assert(M_AXI_ARVALID);
+
+ always @(posedge i_clk)
+ if (phantom_start)
+ begin
+ assert(r_max_burst > 0);
+ assert(M_AXI_ARLEN == $past(r_max_burst)-1);
+ end
+
+
+
+ //
+ // Address checking
+ //
+
+ // Check cmd_addr
+ always @(*)
+ if (r_busy)
+ begin
+ if (r_increment && r_continuous)
+ begin
+ assert(cmd_addr == axi_raddr);
+ end else
+ assert(cmd_addr == fv_start_addr);
+ end
+
+ // Check M_AXI_ARADDR
+ //
+ // ...
+ //
+
+ //
+ // Check M_AXI_ARLEN
+ //
+ // ...
+ //
+
+ //
+ // Constrain the r_maxburst
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ assert(r_max_burst <= (1<<LGMAXBURST));
+ //
+ // ...
+ //
+ end
+
+ //
+ // Constrain the length
+ //
+ // ...
+ //
+
+ // Constrain rd_reads_remaining
+ //
+ // ...
+ //
+ always @(*)
+ if (r_busy)
+ begin
+ assert(rd_reads_remaining <= cmd_length_w);
+ //
+ // ...
+ //
+ assert(ar_bursts_outstanding <= rd_reads_remaining);
+ //
+ // ...
+ //
+ end
+
+ //
+ // Constrain the number of requests remaining
+ //
+ // ...
+ //
+
+ //
+ // Make sure our aw_bursts_outstanding counter never overflows
+ // (Given that the counter is as long as the length register, it cannot)
+ //
+ always @(*)
+ begin
+ if (&ar_bursts_outstanding[LGLENWA-1:1])
+ assert(!M_AXI_ARVALID);
+ //
+ // ...
+ //
+ end
+
+ // }}}
+
+ //
+ // Some (fairly) random/unsorted properties
+ // {{{
+
+ always @(*)
+ begin
+ assert(ar_multiple_full_bursts
+ == |cmd_length_w[LGLENW-1:LGMAXBURST]);
+ assert(ar_multiple_fixed_bursts
+ == |cmd_length_w[LGLENW-1:LGMAX_FIXED_BURST]);
+ end
+ //
+ // Match axi_raddr to the faxi_ values
+ //
+ // ...
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Contract checks
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // {{{
+
+ // 1. All data values must get read and placed into the FIFO, with
+ // none skipped
+ // Captured in logic above(?)
+ //
+ // 2. No addresses skipped. Check the write address against the
+ // write address we are expecting
+ //
+ // ...
+ //
+
+ // 3. If we aren't incrementing addresses, then our current address
+ // should always be the axi address
+ //
+ // ...
+
+ //
+ // 4. Whenever we go from busy to idle, we should raise o_int for one
+ // (and only one) cycle
+ always @(posedge i_clk)
+ if (!f_past_valid || $past(!S_AXI_ARESETN))
+ begin
+ assert(!o_int);
+ end else
+ assert(o_int == $fell(r_busy));
+
+ //
+ // ...
+ //
+
+
+ // 5. Pick an incoming data value. Choose whether or not to restrict
+ // incoming data not to be that value. If the incoming data is so
+ // restricted then assert that the stream output will never contain that
+ // value.
+ (* anyconst *) reg f_restrict_data;
+ (* anyconst *) reg [C_AXI_DATA_WIDTH-1:0] f_restricted;
+
+ always @(*)
+ if (f_restrict_data && M_AXI_RVALID
+ && (!OPT_UNALIGNED || !unaligned_cmd_addr))
+ assume(M_AXI_RDATA != f_restricted);
+
+ always @(*)
+ if (f_restrict_data && M_AXIS_TVALID
+ && (!OPT_UNALIGNED || !unaligned_cmd_addr))
+ assert(M_AXIS_TDATA != f_restricted);
+
+ //
+ // ...
+ //
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover checks
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // {{{
+ reg cvr_aborted, cvr_buserr;
+ reg [2:0] cvr_continued;
+
+ initial { cvr_aborted, cvr_buserr } = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ { cvr_aborted, cvr_buserr } <= 0;
+ else if (r_busy && !axi_abort_pending)
+ begin
+ if (cmd_abort && ar_requests_remaining > 0)
+ cvr_aborted <= 1;
+ if (M_AXI_RVALID && M_AXI_RRESP[1] && M_AXI_RLAST)
+ cvr_buserr <= 1;
+ end
+
+ initial cvr_continued = 0;
+ always @(posedge i_clk)
+ if (i_reset || r_err || cmd_abort)
+ cvr_continued <= 0;
+ else begin
+ // Cover a continued transaction across two separate bursts
+ if (r_busy && r_continuous)
+ cvr_continued[0] <= 1;
+ if (!r_busy && cvr_continued[0])
+ cvr_continued[1] <= 1;
+ if (r_busy && cvr_continued[1])
+ cvr_continued[2] <= 1;
+ end
+
+ always @(posedge i_clk)
+ if (f_past_valid && !$past(i_reset) && !i_reset && $fell(r_busy))
+ begin
+ cover( r_err && cvr_aborted);
+ cover( r_err && cvr_buserr);
+ cover(!r_err);
+ if (!r_err && !axi_abort_pending && !cvr_aborted && !cvr_buserr)
+ begin
+ cover(cmd_length_w > 5);
+ cover(cmd_length_w > 8);
+ //
+ // ...
+ //
+ cover(&cvr_continued);
+ cover(&cvr_continued && (cmd_length_w > 2));
+ cover(&cvr_continued && (cmd_length_w > 5));
+ end
+ end
+
+ always @(*)
+ if (!i_reset)
+ cover(!r_err && fifo_fill > 8 && !r_busy);
+
+ always @(*)
+ cover(r_busy);
+
+ always @(*)
+ cover(start_burst);
+
+ always @(*)
+ cover(M_AXI_ARVALID && M_AXI_ARREADY);
+
+ always @(*)
+ cover(M_AXI_RVALID);
+
+ always @(*)
+ cover(M_AXI_RVALID & M_AXI_RLAST);
+ always @(*)
+ if (r_busy)
+ begin
+ cover(!ar_none_remaining);
+ if(!ar_none_remaining)
+ begin
+ cover(1);
+ cover(rd_uncommitted>= {{(LGFIFO-LGMAXBURST){1'b0}}, r_max_burst});
+ if(rd_uncommitted>= {{(LGFIFO-LGMAXBURST){1'b0}}, r_max_burst})
+ begin
+ cover(!phantom_start);
+ cover(phantom_start);
+ end
+ end
+ end
+
+ //
+ // Unaligned cover properties
+ generate if (OPT_TLAST)
+ begin
+ reg [3:0] cvr_lastcount;
+ always @(posedge i_clk)
+ if (i_reset || (r_busy && cmd_length_w <= 2))
+ cvr_lastcount <= 0;
+ else if (M_AXIS_TVALID && M_AXIS_TREADY && M_AXIS_TLAST
+ && !cvr_lastcount[3])
+ cvr_lastcount <= cvr_lastcount + 1;
+
+ always @(*)
+ cover(M_AXIS_TVALID && M_AXIS_TREADY && M_AXIS_TLAST);
+
+ always @(posedge i_clk)
+ cover(o_int && cvr_lastcount > 2);
+
+ end endgenerate
+
+ generate if (OPT_UNALIGNED)
+ begin
+ //
+ // ...
+ //
+ always @(posedge i_clk)
+ if (f_past_valid && !$past(i_reset) && !i_reset &&$fell(r_busy))
+ begin
+ cover(r_err);
+ cover(!r_err);
+ cover(axi_abort_pending);
+ cover(!axi_abort_pending);
+ cover(cvr_aborted);
+ cover(!cvr_aborted);
+ cover(cvr_buserr);
+ cover(!cvr_buserr);
+ cover(!cvr_buserr && !axi_abort_pending);
+ cover(!cvr_buserr && !axi_abort_pending
+ && (cmd_length_w > 2));
+ cover(!r_err && !cvr_aborted && !cvr_buserr
+ && !axi_abort_pending
+ && (cmd_length_w > 2));
+ end
+ end endgenerate
+
+
+ // }}}
+`endif
+// }}}
+endmodule