summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axidma.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axidma.v')
-rw-r--r--rtl/wb2axip/axidma.v2977
1 files changed, 2977 insertions, 0 deletions
diff --git a/rtl/wb2axip/axidma.v b/rtl/wb2axip/axidma.v
new file mode 100644
index 0000000..46b1e69
--- /dev/null
+++ b/rtl/wb2axip/axidma.v
@@ -0,0 +1,2977 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axidma.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: To move memory from one location to another, at high speed.
+// This is not a memory to stream, nor a stream to memory core,
+// but rather a memory to memory core.
+//
+//
+// 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 Clear
+// 1b Start
+// 1. Unused
+// 2-3. Source address, low and then high 64-bit words
+// (Last value read address)
+// 4-5. Destination address, low and then high 64-bit words
+// (Next value to write address)
+// 6-7. Length, low and then high words
+// (Total number minus successful writes)
+//
+// Performance goals:
+// 100% throughput
+// Stay off the bus until you can drive it hard
+// Other goals:
+// Be both AXI3 and AXI4 capable
+//
+// 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 axidma #(
+ // {{{
+ parameter C_AXI_ID_WIDTH = 1,
+ parameter C_AXI_ADDR_WIDTH = 32,
+ parameter C_AXI_DATA_WIDTH = 32,
+ //
+ // These two "parameters" really aren't things that can be
+ // changed externally. They control the size of the AXI4-lite
+ // port. Internally, it's defined to have 8, 32-bit registers.
+ // The registers are configured wide enough to support 64-bit
+ // AXI addressing. Similarly, the AXI-lite data width is fixed
+ // at 32-bits.
+ localparam C_AXIL_ADDR_WIDTH = 5,
+ 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,
+ //
+ // OPT_LOWPOWER:
+ parameter [0:0] OPT_LOWPOWER = 1'b0,
+ //
+ // OPT_CLKGATE:
+ parameter [0:0] OPT_CLKGATE = OPT_LOWPOWER,
+ //
+ // 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] AXI_READ_ID = 0,
+ parameter [C_AXI_ID_WIDTH-1:0] AXI_WRITE_ID = 0,
+ //
+ // 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,
+ //
+ localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3,
+ localparam AXILLSB= $clog2(C_AXIL_DATA_WIDTH)-3,
+ localparam LGLENW= LGLEN-ADDRLSB
+ // }}}
+ ) (
+ // {{{
+ input wire S_AXI_ACLK,
+ input wire S_AXI_ARESETN,
+ // AXI low-power interface
+ // {{{
+ // This has been removed, due to a lack of definition from the
+ // AXI standard for these wires.
+ // }}}
+ //
+ // 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 reg M_AXI_AWVALID,
+ input wire M_AXI_AWREADY,
+ output reg [C_AXI_ID_WIDTH-1:0] M_AXI_AWID,
+ output reg [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR,
+`ifdef AXI3
+ output reg [3:0] M_AXI_AWLEN,
+`else
+ output reg [7:0] M_AXI_AWLEN,
+`endif
+ output reg [2:0] M_AXI_AWSIZE,
+ output reg [1:0] M_AXI_AWBURST,
+ output reg M_AXI_AWLOCK,
+ output reg [3:0] M_AXI_AWCACHE,
+ output reg [2:0] M_AXI_AWPROT,
+ output reg [3:0] M_AXI_AWQOS,
+ //
+ //
+ output reg M_AXI_WVALID,
+ input wire M_AXI_WREADY,
+`ifdef AXI3
+ output reg [C_AXI_ID_WIDTH-1:0] M_AXI_WID,
+`endif
+ output reg [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA,
+ output reg [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
+ output reg 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 reg M_AXI_ARVALID,
+ input wire M_AXI_ARREADY,
+ output wire [C_AXI_ID_WIDTH-1:0] M_AXI_ARID,
+ output reg [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR,
+`ifdef AXI3
+ output reg [3:0] M_AXI_ARLEN,
+`else
+ output reg [7:0] M_AXI_ARLEN,
+`endif
+ 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_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 declarations
+ // {{{
+ // 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 [2:0] CTRL_ADDR = 3'b000,
+ // UNUSED_ADDR = 3'b001,
+ SRCLO_ADDR = 3'b010,
+ SRCHI_ADDR = 3'b011,
+ DSTLO_ADDR = 3'b100,
+ DSTHI_ADDR = 3'b101,
+ LENLO_ADDR = 3'b110,
+ LENHI_ADDR = 3'b111;
+ 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;
+ localparam [1:0] AXI_INCR = 2'b01, AXI_OKAY = 2'b00;
+
+ wire gated_clk, clk_active;
+ wire i_clk = gated_clk;
+ wire i_reset = !S_AXI_ARESETN;
+
+ reg axil_write_ready, axil_read_ready;
+ reg [2*C_AXIL_DATA_WIDTH-1:0] wide_src, wide_dst, wide_len;
+ reg [2*C_AXIL_DATA_WIDTH-1:0] new_widesrc, new_widedst, new_widelen;
+
+ reg r_busy, r_err, r_abort, w_start, r_int, r_int_enable,
+ r_done, last_write_ack, zero_len;
+ reg [3:0] r_qos;
+ reg [2:0] r_prot;
+ reg [LGLEN-1:0] r_len; // Length of transfer in octets
+ reg [C_AXI_ADDR_WIDTH-1:0] r_src_addr, r_dst_addr;
+
+ reg fifo_reset;
+ wire [LGFIFO:0] fifo_fill;
+ reg [LGFIFO:0] fifo_space_available;
+ reg [LGFIFO:0] fifo_data_available,
+ next_fifo_data_available;
+ wire fifo_full, fifo_empty;
+ reg [8:0] write_count;
+ //
+ reg phantom_read, w_start_read,
+ no_read_bursts_outstanding;
+ reg [LGLEN:0] readlen_b;
+ reg [LGLENW:0] readlen_w, initial_readlen_w;
+ reg [C_AXI_ADDR_WIDTH:0] read_address;
+ reg [LGLENW:0] reads_remaining_w,
+ read_beats_remaining_w,
+ read_bursts_outstanding;
+ reg [C_AXI_ADDR_WIDTH-1:0] read_distance_to_boundary_b;
+ reg reads_remaining_nonzero;
+ //
+ reg phantom_write, w_write_start;
+ reg [C_AXI_ADDR_WIDTH:0] write_address;
+ reg [LGLENW:0] writes_remaining_w,
+ write_bursts_outstanding;
+ reg [LGLENW:0] write_burst_length;
+ reg write_requests_remaining;
+ reg [LGLEN:0] writelen_b;
+ reg [LGLENW:0] write_beats_remaining;
+
+ 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;
+ //
+ reg r_partial_in_valid;
+ reg r_write_fifo, r_read_fifo;
+ reg r_partial_outvalid;
+ reg [C_AXI_DATA_WIDTH/8-1:0] r_first_wstrb,
+ r_last_wstrb;
+ reg extra_realignment_write,
+ extra_realignment_read;
+ reg [2*ADDRLSB+2:0] write_realignment;
+ reg last_read_beat;
+ reg clear_read_pipeline;
+ reg last_write_burst;
+
+ //
+ // Push some write length calculations across clocks
+ reg [LGLENW:0] w_writes_remaining_w;
+ reg multiple_write_bursts_remaining,
+ first_write_burst;
+ reg [LGMAXBURST:0] initial_write_distance_to_boundary_w,
+ first_write_len_w;
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-Lite control interface
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-lite control write interface
+ // {{{
+ skidbuffer #(.OPT_OUTREG(0), .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), .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_WSTRB, S_AXIL_WDATA }),
+ .o_valid(wskd_valid), .i_ready(axil_write_ready),
+ .o_data({ wskd_strb, wskd_data }));
+
+ always @(*)
+ begin
+ axil_write_ready = !S_AXIL_BVALID || S_AXIL_BREADY;
+ if (!awskd_valid || !wskd_valid)
+ axil_write_ready = 0;
+ if (!clk_active)
+ axil_write_ready = 0;
+ end
+
+ initial S_AXIL_BVALID = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ S_AXIL_BVALID <= 1'b0;
+ else if (!S_AXIL_BVALID || S_AXIL_BREADY)
+ S_AXIL_BVALID <= axil_write_ready;
+
+ assign S_AXIL_BRESP = AXI_OKAY;
+
+ always @(*)
+ begin
+ w_start = !r_busy && axil_write_ready && wskd_strb[0]
+ && wskd_data[CTRL_START_BIT]
+ && (awskd_addr == CTRL_ADDR);
+ if (r_err && (!wskd_strb[0] || !wskd_data[CTRL_ERR_BIT]))
+ w_start = 0;
+ if (zero_len)
+ w_start = 0;
+ end
+
+ always @(posedge i_clk)
+ if (i_reset)
+ r_err <= 1'b0;
+ else if (!r_busy && axil_write_ready)
+ r_err <= (r_err) && (!wskd_strb[0] || !wskd_data[CTRL_ERR_BIT]);
+ else if (r_busy)
+ begin
+ if (M_AXI_BVALID && M_AXI_BRESP[1])
+ r_err <= 1'b1;
+ if (M_AXI_RVALID && M_AXI_RRESP[1])
+ r_err <= 1'b1;
+
+ if (!OPT_WRAPMEM && write_address[C_AXI_ADDR_WIDTH]
+ && write_requests_remaining)
+ r_err <= 1'b1;
+ if (!OPT_WRAPMEM && read_address[C_AXI_ADDR_WIDTH]
+ && reads_remaining_nonzero)
+ r_err <= 1'b1;
+ end
+
+ initial r_busy = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ r_busy <= 1'b0;
+ else if (!r_busy && axil_write_ready)
+ r_busy <= w_start;
+ else if (r_busy)
+ begin
+ if (M_AXI_BVALID && M_AXI_BREADY && last_write_ack)
+ r_busy <= 1'b0;
+ if (r_done)
+ r_busy <= 1'b0;
+ end
+
+ always @(posedge i_clk)
+ if (i_reset || !r_int_enable || !r_busy)
+ o_int <= 0;
+ else if (r_done)
+ o_int <= 1'b1;
+ else
+ o_int <= (last_write_ack && M_AXI_BVALID && M_AXI_BREADY);
+
+ always @(posedge i_clk)
+ if (i_reset)
+ 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 (r_done)
+ r_int <= 1'b1;
+ else
+ r_int <= (last_write_ack && M_AXI_BVALID && M_AXI_BREADY);
+
+ initial r_abort = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ 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);
+
+ wire [C_AXIL_DATA_WIDTH-1:0] newsrclo, newsrchi,
+ newdstlo, newdsthi, newlenlo, newlenhi;
+
+ always @(*)
+ begin
+ wide_src = 0;
+ wide_dst = 0;
+ wide_len = 0;
+
+ wide_src[C_AXI_ADDR_WIDTH-1:0] = r_src_addr;
+ wide_dst[C_AXI_ADDR_WIDTH-1:0] = r_dst_addr;
+ wide_len[LGLEN-1:0] = r_len;
+
+ if (!OPT_UNALIGNED)
+ begin
+ wide_src[ADDRLSB-1:0] = 0;
+ wide_dst[ADDRLSB-1:0] = 0;
+ wide_len[ADDRLSB-1:0] = 0;
+ end
+ end
+
+ assign newsrclo = apply_wstrb(
+ wide_src[C_AXIL_DATA_WIDTH-1:0],
+ wskd_data, wskd_strb);
+ assign newsrchi = apply_wstrb(
+ wide_src[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+ wskd_data, wskd_strb);
+ assign newdstlo = apply_wstrb(
+ wide_dst[C_AXIL_DATA_WIDTH-1:0],
+ wskd_data, wskd_strb);
+ assign newdsthi = apply_wstrb(
+ wide_dst[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+ wskd_data, wskd_strb);
+ assign newlenlo = apply_wstrb(
+ wide_len[C_AXIL_DATA_WIDTH-1:0],
+ wskd_data, wskd_strb);
+ assign newlenhi = apply_wstrb(
+ wide_len[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH],
+ wskd_data, wskd_strb);
+
+ always @(*)
+ begin
+ new_widesrc = wide_src;
+ new_widedst = wide_dst;
+ new_widelen = wide_len;
+
+ if (!awskd_addr[0])
+ begin
+ new_widesrc[C_AXIL_DATA_WIDTH-1:0] = newsrclo;
+ new_widedst[C_AXIL_DATA_WIDTH-1:0] = newdstlo;
+ new_widelen[C_AXIL_DATA_WIDTH-1:0] = newlenlo;
+ end else begin
+ new_widesrc[2*C_AXIL_DATA_WIDTH-1
+ :C_AXIL_DATA_WIDTH] = newsrchi;
+ new_widedst[2*C_AXIL_DATA_WIDTH-1
+ :C_AXIL_DATA_WIDTH] = newdsthi;
+ new_widelen[2*C_AXIL_DATA_WIDTH-1
+ :C_AXIL_DATA_WIDTH] = newlenhi;
+ end
+
+ new_widesrc[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+ new_widedst[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] = 0;
+ new_widelen[2*C_AXIL_DATA_WIDTH-1:LGLEN] = 0;
+
+ if (!OPT_UNALIGNED)
+ begin
+ new_widesrc[ADDRLSB-1:0] = 0;
+ new_widedst[ADDRLSB-1:0] = 0;
+ new_widelen[ADDRLSB-1:0] = 0;
+ end
+ end
+
+ initial r_len = 0;
+ initial zero_len = 1;
+ initial r_src_addr = 0;
+ initial r_dst_addr = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ // {{{
+ r_len <= 0;
+ zero_len <= 1;
+ r_prot <= 0;
+ r_qos <= 0;
+ r_src_addr <= 0;
+ r_dst_addr <= 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])
+ r_int_enable <= wskd_data[CTRL_INTEN_BIT];
+ end
+ SRCLO_ADDR: begin
+ r_src_addr <= new_widesrc[C_AXI_ADDR_WIDTH-1:0];
+ end
+ SRCHI_ADDR: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH) begin
+ r_src_addr <= new_widesrc[C_AXI_ADDR_WIDTH-1:0];
+ end
+ DSTLO_ADDR: begin
+ r_dst_addr <= new_widedst[C_AXI_ADDR_WIDTH-1:0];
+ end
+ DSTHI_ADDR: if (C_AXI_ADDR_WIDTH > C_AXIL_DATA_WIDTH) begin
+ r_dst_addr <= new_widedst[C_AXI_ADDR_WIDTH-1:0];
+ end
+ LENLO_ADDR: begin
+ r_len <= new_widelen[LGLEN-1:0];
+ zero_len <= (new_widelen == 0);
+ end
+ LENHI_ADDR: if (LGLEN > C_AXIL_DATA_WIDTH) begin
+ r_len <= new_widelen[LGLEN-1:0];
+ zero_len <= (new_widelen == 0);
+ end
+ default: begin end
+ endcase
+ // }}}
+ end else if (r_busy)
+ begin
+ // {{{
+ r_dst_addr <= write_address[C_AXI_ADDR_WIDTH-1:0];
+ if (writes_remaining_w[LGLENW])
+ r_len <= -1;
+ else
+ r_len <= { writes_remaining_w[LGLENW-1:0],
+ {(ADDRLSB){1'b0}} };
+ if (OPT_UNALIGNED)
+ r_len[ADDRLSB-1:0] <= 0;
+
+ zero_len <= (writes_remaining_w == 0);
+
+ if (M_AXI_RVALID && M_AXI_RREADY && !M_AXI_RRESP[1])
+ begin
+ r_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ <= r_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]+1;
+ r_src_addr[ADDRLSB-1:0] <= 0;
+ end
+ // }}}
+ 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
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI-lite control read interface
+ // {{{
+ skidbuffer #(.OPT_OUTREG(0), .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));
+
+ always @(*)
+ begin
+ axil_read_ready = !S_AXIL_RVALID || S_AXIL_RREADY;
+ if (!arskd_valid)
+ axil_read_ready = 1'b0;
+ if (!clk_active)
+ axil_read_ready = 1'b0;
+ end
+
+ initial S_AXIL_RVALID = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ S_AXIL_RVALID <= 1'b0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ S_AXIL_RVALID <= axil_read_ready;
+
+ always @(posedge i_clk)
+ if (i_reset)
+ 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
+ SRCLO_ADDR:
+ S_AXIL_RDATA <= wide_src[C_AXIL_DATA_WIDTH-1:0];
+ SRCHI_ADDR:
+ S_AXIL_RDATA <= wide_src[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ DSTLO_ADDR:
+ S_AXIL_RDATA <= wide_dst[C_AXIL_DATA_WIDTH-1:0];
+ DSTHI_ADDR:
+ S_AXIL_RDATA <= wide_dst[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ LENLO_ADDR:
+ S_AXIL_RDATA <= wide_len[C_AXIL_DATA_WIDTH-1:0];
+ LENHI_ADDR:
+ S_AXIL_RDATA <= wide_len[2*C_AXIL_DATA_WIDTH-1:C_AXIL_DATA_WIDTH];
+ default: begin end
+ endcase
+
+ if (!axil_read_ready)
+ S_AXIL_RDATA <= 0;
+ end
+
+ assign S_AXIL_RRESP = AXI_OKAY;
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI read processing
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ //
+ // Read data into our FIFO
+ //
+
+ // read_address
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ read_address <= { 1'b0, r_src_addr };
+ else if (phantom_read)
+ begin
+ // Verilator lint_off WIDTH
+ read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ <= read_address[C_AXI_ADDR_WIDTH:ADDRLSB] +(M_AXI_ARLEN+1);
+ // Verilator lint_on WIDTH
+ read_address[ADDRLSB-1:0] <= 0;
+ end
+ // }}}
+
+ // reads_remaining_w, reads_remaining_nonzero
+ // {{{
+ // Verilator lint_off WIDTH
+ always @(posedge i_clk)
+ if (!r_busy)
+ reads_remaining_w <= readlen_b[LGLEN:ADDRLSB];
+ else if (phantom_read)
+ reads_remaining_w <= reads_remaining_w - (M_AXI_ARLEN+1);
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ reads_remaining_nonzero <= 1;
+ else if (phantom_read)
+ reads_remaining_nonzero
+ <= (reads_remaining_w != (M_AXI_ARLEN+1));
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // read_beats_remaining_w
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ read_beats_remaining_w <= readlen_b[LGLEN:ADDRLSB];
+ else if (M_AXI_RVALID && M_AXI_RREADY)
+ read_beats_remaining_w <= read_beats_remaining_w - 1;
+ // }}}
+
+ // read_bursts_outstanding, no_read_bursts_outstanding
+ // {{{
+ initial read_bursts_outstanding = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ read_bursts_outstanding <= 0;
+ end else case({phantom_read,M_AXI_RVALID&& M_AXI_RREADY && M_AXI_RLAST})
+ 2'b01: read_bursts_outstanding <= read_bursts_outstanding - 1;
+ 2'b10: read_bursts_outstanding <= read_bursts_outstanding + 1;
+ default: begin end
+ endcase
+
+ initial no_read_bursts_outstanding = 1;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ no_read_bursts_outstanding <= 1;
+ end else case({phantom_read,M_AXI_RVALID&& M_AXI_RREADY && M_AXI_RLAST})
+ 2'b01: no_read_bursts_outstanding <= (read_bursts_outstanding == 1);
+ 2'b10: no_read_bursts_outstanding <= 0;
+ default: begin end
+ endcase
+ // }}}
+
+ // M_AXI_ARADDR
+ // {{{
+ always @(posedge i_clk)
+ if (!S_AXI_ARESETN && OPT_LOWPOWER)
+ M_AXI_ARADDR <= 0;
+ else if (!r_busy)
+ begin
+ if (!OPT_LOWPOWER || w_start)
+ M_AXI_ARADDR <= r_src_addr;
+ else
+ M_AXI_ARADDR <= 0;
+ end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ begin
+ M_AXI_ARADDR <= read_address[C_AXI_ADDR_WIDTH-1:0];
+ if (OPT_LOWPOWER && !w_start_read)
+ M_AXI_ARADDR <= 0;
+ end
+ // }}}
+
+ // readlen_b
+ // {{{
+ always @(*)
+ if (OPT_UNALIGNED)
+ readlen_b = r_len + { {(C_AXI_ADDR_WIDTH-ADDRLSB){1'b0}},
+ r_src_addr[ADDRLSB-1:0] }
+ + { {(C_AXI_ADDR_WIDTH-ADDRLSB){1'b0}},
+ {(ADDRLSB){1'b1}} };
+ else begin
+ readlen_b = { 1'b0, r_len };
+ readlen_b[ADDRLSB-1:0] = 0;
+ end
+ // }}}
+
+ // read_distance_to_boundary_b
+ // {{{
+ always @(*)
+ begin
+ read_distance_to_boundary_b = 0;
+ read_distance_to_boundary_b[ADDRLSB +: LGMAXBURST]
+ = -r_src_addr[ADDRLSB +: LGMAXBURST];
+ end
+ // }}}
+
+ // initial_readlen_w
+ // {{{
+ always @(*)
+ begin
+ initial_readlen_w = 0;
+ initial_readlen_w[LGMAXBURST] = 1;
+
+ if (r_src_addr[ADDRLSB +: LGMAXBURST] != 0)
+ initial_readlen_w[LGMAXBURST:0] = { 1'b0,
+ read_distance_to_boundary_b[ADDRLSB +: LGMAXBURST] };
+ if (initial_readlen_w > readlen_b[LGLEN:ADDRLSB])
+ initial_readlen_w[LGMAXBURST:0] = { 1'b0,
+ readlen_b[ADDRLSB +: LGMAXBURST] };
+ initial_readlen_w[LGLENW-1:LGMAXBURST+1] = 0;
+ end
+ // }}}
+
+ // readlen_w
+ // {{{
+ // Verilator lint_off WIDTH
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ readlen_w <= initial_readlen_w;
+ end else if (phantom_read)
+ begin
+ readlen_w <= reads_remaining_w - (M_AXI_ARLEN+1);
+ if (reads_remaining_w - (M_AXI_ARLEN+1) > MAXBURST)
+ readlen_w <= MAXBURST;
+ end
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // w_start_read
+ // {{{
+ always @(*)
+ begin
+ w_start_read = r_busy && reads_remaining_nonzero;
+ if (phantom_read)
+ w_start_read = 0;
+ if (!OPT_WRAPMEM && read_address[C_AXI_ADDR_WIDTH])
+ w_start_read = 0;
+ if (fifo_space_available < MAXBURST)
+ w_start_read = 0;
+ if (M_AXI_ARVALID && !M_AXI_ARREADY)
+ w_start_read = 0;
+ if (r_err || r_abort)
+ w_start_read = 0;
+ end
+ // }}}
+
+ // M_AXI_ARVALID, phantom_read
+ // {{{
+ initial M_AXI_ARVALID = 1'b0;
+ initial phantom_read = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ M_AXI_ARVALID <= 0;
+ phantom_read <= 0;
+ end else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ begin
+ M_AXI_ARVALID <= w_start_read;
+ phantom_read <= w_start_read;
+ end else
+ phantom_read <= 0;
+ // }}}
+
+ // M_AXI_ARLEN
+ // {{{
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ M_AXI_ARLEN <= 0;
+ else if (!M_AXI_ARVALID || M_AXI_ARREADY)
+ begin
+`ifdef AXI3
+ M_AXI_ARLEN <= readlen_w[3:0] - 4'h1;
+`else
+ M_AXI_ARLEN <= readlen_w[7:0] - 8'h1;
+`endif
+ if (OPT_LOWPOWER && !w_start_read)
+ M_AXI_ARLEN <= 0;
+ end
+ // }}}
+
+ assign M_AXI_ARID = AXI_READ_ID;
+ assign M_AXI_ARBURST = AXI_INCR;
+ assign M_AXI_ARSIZE = ADDRLSB[2:0];
+ assign M_AXI_ARLOCK = 1'b0;
+ assign M_AXI_ARCACHE = 4'b0011;
+ assign M_AXI_ARPROT = r_prot;
+ assign M_AXI_ARQOS = r_qos;
+ //
+ assign M_AXI_RREADY = !no_read_bursts_outstanding;
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The intermediate FIFO
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ always @(*)
+ fifo_reset = i_reset || !r_busy || r_done;
+
+ generate if (OPT_UNALIGNED)
+ begin : REALIGNMENT_FIFO
+ // {{{
+ reg [ADDRLSB-1:0] inbyte_shift, outbyte_shift,
+ remaining_read_realignment;
+ reg [ADDRLSB+3-1:0] inshift_down, outshift_down,
+ inshift_up, outshift_up;
+ reg [C_AXI_DATA_WIDTH-1:0] r_partial_inword,
+ r_outword, r_partial_outword,
+ r_realigned_incoming;
+ wire [C_AXI_DATA_WIDTH-1:0] fifo_data;
+ reg [ADDRLSB-1:0] r_last_write_addr;
+ reg r_oneword, r_firstword;
+
+
+ ///////////////////
+
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ inbyte_shift <= r_src_addr[ADDRLSB-1:0];
+ inshift_up <= 0;
+ inshift_up[3 +: ADDRLSB] <= -r_src_addr[ADDRLSB-1:0];
+ end
+
+ always @(*)
+ inshift_down = { inbyte_shift, 3'b000 };
+
+ always @(*)
+ remaining_read_realignment = -r_src_addr[ADDRLSB-1:0];
+
+ // extra_realignment_read will be true if we need to flush
+ // the read processor after the last word has been read in an
+ // extra write to the FIFO that isn't associated with any reads.
+ // In other words, if the number of writes to the FIFO is
+ // greater than the number of read beats
+ // - (src_addr unaligned?1:0)
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ extra_realignment_read <= (remaining_read_realignment
+ >= r_len[ADDRLSB-1:0]) ? 1:0;
+ if (r_len[ADDRLSB-1:0] == 0)
+ extra_realignment_read <= 1'b0;
+ if (r_src_addr[ADDRLSB-1:0] == 0)
+ extra_realignment_read <= 1'b0;
+ end else if ((!r_write_fifo || !fifo_full) && clear_read_pipeline)
+ extra_realignment_read <= 1'b0;
+
+ always @(posedge i_clk)
+ if (!r_busy || !extra_realignment_read || clear_read_pipeline)
+ clear_read_pipeline <= 0;
+ else if (!r_write_fifo || !fifo_full)
+ clear_read_pipeline <= (read_beats_remaining_w
+ == (M_AXI_RVALID ? 1:0));
+
+`ifdef FORMAL
+ always @(*)
+ if (r_busy)
+ begin
+ if (!extra_realignment_read)
+ begin
+ assert(!clear_read_pipeline);
+ end else if (read_beats_remaining_w > 0)
+ begin
+ assert(!clear_read_pipeline);
+ end else if (!no_read_bursts_outstanding)
+ begin
+ assert(!clear_read_pipeline);
+ end
+ end
+`endif
+
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_partial_in_valid <= (r_src_addr[ADDRLSB-1:0] == 0);
+ else if (M_AXI_RVALID)
+ r_partial_in_valid <= 1;
+ else if ((!r_write_fifo || !fifo_full) && clear_read_pipeline)
+ // If we have to flush the final partial valid signal,
+ // the do it when writing to the FIFO with clear_read
+ // pipelin set. Actually, this is one clock before
+ // that ...
+ r_partial_in_valid <= 0;
+
+ always @(posedge i_clk)
+ if (fifo_reset || (inbyte_shift == 0))
+ r_partial_inword <= 0;
+ else if (M_AXI_RVALID)
+ r_partial_inword <= M_AXI_RDATA >> inshift_down;
+
+ initial r_write_fifo = 0;
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_write_fifo <= 0;
+ else if (M_AXI_RVALID || clear_read_pipeline)
+ r_write_fifo <= r_partial_in_valid;
+ else if (!fifo_full)
+ r_write_fifo <= 0;
+
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_realigned_incoming <= 0;
+ else if (M_AXI_RVALID)
+ r_realigned_incoming <= r_partial_inword
+ | (M_AXI_RDATA << inshift_up);
+ else if (!r_write_fifo || !fifo_full)
+ r_realigned_incoming <= r_partial_inword;
+
+ sfifo #(
+ // {{{
+ .BW(C_AXI_DATA_WIDTH),
+ .LGFLEN(LGFIFO),
+ .OPT_ASYNC_READ(1'b1)
+ // }}}
+ ) middata(
+ // {{{
+ i_clk, fifo_reset,
+ r_write_fifo, r_realigned_incoming,
+ fifo_full, fifo_fill,
+ r_read_fifo, fifo_data, fifo_empty
+ // }}}
+ );
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ outbyte_shift <= r_dst_addr[ADDRLSB-1:0];
+ outshift_down <= 0;
+ outshift_down[3 +: ADDRLSB] <= -r_dst_addr[ADDRLSB-1:0];
+ end
+
+ always @(*)
+ outshift_up = { outbyte_shift, 3'b000 };
+
+
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_partial_outword <= 0;
+ else if (r_read_fifo && outshift_up != 0)
+ r_partial_outword
+ <= (fifo_data >> outshift_down);
+ else if (M_AXI_WVALID && M_AXI_WREADY)
+ r_partial_outword <= 0;
+
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_partial_outvalid <= 0;
+ else if (r_read_fifo && !fifo_empty)
+ r_partial_outvalid <= 1;
+ else if (fifo_empty && M_AXI_WVALID && M_AXI_WREADY)
+ r_partial_outvalid <= extra_realignment_write;
+
+ always @(posedge i_clk)
+ if (fifo_reset)
+ r_outword <= 0;
+ else if (!r_partial_outvalid || (M_AXI_WVALID && M_AXI_WREADY))
+ begin
+ if (!fifo_empty)
+ r_outword <= r_partial_outword |
+ (fifo_data << outshift_up);
+ else
+ r_outword <= r_partial_outword;
+ end
+
+ always @(*)
+ M_AXI_WDATA = r_outword;
+
+ always @(*)
+ begin
+ r_read_fifo = 0;
+ if (!r_partial_outvalid)
+ r_read_fifo = 1;
+ if (M_AXI_WVALID && M_AXI_WREADY)
+ r_read_fifo = 1;
+
+ if (fifo_empty)
+ r_read_fifo = 0;
+ end
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // Write strobe logic for the unaligned case
+ //
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ if (r_len[(LGLEN-1):(ADDRLSB+1)] != 0)
+ r_oneword <= 0;
+ else
+ r_oneword <= (({ 2'b0, r_dst_addr[ADDRLSB-1:0]}
+ + r_len[ADDRLSB+1:0]) <=
+ { 2'b01, {(ADDRLSB){1'b0}} } ? 1:0);
+ end
+
+ initial r_first_wstrb = 0;
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ if (r_len[LGLEN-1:ADDRLSB] != 0)
+ r_first_wstrb <= -1 << r_dst_addr[ADDRLSB-1:0];
+ else
+ r_first_wstrb <= ((1<<r_len[ADDRLSB-1:0]) -1) << r_dst_addr[ADDRLSB-1:0];
+ end
+
+ always @(*)
+ r_last_write_addr = r_dst_addr[ADDRLSB-1:0] + r_len[ADDRLSB-1:0];
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ if (r_last_write_addr[ADDRLSB-1:0] == 0)
+ r_last_wstrb <= -1;
+ else
+ r_last_wstrb <= (1<<r_last_write_addr)-1;
+ end
+
+ always @(posedge i_clk)
+ if (!r_busy)
+ r_firstword <= 1;
+ else if (M_AXI_WVALID && M_AXI_WREADY)
+ r_firstword <= 0;
+
+ always @(posedge i_clk)
+ if (!M_AXI_WVALID || M_AXI_WREADY)
+ begin
+ if (r_oneword)
+ M_AXI_WSTRB <= r_first_wstrb & r_last_wstrb;
+ else if (M_AXI_WVALID && M_AXI_WREADY)
+ begin
+ if (write_beats_remaining > 2)
+ M_AXI_WSTRB <= -1;
+ else
+ M_AXI_WSTRB <= r_last_wstrb;
+ end else if (r_firstword)
+ M_AXI_WSTRB <= r_first_wstrb;
+
+ if (r_err || r_abort)
+ M_AXI_WSTRB <= 0;
+ end
+ // }}}
+ end else begin : ALIGNED_FIFO
+ // {{{
+ always @(*)
+ begin
+ r_first_wstrb = -1;
+ r_last_wstrb = -1;
+ r_partial_in_valid = 1;
+ r_partial_outvalid = !fifo_empty;
+
+ r_write_fifo = M_AXI_RVALID;
+ r_read_fifo = M_AXI_WVALID && M_AXI_WREADY;
+
+ clear_read_pipeline = 1'b0;
+ end
+
+ sfifo #(
+ // {{{
+ .BW(C_AXI_DATA_WIDTH),
+ .LGFLEN(LGFIFO),
+ .OPT_ASYNC_READ(1'b1)
+ // }}}
+ ) middata(
+ // {{{
+ i_clk, fifo_reset,
+ r_write_fifo, M_AXI_RDATA, fifo_full, fifo_fill,
+ r_read_fifo, M_AXI_WDATA, fifo_empty
+ // }}}
+ );
+
+
+ initial M_AXI_WSTRB = -1;
+ always @(posedge i_clk)
+ if (!S_AXI_ARESETN || !r_busy)
+ M_AXI_WSTRB <= -1;
+ else if (!M_AXI_WVALID || M_AXI_WREADY)
+ M_AXI_WSTRB <= (r_err || r_abort) ? 0 : -1;
+
+ always @(*)
+ extra_realignment_read <= 0;
+ // }}}
+ end endgenerate
+
+ // fifo_space_available
+ // {{{
+ always @(posedge i_clk)
+ if (fifo_reset)
+ fifo_space_available <= (1<<LGFIFO)
+ // space for r_partial_outvalid
+ + (OPT_UNALIGNED ? 1:0)
+ // space for r_partial_in_valid
+ + (OPT_UNALIGNED && (r_src_addr[ADDRLSB-1:0] != 0) ? 1:0);
+ else case({ phantom_read, M_AXI_WVALID && M_AXI_WREADY })
+ // Verilator lint_off WIDTH
+ 2'b10: fifo_space_available <= fifo_space_available - (M_AXI_ARLEN+1);
+ 2'b01: fifo_space_available <= fifo_space_available + 1;
+ 2'b11: fifo_space_available <= fifo_space_available - M_AXI_ARLEN;
+ // Verilator lint_on WIDTH
+ default: begin end
+ endcase
+ // }}}
+
+ // write_realignment
+ // {{{
+ always @(*)
+ if (OPT_UNALIGNED)
+ begin
+ // Verilator lint_off WIDTH
+ // write_remaining
+ write_realignment[ADDRLSB+1:0]
+ = r_len[ADDRLSB-1:0]+r_dst_addr[ADDRLSB-1:0]
+ + (1<<ADDRLSB)-1;
+
+ // Raw length
+ write_realignment[2*ADDRLSB+2:ADDRLSB+2]
+ = r_len[ADDRLSB-1:0] + (1<<ADDRLSB)-1;
+ // Verilator lint_on WIDTH
+ end else
+ write_realignment = 0;
+ // }}}
+
+ // extra_realignment_write
+ // {{{
+ always @(posedge i_clk)
+ if (!OPT_UNALIGNED)
+ extra_realignment_write <= 1'b0;
+ else if (!r_busy)
+ begin
+ if ({ 1'b0, write_realignment[2*ADDRLSB+2] }
+ != write_realignment[ADDRLSB+1:ADDRLSB])
+ extra_realignment_write <= 1'b1;
+ else
+ extra_realignment_write <= 1'b0;
+ end else if (M_AXI_WVALID && M_AXI_WREADY && fifo_empty)
+ extra_realignment_write <= 1'b0;
+ // }}}
+
+ // last_read_beat
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ last_read_beat <= 1'b0;
+ else
+ last_read_beat <= M_AXI_RVALID && M_AXI_RREADY
+ && (read_beats_remaining_w == 1);
+ // }}}
+
+ // next_fifo_data_available
+ // {{{
+ always @(*)
+ begin
+ next_fifo_data_available = fifo_data_available;
+ // Verilator lint_off WIDTH
+ if (phantom_write)
+ next_fifo_data_available = next_fifo_data_available
+ - (M_AXI_AWLEN + (r_write_fifo && !fifo_full ? 0:1));
+ else if (r_write_fifo && !fifo_full)
+ next_fifo_data_available = next_fifo_data_available + 1;
+
+ if (extra_realignment_write && last_read_beat)
+ next_fifo_data_available = next_fifo_data_available + 1;
+ // Verilator lint_on WIDTH
+ end
+ // }}}
+
+ // fifo_data_available
+ // {{{
+ initial fifo_data_available = 0;
+ always @(posedge i_clk)
+ if (!r_busy || r_done)
+ fifo_data_available <= 0;
+ else
+ fifo_data_available <= next_fifo_data_available;
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI write processing
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ //
+ // Write data from the FIFO to the AXI bus
+ //
+
+ // write_address
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ write_address <= { 1'b0, r_dst_addr };
+ else if (phantom_write)
+ begin
+ // Verilator lint_off WIDTH
+ write_address <= write_address + ((M_AXI_AWLEN+1)<< M_AXI_AWSIZE);
+ // Verilator lint_on WIDTH
+ write_address[ADDRLSB-1:0] <= 0;
+ end
+ // }}}
+
+ // writes_remaining_w, multiple_write_bursts_remaining
+ // {{{
+ // Verilator lint_off WIDTH
+ always @(*)
+ w_writes_remaining_w = writes_remaining_w - (M_AXI_AWLEN+1);
+
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ writes_remaining_w <= writelen_b[LGLEN:ADDRLSB];
+ multiple_write_bursts_remaining <= |writelen_b[LGLEN:(ADDRLSB+LGMAXBURST)];
+ end else if (phantom_write)
+ begin
+ writes_remaining_w <= w_writes_remaining_w;
+ multiple_write_bursts_remaining
+ <= |w_writes_remaining_w[LGLENW:LGMAXBURST];
+ end
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // write_beats_remaining
+ // {{{
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ write_beats_remaining <= writelen_b[LGLEN:ADDRLSB];
+ end else if (M_AXI_WVALID && M_AXI_WREADY)
+ write_beats_remaining <= write_beats_remaining - 1;
+ // }}}
+
+ // write_requests_remaining
+ // {{{
+ // Verilator lint_off WIDTH
+ initial write_requests_remaining = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ write_requests_remaining <= 1'b0;
+ else if (!r_busy)
+ write_requests_remaining <= w_start;
+ else if (phantom_write)
+ write_requests_remaining <= (writes_remaining_w != (M_AXI_AWLEN+1));
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // write_bursts_outstanding
+ // {{{
+ initial write_bursts_outstanding = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ write_bursts_outstanding <= 0;
+ end else case({phantom_write, M_AXI_BVALID && M_AXI_BREADY })
+ 2'b01: write_bursts_outstanding <= write_bursts_outstanding - 1;
+ 2'b10: write_bursts_outstanding <= write_bursts_outstanding + 1;
+ default: begin end
+ endcase
+ // }}}
+
+ // last_write_ack
+ // {{{
+ // Verilator lint_off WIDTH
+ always @(posedge i_clk)
+ if (!r_busy)
+ last_write_ack <= 0;
+ else if (writes_remaining_w > ((phantom_write) ? (M_AXI_AWLEN+1) : 0))
+ last_write_ack <= 0;
+ else
+ last_write_ack <= (write_bursts_outstanding
+ == (phantom_write ? 0:1) + (M_AXI_BVALID ? 1:0));
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // r_done
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy || M_AXI_ARVALID || M_AXI_AWVALID)
+ r_done <= 0;
+ else if (read_bursts_outstanding > 0)
+ r_done <= 0;
+ else if (write_bursts_outstanding > (M_AXI_BVALID ? 1:0))
+ r_done <= 0;
+ else if (r_abort || r_err)
+ r_done <= 1;
+ else if (writes_remaining_w > 0)
+ r_done <= 0;
+ else
+ r_done <= 1;
+ // }}}
+
+ // writelen_b
+ // {{{
+ always @(*)
+ if (OPT_UNALIGNED)
+ writelen_b = { 1'b0, r_len } + { {(LGLEN+1-ADDRLSB){1'b0}},
+ r_dst_addr[ADDRLSB-1:0] }
+ + { {(LGLEN+1-ADDRLSB){1'b0}}, {(ADDRLSB){1'b1}} };
+ // was + (1<<ADDRLSB)-1;
+ else begin
+ writelen_b = { 1'b0, r_len };
+ writelen_b[ADDRLSB-1:0] = 0;
+ end
+ // }}}
+
+ // initial_write_distance_to_boundary_w
+ // {{{
+ always @(*)
+ begin
+ initial_write_distance_to_boundary_w
+ = - { 1'b0, write_address[ADDRLSB +: LGMAXBURST] };
+ initial_write_distance_to_boundary_w[LGMAXBURST] = 1'b0;
+ end
+ // }}}
+
+ // first_write_burst, first_write_len_w
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ begin
+ first_write_burst <= 1'b1;
+ if (|writelen_b[LGLEN:ADDRLSB+LGMAXBURST])
+ first_write_len_w <= MAXBURST;
+ else
+ first_write_len_w <= { 1'b0,
+ writelen_b[ADDRLSB +: LGMAXBURST] };
+ end else begin
+ if (phantom_write)
+ first_write_burst <= 1'b0;
+
+ if (first_write_burst
+ && write_address[ADDRLSB +: LGMAXBURST] != 0
+ && first_write_len_w
+ > initial_write_distance_to_boundary_w)
+ first_write_len_w<=initial_write_distance_to_boundary_w;
+ end
+ // }}}
+
+ // write_burst_length
+ // {{{
+ // Verilator lint_off WIDTH
+ always @(*)
+ if (first_write_burst)
+ write_burst_length = first_write_len_w;
+ else begin
+ write_burst_length = MAXBURST;
+
+ if (!multiple_write_bursts_remaining
+ && (write_burst_length[ADDRLSB +: LGMAXBURST]
+ > writes_remaining_w[ADDRLSB +: LGMAXBURST]))
+ write_burst_length = writes_remaining_w;
+ end
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // write_count
+ // {{{
+ initial write_count = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ write_count <= 0;
+ else if (w_write_start)
+ begin
+ write_count <= 0;
+ write_count[LGMAXBURST:0] <= write_burst_length[LGMAXBURST:0];
+ end else if (M_AXI_WVALID && M_AXI_WREADY)
+ write_count <= write_count - 1;
+ // }}}
+
+ // M_AXI_WLAST
+ // {{{
+ initial M_AXI_WLAST = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ begin
+ M_AXI_WLAST <= 0;
+ end else if (!M_AXI_WVALID || M_AXI_WREADY)
+ begin
+ M_AXI_WLAST <= 1;
+ if (write_count > 2)
+ M_AXI_WLAST <= 0;
+ if (w_write_start)
+`ifdef AXI3
+ M_AXI_WLAST <= (write_burst_length[3:0] == 1);
+`else
+ M_AXI_WLAST <= (write_burst_length[7:0] == 1);
+`endif
+ end
+ // }}}
+
+ // w_write_start
+ // {{{
+ always @(*)
+ last_write_burst = (write_burst_length == writes_remaining_w);
+
+ always @(*)
+ begin
+ // Verilator lint_off WIDTH
+ if (!last_write_burst && OPT_UNALIGNED)
+ w_write_start = (fifo_data_available > 1)
+ &&(fifo_data_available > write_burst_length);
+ else
+ w_write_start = (fifo_data_available >= write_burst_length);
+ // Verilator lint_on WIDTH
+ if (!write_requests_remaining)
+ w_write_start = 0;
+ if (!OPT_WRAPMEM && write_address[C_AXI_ADDR_WIDTH])
+ w_write_start = 0;
+ if (phantom_write)
+ w_write_start = 0;
+ if (M_AXI_AWVALID && !M_AXI_AWREADY)
+ w_write_start = 0;
+ if (M_AXI_WVALID && (!M_AXI_WLAST || !M_AXI_WREADY))
+ w_write_start = 0;
+ if (i_reset || r_err || r_abort || !r_busy)
+ w_write_start = 0;
+ end
+ // }}}
+
+ // M_AXI_AWVALID, phantom_write
+ // {{{
+ initial M_AXI_AWVALID = 0;
+ initial phantom_write = 0;
+ always @(posedge i_clk)
+ if (i_reset)
+ begin
+ M_AXI_AWVALID <= 0;
+ phantom_write <= 0;
+ end else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+ begin
+ M_AXI_AWVALID <= w_write_start;
+ phantom_write <= w_write_start;
+ end else
+ phantom_write <= 0;
+ // }}}
+
+ // M_AXI_WVALID
+ // {{{
+ initial M_AXI_WVALID = 1'b0;
+ always @(posedge i_clk)
+ if (i_reset)
+ M_AXI_WVALID <= 0;
+ else if (!M_AXI_WVALID || M_AXI_WREADY)
+ begin
+ M_AXI_WVALID <= 0;
+ if (M_AXI_WVALID && !M_AXI_WLAST)
+ M_AXI_WVALID <= 1;
+ if (w_write_start)
+ M_AXI_WVALID <= 1;
+ end
+ // }}}
+
+ // M_AXI_AWLEN
+ // {{{
+ initial M_AXI_AWLEN = 0;
+ always @(posedge i_clk)
+ if (i_reset || !r_busy)
+ M_AXI_AWLEN <= 0;
+ else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+ begin
+ M_AXI_AWLEN <= 0;
+ if (w_write_start)
+`ifdef AXI3
+ M_AXI_AWLEN <= write_burst_length[3:0]-1;
+`else
+ M_AXI_AWLEN <= write_burst_length[7:0]-1;
+`endif
+ end
+ // }}}
+
+ // M_AXI_AWADDR
+ // {{{
+ always @(posedge i_clk)
+ if (!r_busy)
+ M_AXI_AWADDR <= r_dst_addr;
+ else if (!M_AXI_AWVALID || M_AXI_AWREADY)
+ M_AXI_AWADDR <= write_address[C_AXI_ADDR_WIDTH-1:0];
+ // }}}
+
+ always @(*)
+ begin
+ M_AXI_AWID = AXI_WRITE_ID;
+ M_AXI_AWBURST = AXI_INCR;
+ M_AXI_AWSIZE = ADDRLSB[2:0];
+ M_AXI_AWLOCK = 1'b0;
+ M_AXI_AWCACHE = 4'b0011;
+ M_AXI_AWPROT = r_prot;
+ M_AXI_AWQOS = r_qos;
+ //
+`ifdef AXI3
+ M_AXI_WID = AXI_WRITE_ID;
+`endif
+ M_AXI_BREADY = !r_done;
+ end
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // (Optional) Clock gating
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ generate if (OPT_CLKGATE)
+ begin : CLK_GATING
+ // {{{
+ reg 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;
+ end
+
+ assign clk_active = r_clk_active;
+ // }}}
+ // Gate the clock here locally
+ // {{{
+ always @(negedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ gaten <= 1'b1;
+ else
+ gaten <= r_clk_active;
+
+ 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 lint_off UNUSED
+ // Verilator coverage_off
+ wire unused;
+ assign unused = &{ 1'b0, S_AXIL_AWPROT, S_AXIL_ARPROT, M_AXI_BID,
+ M_AXI_RID, M_AXI_BRESP[0], M_AXI_RRESP[0],
+ S_AXIL_AWADDR[AXILLSB-1:0], S_AXIL_ARADDR[AXILLSB-1:0],
+ fifo_full, fifo_fill, fifo_empty,
+`ifdef AXI3
+ readlen_w[LGLENW:4],
+`else
+ readlen_w[LGLENW:8],
+`endif
+ writelen_b[ADDRLSB-1:0], readlen_b[ADDRLSB-1:0],
+ read_distance_to_boundary_b
+ };
+
+ generate if (C_AXI_ADDR_WIDTH < 2*C_AXIL_DATA_WIDTH)
+ begin : NEW_UNUSED
+ wire genunused;
+
+ assign genunused = &{ 1'b0,
+ new_widesrc[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH],
+ new_widedst[2*C_AXIL_DATA_WIDTH-1:C_AXI_ADDR_WIDTH] };
+ end endgenerate
+
+ // Verilator coverage_on
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal property section
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The following formal properties are only a subset of those used
+ // to verify the full core. Do not be surprised to find syntax errors
+ // here, or registers that are not defined. These are correct in the
+ // full version.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ reg f_past_valid;
+
+ initial f_past_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ f_past_valid <= 1;
+
+ //
+ // ...
+ //
+
+ reg [C_AXI_ADDR_WIDTH:0] f_next_wraddr, f_next_rdaddr;
+
+ reg [C_AXI_ADDR_WIDTH:0] f_src_addr, f_dst_addr,
+ f_read_address, f_write_address,
+ f_read_check_addr, f_write_beat_addr,
+ f_read_beat_addr;
+ reg [LGLEN:0] f_length, f_rdlength, f_wrlength,
+ f_writes_complete, f_reads_complete;
+
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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)
+ //
+ // ...
+ //
+ );
+
+ //
+ // ...
+ //
+
+ //
+ // Verify the AXI-lite result registers
+ //
+ always @(*)
+ if (!r_busy)
+ assert((r_done && (r_err || r_abort))
+ || (zero_len == (r_len == 0)));
+ else
+ assert(zero_len == (r_len == 0 && writes_remaining_w == 0));
+
+ always @(*)
+ if (!i_reset && !OPT_UNALIGNED)
+ assert(r_src_addr[ADDRLSB-1:0] == 0);
+
+ always @(*)
+ if (!i_reset && !OPT_UNALIGNED)
+ assert(r_dst_addr[ADDRLSB-1:0] == 0);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // The main AXI data 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_MAXBURST(MAXBURST)
+ //
+ // ...
+ //
+ )
+ faxi(
+ .i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(M_AXI_AWVALID),
+ .i_axi_awready(M_AXI_AWREADY),
+ .i_axi_awid( M_AXI_AWID),
+ .i_axi_awaddr( M_AXI_AWADDR),
+ .i_axi_awlen( M_AXI_AWLEN),
+ .i_axi_awsize( M_AXI_AWSIZE),
+ .i_axi_awburst(M_AXI_AWBURST),
+ .i_axi_awlock( M_AXI_AWLOCK),
+ .i_axi_awcache(M_AXI_AWCACHE),
+ .i_axi_awprot( M_AXI_AWPROT),
+ .i_axi_awqos( M_AXI_AWQOS),
+ //
+ .i_axi_wvalid(M_AXI_WVALID),
+ .i_axi_wready(M_AXI_WREADY),
+ .i_axi_wdata( M_AXI_WDATA),
+ .i_axi_wstrb( M_AXI_WSTRB),
+ .i_axi_wlast( M_AXI_WLAST),
+ //
+ .i_axi_bvalid(M_AXI_BVALID),
+ .i_axi_bready(M_AXI_BREADY),
+ .i_axi_bid( M_AXI_BID),
+ .i_axi_bresp( M_AXI_BRESP),
+ //
+ .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_rid( M_AXI_RID),
+ .i_axi_rdata( M_AXI_RDATA),
+ .i_axi_rlast( M_AXI_RLAST),
+ .i_axi_rresp( M_AXI_RRESP)
+ //
+ // ...
+ //
+ );
+
+ always @(*)
+ begin
+ //
+ // ...
+ //
+ if (r_done)
+ begin
+ //
+ // ...
+ //
+ assert(!M_AXI_AWVALID);
+ assert(!M_AXI_WVALID);
+ assert(!M_AXI_ARVALID);
+ end
+ end
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Internal assertions (Induction)
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ always @(posedge S_AXI_ACLK)
+ if (w_start)
+ begin
+ f_src_addr <= { 1'b0, r_src_addr };
+ f_dst_addr <= { 1'b0, r_dst_addr };
+ f_length <= r_len;
+ end else if (r_busy)
+ begin
+ assert(f_length != 0);
+ assert(f_length[LGLEN] == 0);
+
+ assert(f_src_addr[C_AXI_ADDR_WIDTH] == 1'b0);
+ assert(f_dst_addr[C_AXI_ADDR_WIDTH] == 1'b0);
+ end
+
+ always @(*)
+ begin
+ f_rdlength = f_length + f_src_addr[ADDRLSB-1:0]
+ + (1<<ADDRLSB)-1;
+ f_rdlength[ADDRLSB-1:0] = 0;
+
+ f_wrlength = f_length + f_dst_addr[ADDRLSB-1:0]
+ + (1<<ADDRLSB)-1;
+ f_wrlength[ADDRLSB-1:0] = 0;
+
+ f_raw_length = f_length + (1<<ADDRLSB)-1;
+ f_raw_length[ADDRLSB-1:0] = 0;
+
+ // One past the last address we'll actually read
+ f_last_src_addr = f_src_addr + f_length + (1<<ADDRLSB)-1;
+ f_last_src_addr[ADDRLSB-1:0] = 0;
+ f_last_src_beat = f_src_addr + f_length -1;
+ f_last_src_beat[ADDRLSB-1:0] = 0;
+
+ f_last_dst_addr = f_dst_addr + f_length + (1<<ADDRLSB)-1;
+ f_last_dst_addr[ADDRLSB-1:0] = 0;
+
+ f_rd_arfirst = ({ 1'b0, M_AXI_ARADDR } == f_src_addr);
+ f_rd_arlast = (M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ + (M_AXI_ARLEN+1)
+ == f_last_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+ f_rd_ckfirst = (faxi_rd_ckaddr == f_src_addr);
+ f_rd_cklast = (faxi_rd_ckaddr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ + faxi_rd_cklen == f_last_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+
+ // f_extra_realignment_read
+ // true if we need to write a partial word to the FIFO/buffer
+ // *after* all of our reads are complete. This is a final
+ // flush sort of thing.
+ if (OPT_UNALIGNED && f_src_addr[ADDRLSB-1:0] != 0)
+ begin
+ // In general, if we are 1) unaligned, and 2) the
+ // length is greater than a word, and 3) there's a
+ // fraction of a word remaining, then we need to flush
+ // a last word into the FIFO.
+ f_extra_realignment_read
+ = (((1<<ADDRLSB)-f_src_addr[ADDRLSB-1:0])
+ >= f_length[ADDRLSB-1:0]) ? 1:0;
+ if (f_length[ADDRLSB-1:0] == 0)
+ f_extra_realignment_read = 0;
+ end else
+ f_extra_realignment_read = 1'b0;
+
+ //
+ // f_extra_realignment_preread
+ // will be true anytime we need to read a first word before
+ // writing anything to the buffer.
+ if (OPT_UNALIGNED && f_src_addr[ADDRLSB-1:0] != 0)
+ f_extra_realignment_preread = 1'b1;
+ else
+ f_extra_realignment_preread = 1'b0;
+
+ //
+ // f_extra_realignment_write
+ // true if following the last read from the FIFO there's a
+ // partial word that will need to be flushed through the
+ // system.
+ if (OPT_UNALIGNED && f_raw_length[LGLEN:ADDRLSB]
+ != f_wrlength[LGLEN:ADDRLSB])
+ f_extra_realignment_write = 1'b1;
+ else
+ f_extra_realignment_write = 1'b0;
+
+ f_extra_write_in_fifo = (f_extra_realignment_write)
+ && (read_beats_remaining_w == 0)&&(!last_read_beat);
+ end
+
+ always @(*)
+ if (r_busy && !OPT_UNALIGNED)
+ begin
+ assert(f_src_addr[ADDRLSB-1:0] == 0);
+ assert(f_dst_addr[ADDRLSB-1:0] == 0);
+ assert(f_length[ADDRLSB-1:0] == 0);
+ end
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (!f_extra_realignment_write)
+ assert(!extra_realignment_write);
+ else if (f_writes_complete >= f_wrlength[LGLEN:ADDRLSB]-1)
+ assert(!extra_realignment_write);
+ else
+ assert(extra_realignment_write);
+
+ if ((f_writes_complete > 0 || M_AXI_WVALID)
+ && extra_realignment_write)
+ assert(r_partial_outvalid);
+ end
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (extra_realignment_read)
+ assert(f_extra_realignment_read);
+ else if (read_beats_remaining_w > 0)
+ assert(f_extra_realignment_read == extra_realignment_read);
+ end
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (fifo_full)
+ assert(no_read_bursts_outstanding);
+
+ always @(*)
+ if (r_busy)
+ assert(!r_int);
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Write checks
+ //
+
+ //
+ // ...
+ //
+
+ always @(*)
+ begin
+ f_write_address = 0;
+ f_write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + (f_wrlength[LGLEN:ADDRLSB] - writes_remaining_w);
+ end
+
+ always @(*)
+ begin
+ f_next_wraddr = { 1'b0, M_AXI_AWADDR }
+ + ((M_AXI_AWLEN+1)<<M_AXI_AWSIZE);
+ f_next_wraddr[ADDRLSB-1:0] = 0;
+ end
+
+ always @(*)
+ if (M_AXI_AWVALID)
+ begin
+ assert(M_AXI_WVALID);
+ assert(M_AXI_AWLEN < (1<<LGMAXBURST));
+
+ if (M_AXI_AWLEN != (1<<LGMAXBURST)-1)
+ begin
+ assert((M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ == f_dst_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB])
+ ||(phantom_write)
+ ||(writes_remaining_w == 0));
+ end else begin
+ assert(M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ == f_write_beat_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]);
+ end
+
+ if (M_AXI_AWADDR[ADDRLSB-1:0] != 0)
+ assert({ 1'b0, M_AXI_AWADDR[C_AXI_ADDR_WIDTH-1:0] }
+ == f_dst_addr);
+ else if (M_AXI_AWADDR != f_dst_addr)
+ assert(M_AXI_AWADDR[0 +: LGMAXBURST+ADDRLSB] == 0);
+ end
+
+ always @(*)
+ if (!OPT_UNALIGNED)
+ begin
+ assert(r_len[ADDRLSB-1:0] == 0);
+ assert(r_src_addr[ADDRLSB-1:0] == 0);
+ assert(r_dst_addr[ADDRLSB-1:0] == 0);
+ end
+
+ always @(*)
+ if (r_busy)
+ begin
+ assert(writes_remaining_w <= f_wrlength[LGLEN:ADDRLSB]);
+ assert(f_writes_complete <= f_wrlength[LGLEN:ADDRLSB]);
+ assert(fifo_fill <= f_wrlength[LGLEN:ADDRLSB]);
+
+ assert(write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ == f_write_address[C_AXI_ADDR_WIDTH:ADDRLSB]);
+
+ if (M_AXI_AWADDR != f_dst_addr && writes_remaining_w != 0)
+ assert(M_AXI_AWADDR[LGMAXBURST+ADDRLSB-1:0] == 0);
+ else if (!OPT_UNALIGNED)
+ assert(M_AXI_AWADDR[ADDRLSB-1:0] == 0);
+
+ if((writes_remaining_w!= f_wrlength[LGLEN:ADDRLSB])
+ &&(writes_remaining_w != 0))
+ assert(write_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+ if ((write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ != f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+ &&(writes_remaining_w > 0))
+ assert(write_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+ if (writes_remaining_w != f_wrlength[LGLEN:ADDRLSB]
+ && writes_remaining_w != 0)
+ assert((write_burst_length == (1<<LGMAXBURST))
+ ||(write_burst_length == writes_remaining_w));
+
+ assert(write_requests_remaining == (writes_remaining_w != 0));
+ end
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (M_AXI_AWVALID && !phantom_write)
+ begin
+ assert(write_count == (M_AXI_AWLEN+1));
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ if (r_busy && last_write_ack)
+ begin
+ assert(reads_remaining_w == 0);
+ assert(!M_AXI_ARVALID);
+ assert(writes_remaining_w == 0);
+ end
+
+ always @(*)
+ if (r_busy && !r_abort && !r_err)
+ assert(write_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ == f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ || (write_address[LGMAXBURST-1:0] == 0)
+ || (writes_remaining_w == 0));
+
+ always @(*)
+ if (phantom_write)
+ assert(writes_remaining_w >= (M_AXI_AWLEN+1));
+ else if (M_AXI_AWVALID)
+ assert(write_address[C_AXI_ADDR_WIDTH-1:0]
+ == f_next_wraddr[C_AXI_ADDR_WIDTH-1:0]);
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (M_AXI_WVALID)
+ begin
+ if (OPT_UNALIGNED)
+ assert(r_partial_outvalid);
+ else
+ assert(!fifo_empty || r_abort || r_err);
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ begin
+ f_write_beat_addr = 0;
+ f_write_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + (f_wrlength[LGLEN:ADDRLSB]-write_beats_remaining);
+
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ if (r_busy)
+ begin
+ //
+ // ...
+ //
+
+ if (write_beats_remaining == 0)
+ assert(!M_AXI_WVALID);
+ end
+
+ always @(*)
+ if (writes_remaining_w < f_wrlength[LGLEN:ADDRLSB])
+ begin
+ if (writes_remaining_w == 0)
+ assert(fifo_data_available == 0);
+ // else ...
+ end
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Read checks
+ //
+ always @(*)
+ begin
+ f_reads_complete = f_rdlength[LGLEN:ADDRLSB]
+ - reads_remaining_w - // ...
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ begin
+ if (reads_remaining_w == f_rdlength[LGLEN:ADDRLSB])
+ f_read_address = f_src_addr;
+ else begin
+ f_read_address = 0;
+ f_read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + (f_rdlength[LGLEN:ADDRLSB] - reads_remaining_w);
+ end
+
+ f_araddr = f_read_address;
+ if (M_AXI_ARVALID && !phantom_read)
+ f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ - (M_AXI_ARLEN+1);
+ if (f_araddr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ == f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+ f_araddr[ADDRLSB-1:0] = f_src_addr[ADDRLSB-1:0];
+
+ //
+ // Match the read check address to our source address
+ //
+ f_read_check_addr = 0;
+ f_read_check_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ = f_src_addr[C_AXI_ADDR_WIDTH-1:ADDRLSB]
+ + f_reads_complete + // ...
+
+
+ //
+ // Match the RVALID address to our source address
+ //
+ f_read_beat_addr = 0;
+ if (f_reads_complete == 0)
+ f_read_beat_addr = f_src_addr;
+ else
+ f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + f_reads_complete;
+
+ f_end_of_read_burst = M_AXI_ARADDR;
+ f_end_of_read_burst[ADDRLSB-1:0] = 0;
+ f_end_of_read_burst[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_end_of_read_burst[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + (M_AXI_ARLEN + 1);
+
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ begin
+ f_next_rdaddr = { 1'b0, M_AXI_ARADDR } + ((M_AXI_ARLEN+1)<<M_AXI_ARSIZE);
+ f_next_rdaddr[ADDRLSB-1:0] = 0;
+ end
+
+ /////////
+ //
+ // Constrain the read address
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (!f_rd_arfirst)
+ begin
+ assert(reads_remaining_w < f_rdlength[LGLEN:ADDRLSB]);
+
+ // All bursts following the first one must be aligned
+ if (M_AXI_ARVALID || reads_remaining_w > 0)
+ assert(M_AXI_ARADDR[0 +: LGMAXBURST + ADDRLSB] == 0);
+ end else if (phantom_read)
+ assert(reads_remaining_w == f_rdlength[LGLEN:ADDRLSB]);
+ else if (M_AXI_ARVALID)
+ assert(reads_remaining_w == f_rdlength[LGLEN:ADDRLSB]
+ - (M_AXI_ARLEN+1));
+
+ // All but the first burst should be aligned
+ if (!OPT_UNALIGNED || M_AXI_ARADDR != f_src_addr)
+ assert(M_AXI_ARADDR[ADDRLSB-1:0] == 0);
+
+ if (phantom_read)
+ assert(M_AXI_ARADDR == read_address[C_AXI_ADDR_WIDTH-1:0]);
+ else if (M_AXI_ARVALID)
+ assert(read_address[C_AXI_ADDR_WIDTH-1:0] == f_next_rdaddr[C_AXI_ADDR_WIDTH-1:0]);
+ end // else ...
+
+ //
+ // ...
+ //
+
+ // Constrain read_address--our pointer to the next bursts address
+ always @(*)
+ if (r_busy)
+ begin
+ assert((read_address == f_src_addr)
+ || (read_address[LGMAXBURST+ADDRLSB-1:0] == 0)
+ || (reads_remaining_w == 0));
+
+
+ assert(read_address == f_read_address);
+ if (!OPT_UNALIGNED)
+ assert(read_address[ADDRLSB-1:0] == 0);
+
+ if ((reads_remaining_w != f_rdlength[LGLEN:ADDRLSB])
+ &&(reads_remaining_w > 0))
+ assert(read_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+
+ if ((read_address[C_AXI_ADDR_WIDTH:ADDRLSB]
+ != f_src_addr[C_AXI_ADDR_WIDTH:ADDRLSB])
+ &&(reads_remaining_w > 0))
+ assert(read_address[LGMAXBURST+ADDRLSB-1:0] == 0);
+ end
+
+
+ /////////
+ //
+ // Constrain the read length
+ //
+ always @(*)
+ if (M_AXI_ARVALID)
+ begin
+ assert(M_AXI_ARLEN < (1<<LGMAXBURST));
+ if (M_AXI_ARLEN != (1<<LGMAXBURST)-1)
+ begin
+ assert((M_AXI_ARADDR == f_src_addr)
+ ||(phantom_read)
+ ||(reads_remaining_w == 0));
+ end
+
+ assert(f_end_of_read_burst_last[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]
+ == M_AXI_ARADDR[C_AXI_ADDR_WIDTH-1:LGMAXBURST+ADDRLSB]);
+ end
+
+ always @(*)
+ if (M_AXI_ARVALID && reads_remaining_w > (M_AXI_ARLEN+1))
+ assert(f_end_of_read_burst[ADDRLSB+LGMAXBURST-1:0]==0);
+
+
+ /////////
+ //
+ // Constrain RLAST
+ //
+
+ always @(*)
+ if (M_AXI_RVALID)
+ begin
+ if (M_AXI_RLAST)
+ begin
+ if (f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ != f_last_src_beat[C_AXI_ADDR_WIDTH:ADDRLSB])
+ assert(&f_read_beat_addr[ADDRLSB+LGMAXBURST-1:ADDRLSB]);
+ end else
+ assert(f_read_beat_addr[ADDRLSB+LGMAXBURST-1:ADDRLSB]
+ != {(LGMAXBURST){1'b1}});
+ end
+
+ always @(*)
+ if (f_read_beat_addr == f_last_src_beat)
+ assert(!M_AXI_RVALID || M_AXI_RLAST);
+ else
+ assert(!M_AXI_RVALID
+ || M_AXI_RLAST == (&f_read_beat_addr[LGMAXBURST+ADDRLSB-1:ADDRLSB]));
+
+
+ /////////
+ //
+ //
+ //
+
+
+ always @(*)
+ assert(no_read_bursts_outstanding == (read_bursts_outstanding == 0));
+
+ always @(*)
+ if (r_busy && !r_err)
+ assert(f_read_beat_addr[C_AXI_ADDR_WIDTH-1:0] == r_src_addr);
+
+ always @(*)
+ if (r_busy)
+ begin
+ // Some quick checks to make sure the subsequent checks
+ // don't overflow anything
+ assert(reads_remaining_w <= f_rdlength[LGLEN:ADDRLSB]);
+ assert(f_reads_complete <= f_rdlength[LGLEN:ADDRLSB]);
+ // ...
+ assert(fifo_fill <= f_raw_length[LGLEN:ADDRLSB]);
+ assert(fifo_space_available<= (1<<LGFIFO));
+ assert(fifo_space_available<= (1<<LGFIFO) - fifo_fill);
+ // ...
+
+
+ if (reads_remaining_w != f_rdlength[LGLEN:ADDRLSB]
+ && reads_remaining_w != 0)
+ assert((readlen_w == (1<<LGMAXBURST))
+ ||(readlen_w == reads_remaining_w));
+
+ //
+ // Read-length checks
+ assert(readlen_w <= (1<<LGMAXBURST));
+ if (reads_remaining_w > 0)
+ assert(readlen_w != 0);
+ if (readlen_w != (1<<LGMAXBURST))
+ assert(reads_remaining_w == readlen_w
+ ||(read_address == f_src_addr));
+ end
+
+ //
+ // ...
+ //
+
+ ////////////////////////////////////////
+ //
+ // Errors or aborts -- do we properly end gracefully
+ //
+ // Make certain we don't deadlock here, but also that we wait
+ // for the last burst return before we clear
+ //
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && r_busy && $past(r_busy))
+ begin
+ // Not allowed to set r_done while anything remains outstanding
+ if (!no_read_bursts_outstanding)
+ assert(!r_done);
+ if (write_bursts_outstanding > 0)
+ assert(!r_done);
+
+ //
+ // If no returns are outstanding, and following an error, then
+ // r_done should be set
+ if ($past(r_busy && (r_err || r_abort))
+ &&($past(!M_AXI_ARVALID && read_bursts_outstanding==0))
+ &&($past(!M_AXI_AWVALID && write_bursts_outstanding==0)))
+ assert(r_done);
+
+ if ($past(r_err || r_abort))
+ begin
+ //
+ // Just double check that we aren't starting anything
+ // new following either an abort or an error
+ //
+ assert(!$rose(M_AXI_ARVALID));
+ assert(!$rose(M_AXI_AWVALID));
+
+ if ($past(!M_AXI_WVALID || M_AXI_WREADY))
+ assert(M_AXI_WSTRB == 0);
+ end
+ end
+
+ //
+ // ...
+ //
+
+ ////////////////////////////////////////
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ if (readlen_w == 0)
+ assert(reads_remaining_w == 0);
+ else begin
+ assert(reads_remaining_w > 0);
+ if (!w_start_read)
+ begin
+ assert(readlen_w <= reads_remaining_w);
+ assert(readlen_w <= (1<<LGMAXBURST));
+ end
+ end
+ end
+
+ always @(*)
+ if (M_AXI_BVALID)
+ assert(M_AXI_BREADY);
+
+ always @(*)
+ if (M_AXI_RVALID)
+ assert(M_AXI_RREADY);
+
+ generate if (OPT_UNALIGNED)
+ begin : REALIGNMENT_CHECKS
+
+ //
+ // ...
+ //
+
+ end endgenerate
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // FIFO checks
+ //
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (phantom_read)
+ assert(M_AXI_ARVALID);
+
+ always @(*)
+ if (phantom_write)
+ assert(M_AXI_AWVALID);
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Combined
+ //
+
+ always @(*)
+ if (r_busy)
+ begin
+ //
+ // ...
+ //
+
+ assert(writes_remaining_w + write_bursts_outstanding
+ <= f_wrlength[LGLEN:ADDRLSB]);
+
+ //
+ // ...
+ //
+ if (write_count > 0)
+ assert(M_AXI_WVALID);
+ //
+ // ...
+ //
+ end
+
+ always @(*)
+ if (r_busy)
+ assert(last_write_ack == ((write_bursts_outstanding <= 1)
+ &&(writes_remaining_w == 0)));
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Initial (only) constraints
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ always @(posedge S_AXI_ACLK)
+ if (!f_past_valid || $past(!S_AXI_ARESETN))
+ begin
+ assert(!S_AXIL_BVALID);
+ assert(!S_AXIL_RVALID);
+
+ assert(!M_AXI_AWVALID);
+ assert(!M_AXI_WVALID);
+ assert(!M_AXI_ARVALID);
+
+ assert(write_bursts_outstanding == 0);
+ assert(write_requests_remaining == 0);
+
+ assert(!phantom_read);
+ assert(!phantom_write);
+ assert(!r_busy);
+ assert(read_bursts_outstanding == 0);
+ assert(no_read_bursts_outstanding);
+
+ assert(r_len == 0);
+ assert(zero_len);
+
+ assert(write_count == 0);
+ assert(!M_AXI_WLAST);
+ assert(M_AXI_AWLEN == 0);
+ assert(!r_write_fifo);
+ assert(r_src_addr == 0);
+ assert(r_dst_addr == 0);
+ end
+
+ always @(*)
+ assert(ADDRLSB + LGMAXBURST <= 12);
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Formal contract checking
+ // {{{
+ // Given an arbitrary address within the source address range, and an
+ // arbitrary piece of data at that source address, prove that said
+ // piece of data will get properly written to the destination address
+ // range
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ // We'll pick the byte read from const_addr_src, and then written to
+ // const_addr_dst.
+ //
+ generate if (OPT_UNALIGNED)
+ begin : F_UNALIGNED_SAMPLE_CHECK
+ (* anyconst *) reg [C_AXI_ADDR_WIDTH-1:0] f_const_posn;
+ reg [C_AXI_ADDR_WIDTH:0] f_const_addr_src,
+ f_const_addr_dst;
+ reg [8-1:0] f_const_byte;
+ reg [C_AXI_ADDR_WIDTH:0] f_write_fifo_addr,
+ f_read_fifo_addr,
+ f_partial_out_addr;
+ reg [C_AXI_DATA_WIDTH-1:0] f_shifted_read, f_shifted_write;
+ reg [C_AXI_DATA_WIDTH/8-1:0] f_shifted_wstrb;
+ reg [C_AXI_DATA_WIDTH-1:0] f_shifted_to_fifo,
+ f_shifted_partial_to_fifo,
+ f_shifted_partial_from_fifo;
+ reg [C_AXI_DATA_WIDTH-1:0] f_shifted_from_fifo,
+ f_shifted_from_partial_out;
+ reg [ADDRLSB-1:0] subshift;
+
+
+ always @(*)
+ begin
+ assume(f_const_posn < f_length);
+
+ f_const_addr_src = f_src_addr + f_const_posn;
+ f_const_addr_dst = f_dst_addr + f_const_posn;
+
+ f_shifted_read =(M_AXI_RDATA >> (8*f_const_addr_src[ADDRLSB-1:0]));
+ f_shifted_write=(M_AXI_WDATA >> (8*f_const_addr_dst[ADDRLSB-1:0]));
+ f_shifted_wstrb=(M_AXI_WSTRB >> (f_const_addr_dst[ADDRLSB-1:0]));
+ end
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // Step 1: Assume a known input
+ // Actually, we'll copy it when it comes in
+ //
+ always @(posedge S_AXI_ACLK)
+ if (M_AXI_RVALID
+ && f_read_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ == f_const_addr_src[C_AXI_ADDR_WIDTH:ADDRLSB])
+ begin
+ // Record our byte to be read
+ f_const_byte <= f_shifted_read[7:0];
+ end
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // Step 2: Assert that value gets written on the way out
+ //
+ always @(*)
+ if (M_AXI_WVALID
+ && f_write_beat_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ == f_const_addr_dst[C_AXI_ADDR_WIDTH:ADDRLSB])
+ begin
+ // Assert that we have the right byte in the end
+ if (!r_err && !r_abort)
+ begin
+ // Although it only really matters if we are
+ // actually writing it to the bus
+ assert(f_shifted_wstrb[0]);
+ assert(f_shifted_write[7:0] == f_const_byte);
+ end else
+ assert(f_shifted_wstrb[0] || M_AXI_WSTRB==0);
+ end
+
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // Assert the write side of the realignment FIFO
+ //
+ always @(*)
+ begin
+ //
+ // ...
+ //
+
+ subshift = f_const_posn[ADDRLSB-1:0];
+ end
+
+ always @(*)
+ f_shifted_to_fifo = REALIGNMENT_FIFO.r_realigned_incoming
+ >> (8*subshift);
+
+ always @(*)
+ f_shifted_partial_to_fifo = REALIGNMENT_FIFO.r_partial_inword
+ >> (8*subshift);
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (S_AXI_ARESETN && r_write_fifo
+ && f_write_fifo_addr <= f_const_addr_src
+ && f_write_fifo_addr + (1<<ADDRLSB) > f_const_addr_src)
+ begin
+ // Assert that our special byte gets written to the FIFO
+ assert(f_const_byte == f_shifted_to_fifo[7:0]);
+ end
+
+ ////////////////////////////////////////////////////////////////
+ //
+ // Assert the read side of the realignment FIFO
+ //
+ always @(*)
+ begin
+ f_read_fifo_addr =f_dst_addr;
+ f_read_fifo_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ = f_dst_addr[C_AXI_ADDR_WIDTH:ADDRLSB]
+ + (r_partial_outvalid ? 1:0)
+ + f_writes_complete;
+
+ f_partial_out_addr = f_read_fifo_addr;
+ f_partial_out_addr[ADDRLSB-1:0] = 0;
+ end
+
+ always @(*)
+ f_shifted_from_fifo = REALIGNMENT_FIFO.fifo_data
+ >> (8*subshift);
+
+ always @(*)
+ f_shifted_from_partial_out
+ = REALIGNMENT_FIFO.r_partial_outword
+ >> (8*f_const_addr_dst[ADDRLSB-1:0]);
+
+
+ always @(*)
+ if (!fifo_empty && f_read_fifo_addr <= f_const_addr_dst
+ && f_read_fifo_addr + (1<<ADDRLSB) > f_const_addr_dst)
+ begin
+ // Assume that our special byte gets read from the FIFO
+ // That way we don't have to verify every element of the
+ // FIFO. We'll instead rely upon the FIFO working from
+ // here.
+ assume(f_const_byte == f_shifted_from_fifo[7:0]);
+ end
+
+ //
+ // ...
+ //
+
+ end endgenerate
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover checks
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ reg [3:0] f_cvr_rd_bursts, f_cvr_wr_bursts;
+ reg f_cvr_complete;
+
+ always @(posedge S_AXI_ACLK)
+ if (i_reset)
+ f_cvr_wr_bursts <= 0;
+ else if (w_start)
+ f_cvr_wr_bursts <= 0;
+ else if (M_AXI_AWVALID && M_AXI_AWREADY && !f_cvr_wr_bursts[3])
+ f_cvr_wr_bursts <= f_cvr_wr_bursts + 1;
+
+ always @(posedge S_AXI_ACLK)
+ if (i_reset)
+ f_cvr_rd_bursts <= 0;
+ else if (w_start)
+ f_cvr_rd_bursts <= 0;
+ else if (M_AXI_ARVALID && M_AXI_ARREADY && !f_cvr_rd_bursts[3])
+ f_cvr_rd_bursts <= f_cvr_rd_bursts + 1;
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+ cover(!r_busy && !r_err && !r_abort && f_cvr_wr_bursts[0]
+ && f_cvr_rd_bursts[0]);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+ cover(r_done && !r_err && !r_abort && f_cvr_wr_bursts[0]
+ && f_cvr_rd_bursts[0]);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+ cover(!r_busy && !r_err && !r_abort && &f_cvr_wr_bursts[1]
+ && f_cvr_rd_bursts[1]);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+ cover(!r_busy && !r_err && !r_abort && (&f_cvr_wr_bursts[1:0])
+ && (&f_cvr_rd_bursts[1:0]));
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy))
+ cover(!r_busy && !r_err && !r_abort && f_cvr_wr_bursts[2]
+ && f_cvr_rd_bursts[2]);
+
+ always @(*)
+ cover(f_past_valid && S_AXI_ARESETN && r_busy && r_err);
+
+ always @(*)
+ cover(f_past_valid && S_AXI_ARESETN && r_busy
+ && M_AXI_RVALID && M_AXI_RRESP[1]);
+
+ always @(*)
+ cover(f_past_valid && S_AXI_ARESETN && r_busy
+ && M_AXI_RVALID && M_AXI_BRESP[1]);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy && r_err))
+ cover(!r_busy && r_err);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && $past(S_AXI_ARESETN && r_busy && r_abort))
+ cover(!r_busy && r_abort);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && r_busy && !r_abort && !r_err)
+ cover(reads_remaining_w == 0);
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && r_busy && !r_abort && !r_err)
+ cover(reads_remaining_w == 0 && fifo_empty);
+
+ generate if (OPT_UNALIGNED)
+ begin : COVER_MISALIGNED_COPYING
+
+ reg [2:0] cvr_opt_checks;
+ integer ik;
+
+ always @(*)
+ begin
+ cvr_opt_checks[0] = (f_src_addr[ADDRLSB-1:0] == 0);
+ cvr_opt_checks[1] = (f_dst_addr[ADDRLSB-1:0] == 0);
+ cvr_opt_checks[2] = (f_length[ ADDRLSB-1:0] == 0);
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && S_AXI_ARESETN && o_int)
+ begin
+ for(ik=0; ik<8; ik=ik+1)
+ begin
+ cover(cvr_opt_checks == ik[2:0]
+ && !r_busy && r_err && !r_abort
+ && f_cvr_wr_bursts[0]
+ && f_cvr_rd_bursts[0]);
+
+ cover(cvr_opt_checks == ik[2:0]
+ && !r_busy && !r_err && r_abort
+ && f_cvr_wr_bursts[0]
+ && f_cvr_rd_bursts[0]);
+
+ cover(cvr_opt_checks == ik[2:0]
+ && !r_busy && !r_err && !r_abort
+ && f_cvr_wr_bursts[0]
+ && f_cvr_rd_bursts[0]);
+
+ cover(cvr_opt_checks == ik[2:0]
+ && !r_busy && !r_err && !r_abort
+ && f_cvr_wr_bursts[2]
+ && f_cvr_rd_bursts[2]);
+ end
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && S_AXI_ARESETN && o_int)
+ begin
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && f_extra_realignment_read
+ && f_extra_realignment_write);
+
+ //
+ // Will never happen--since f_extra_realignment_read
+ // can only be true if f_extra_realignment_preread
+ // is also true
+ //
+ // cover(!r_busy && !r_err && !r_abort
+ // && !f_extra_realignment_preread
+ // && f_extra_realignment_read
+ // && f_extra_realignment_write);
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && f_extra_realignment_write);
+
+ cover(!r_busy && !r_err && !r_abort
+ && !f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && f_extra_realignment_write);
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && f_extra_realignment_read
+ && !f_extra_realignment_write);
+
+ // !preread && read will never happen
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && !f_extra_realignment_write);
+
+ cover(!r_busy && !r_err && !r_abort
+ && !f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && !f_extra_realignment_write);
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && f_extra_realignment_read
+ && f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+
+ // !preread && read will never happen
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+
+ cover(!r_busy && !r_err && !r_abort
+ && !f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && f_extra_realignment_read
+ && !f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+
+
+ // !preread && read will never happen
+
+ cover(!r_busy && !r_err && !r_abort
+ && f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && !f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+
+ cover(!r_busy && !r_err && !r_abort
+ && !f_extra_realignment_preread
+ && !f_extra_realignment_read
+ && !f_extra_realignment_write
+ && f_length[LGLEN-1:ADDRLSB] > 2);
+ end
+
+ end endgenerate
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Careless assumptions (i.e. constraints)
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // None (currently)
+`endif
+// }}}
+endmodule