summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axispacker.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axispacker.v')
-rw-r--r--rtl/wb2axip/axispacker.v890
1 files changed, 890 insertions, 0 deletions
diff --git a/rtl/wb2axip/axispacker.v b/rtl/wb2axip/axispacker.v
new file mode 100644
index 0000000..74b8f5b
--- /dev/null
+++ b/rtl/wb2axip/axispacker.v
@@ -0,0 +1,890 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axispacker
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: AXI-Stream packer: This uses TKEEP to pack bytes in a stream.
+// Bytes with TKEEP clear on input will be removed from the
+// output stream.
+//
+// TID, TDEST, and TUSER fields are not (currently) implemented, although
+// they shouldn't be too hard to add back in.
+//
+// This design *ASSUMES* that TLAST will only be set if TKEEP is not zero.
+// This assumption is not required by the AXI-stream specification, and
+// should be removed in the future.
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2021-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 axispacker #(
+ parameter C_AXIS_DATA_WIDTH = 32,
+ parameter [0:0] OPT_LOWPOWER = 1
+ ) (
+ // {{{
+ input wire S_AXI_ACLK, S_AXI_ARESETN,
+ // Incoming slave interface
+ // {{{
+ input wire S_AXIS_TVALID,
+ output wire S_AXIS_TREADY,
+ input wire [C_AXIS_DATA_WIDTH-1:0] S_AXIS_TDATA,
+ input wire [C_AXIS_DATA_WIDTH/8-1:0] S_AXIS_TSTRB,
+ input wire [C_AXIS_DATA_WIDTH/8-1:0] S_AXIS_TKEEP,
+ input wire S_AXIS_TLAST,
+ // }}}
+ // Outgoing AXI-Stream master interface
+ // {{{
+ output reg M_AXIS_TVALID,
+ input wire M_AXIS_TREADY,
+ output reg [C_AXIS_DATA_WIDTH-1:0] M_AXIS_TDATA,
+ output reg [C_AXIS_DATA_WIDTH/8-1:0] M_AXIS_TSTRB,
+ output reg [C_AXIS_DATA_WIDTH/8-1:0] M_AXIS_TKEEP,
+ output reg M_AXIS_TLAST
+ // }}}
+ // }}}
+ );
+
+ // Local declarations
+ // {{{
+ localparam DW = C_AXIS_DATA_WIDTH;
+
+ wire pre_tvalid, pre_tready;
+ wire [DW-1:0] pre_tdata;
+ wire [DW/8-1:0] pre_tstrb, pre_tkeep;
+ wire pre_tlast;
+
+ localparam MAX_COUNT = DW/8;
+ localparam COUNT_BITS = $clog2(MAX_COUNT+1)+1;
+
+ reg [DW-1:0] pck_tdata;
+ reg [DW/8-1:0] pck_tstrb, pck_tkeep;
+ reg pck_tlast;
+ reg [COUNT_BITS-1:0] pck_count;
+
+ reg axis_ready;
+
+ wire skd_valid;
+ wire [DW-1:0] skd_data;
+ wire [DW/8-1:0] skd_strb, skd_keep;
+ wire [COUNT_BITS-1:0] skd_count;
+ wire skd_last;
+
+ reg [COUNT_BITS-1:0] mid_fill;
+ reg [DW-1:0] mid_data;
+ reg [DW/8-1:0] mid_strb, mid_keep;
+ reg mid_last;
+
+ reg [2*DW-1:0] w_packed_data;
+ reg [2*DW/8-1:0] w_packed_strb, w_packed_keep;
+
+ localparam TRIM_MAX = MAX_COUNT[COUNT_BITS-1:0];
+ reg next_valid, next_last;
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Incoming skid buffer
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // This makes it so that we can control VALID && DATA (and so
+ // backpressure) with a combinatorial value, something that would
+ // otherwise be against protocol.
+ //
+
+`ifdef FORMAL
+ // {{{
+ assign pre_tvalid = S_AXIS_TVALID;
+ assign S_AXIS_TREADY = pre_tready;
+ assign pre_tdata = S_AXIS_TDATA;
+ assign pre_tstrb = S_AXIS_TSTRB;
+ assign pre_tkeep = S_AXIS_TKEEP;
+ assign pre_tlast = S_AXIS_TLAST;
+ // }}}
+`else
+ skidbuffer #(
+ // {{{
+ .DW(DW + DW/8 + DW/8 + 1),
+ .OPT_OUTREG(1'b1)
+ // }}}
+ ) slave_skd (
+ // {{{
+ .i_clk(S_AXI_ACLK),
+ .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIS_TVALID), .o_ready(S_AXIS_TREADY),
+ .i_data({ S_AXIS_TDATA, S_AXIS_TSTRB,
+ S_AXIS_TKEEP, S_AXIS_TLAST }),
+ .o_valid(pre_tvalid), .i_ready(pre_tready),
+ .o_data({ pre_tdata, pre_tstrb, pre_tkeep, pre_tlast })
+ // }}}
+ );
+`endif
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Beat packing stage
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(*)
+ begin
+ { pck_tdata, pck_tstrb, pck_tkeep }
+ = pack( pre_tdata, pre_tstrb,
+ (pre_tvalid) ? pre_tkeep : {(DW/8){1'b0}} );
+ pck_tlast = pre_tlast;
+ // Verilator lint_off WIDTH
+ pck_count = $countones(pre_tkeep);
+ // Verilator lint_on WIDTH
+ end
+
+`ifdef FORMAL
+ // {{{
+ assign skd_valid = pre_tvalid;
+ assign pre_tready = axis_ready;
+ assign skd_data = pck_tdata;
+ assign skd_strb = pck_tstrb;
+ assign skd_keep = pck_tkeep;
+ assign skd_last = pck_tlast;
+ assign skd_count= pck_count;
+ // }}}
+`else
+ skidbuffer #(
+ // {{{
+ .DW(DW + DW/8 + DW/8 + 1 + COUNT_BITS),
+ .OPT_OUTREG(1'b1)
+ // }}}
+ ) beat_skd (
+ // {{{
+ .i_clk(S_AXI_ACLK),
+ .i_reset(!S_AXI_ARESETN),
+ .i_valid(pre_tvalid), .o_ready(pre_tready),
+ .i_data({ pck_count, pck_tdata, pck_tstrb,
+ pck_tkeep, pck_tlast }),
+ .o_valid(skd_valid), .i_ready(axis_ready),
+ .o_data({ skd_count, skd_data, skd_strb, skd_keep,
+ skd_last })
+ // }}}
+ );
+`endif
+
+ function [DW+DW/8+DW/8-1:0] pack; // (i_data, i_strb, i_keep)
+ // {{{
+ input [DW-1:0] i_data;
+ input [DW/8-1:0] i_strb;
+ input [DW/8-1:0] i_keep;
+
+ reg [DW-1:0] p_data;
+ reg [DW/8-1:0] p_strb;
+ reg [DW/8-1:0] p_keep;
+
+ integer rounds, ik;
+ begin
+ p_data = i_data;
+ p_strb = i_strb;
+ p_keep = i_keep;
+ for(ik=0; ik < DW/8; ik=ik+1)
+ begin
+ if (!p_keep[ik])
+ begin
+ p_data[ik*8 +: 8]= 8'h00;
+ p_strb[ik] = 1'b0;
+ end
+ end
+ for(rounds = 0; rounds < DW/8; rounds = rounds+1)
+ begin
+ for(ik=0; ik < DW/8-1; ik=ik+1)
+ begin
+ if (!p_keep[ik])
+ begin
+ p_data[ik*8 +: 8]=p_data[(ik+1)*8 +: 8];
+ p_keep[ik] = p_keep[ik+1];
+ p_strb[ik] = p_strb[ik+1];
+
+ p_keep[ik+1] = 0;
+ p_data[(ik+1)*8 +: 8] = 0;
+ p_strb[ik+1] = 0;
+ end
+ end
+ end
+
+ pack = { p_data, p_strb, p_keep };
+/*
+ p_data = 0;
+ p_strb = 0;
+ p_keep = 0;
+
+ for(fill=0; fill<2*DW; fill=fill+1)
+ begin
+ p_data[(fill *8) +: 8] = i_data[fill*8 +: 8];
+ p_strb[ fill ] = i_strb[fill];
+ p_keep[ fill ] = i_keep[fill];
+ if (fill != 0)
+ p_keep[ fill ] = i_keep[fill]
+ && $countones(i_keep[((fill > 0)?(fill-1):0):0]) == fill;
+ for(ik=fill; ik<2*DW; ik=ik+1)
+ if (i_keep[ik] && $countones(i_keep[ik-1:0]) == fill)
+ begin
+ p_data[fill*8 +: 8] = i_data[ik*8 +: 8];
+ p_strb[fill ] = i_strb[ik];
+ p_keep[fill ] = i_keep[ik];
+ end
+
+ if (!p_keep[fill])
+ begin
+ p_strb[fill] = 1'b0;
+ if (OPT_LOWPOWER)
+ p_data[(fill *8) +: 8] = 8'h00;
+ end
+ end
+
+ pack = { p_data, p_strb, p_keep };
+*/
+ end endfunction
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Word Packing stage
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // axis_ready
+ // {{{
+ always @(*)
+ begin
+ axis_ready = 1;
+ if ((mid_last || (skd_count + mid_fill >= TRIM_MAX))
+ &&(M_AXIS_TVALID && !M_AXIS_TREADY))
+ axis_ready = 0;
+ if (!skd_valid)
+ axis_ready = 0;
+ end
+ // }}}
+
+ // mid_fill
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ mid_fill <= 0;
+ else if (mid_last && (!M_AXIS_TVALID || M_AXIS_TREADY))
+ mid_fill <= (axis_ready) ? skd_count : 0;
+ else if (skd_valid && skd_last && (!M_AXIS_TVALID || M_AXIS_TREADY))
+ mid_fill <= (skd_count + mid_fill <= TRIM_MAX) ? 0 : skd_count + mid_fill - TRIM_MAX;
+ else
+ mid_fill <= mid_fill + (axis_ready ? skd_count : 0)
+ - ((next_valid && (!M_AXIS_TVALID || M_AXIS_TREADY))
+ ? TRIM_MAX : 0);
+ // }}}
+
+ // mid_last
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ mid_last <= 0;
+ else if (axis_ready)
+ begin
+ mid_last <= !next_last || (M_AXIS_TVALID && !M_AXIS_TREADY);
+ if (mid_last)
+ mid_last <= 1'b1;
+ if (!skd_last)
+ mid_last <= 1'b0;
+ end else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+ mid_last <= 0;
+ // }}}
+
+ // mid_data, mid_strb, mid_keep
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ mid_data <= 0;
+ mid_strb <= 0;
+ mid_keep <= 0;
+ end else if (mid_last && (!M_AXIS_TVALID || M_AXIS_TREADY))
+ begin
+ mid_data <= (axis_ready) ? skd_data : 0;
+ mid_strb <= (axis_ready) ? skd_strb : 0;
+ mid_keep <= (axis_ready) ? skd_keep : 0;
+ end else if (skd_valid && skd_last && (!M_AXIS_TVALID || M_AXIS_TREADY))
+ begin
+ if (skd_count + mid_fill <= TRIM_MAX)
+ begin
+ mid_data <= 0;
+ mid_strb <= 0;
+ mid_keep <= 0;
+ end else begin
+ mid_data <= w_packed_data[2*DW-1:DW];
+ mid_strb <= w_packed_strb[2*DW/8-1:DW/8];
+ mid_keep <= w_packed_keep[2*DW/8-1:DW/8];
+ end
+ end else if (axis_ready)
+ begin
+ if (mid_fill + skd_count >= TRIM_MAX)
+ begin
+ mid_data <= w_packed_data[2*DW-1:DW];
+ mid_strb <= w_packed_strb[2*DW/8-1:DW/8];
+ mid_keep <= w_packed_keep[2*DW/8-1:DW/8];
+ end else begin
+ mid_data <= w_packed_data[DW-1:0];
+ mid_strb <= w_packed_strb[DW/8-1:0];
+ mid_keep <= w_packed_keep[DW/8-1:0];
+ end
+ end
+ // }}}
+
+ // w_packed_data, w_packed_strb, w_packed_keep
+ // {{{
+ always @(*)
+ begin
+ w_packed_data = 0;
+ w_packed_strb = 0;
+
+ w_packed_data = { {(DW){1'b0}}, mid_data }
+ | ( { {(DW){1'b0}}, skd_data } << (mid_fill * 8));
+ w_packed_strb = { {(DW/8){1'b0}}, mid_strb }
+ | ( { {(DW/8){1'b0}}, skd_strb } << (mid_fill));
+ w_packed_keep = { {(DW/8){1'b0}}, mid_keep }
+ | ( { {(DW/8){1'b0}}, skd_keep } << (mid_fill));
+ end
+ // }}}
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Outputs
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // next_valid
+ // {{{
+ always @(*)
+ begin
+ next_valid = skd_valid && (skd_count + mid_fill >= TRIM_MAX);
+ if (mid_last || (skd_last && skd_valid))
+ next_valid = 1;
+ if (skd_count + mid_fill == 0)
+ next_valid = 0;
+ end
+ // }}}
+
+ // next_last
+ // {{{
+ always @(*)
+ begin
+ next_last = mid_last;
+ if (skd_valid && skd_last && (skd_count + mid_fill <= TRIM_MAX))
+ next_last = 1;
+ if (!next_valid)
+ next_last = 0;
+ end
+ // }}}
+
+ // M_AXIS_TVALID
+ // {{{
+ initial M_AXIS_TVALID = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ M_AXIS_TVALID <= 0;
+ else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+ M_AXIS_TVALID <= next_valid;
+ // }}}
+
+ // M_AXIS_TDATA, M_AXIS_TSTRB, M_AXIS_TKEEP, M_AXIS_TLAST
+ // {{{
+ initial M_AXIS_TDATA = 0;
+ initial M_AXIS_TSTRB = 0;
+ initial M_AXIS_TKEEP = 0;
+ initial M_AXIS_TLAST = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ M_AXIS_TDATA <= 0;
+ M_AXIS_TSTRB <= 0;
+ M_AXIS_TKEEP <= 0;
+ M_AXIS_TLAST <= 0;
+ end else if (!M_AXIS_TVALID || M_AXIS_TREADY)
+ begin
+ if (mid_last)
+ begin
+ M_AXIS_TDATA <= mid_data;
+ M_AXIS_TSTRB <= mid_strb;
+ M_AXIS_TKEEP <= mid_keep;
+ M_AXIS_TLAST <= 1'b1;
+ end else begin
+ M_AXIS_TDATA <= w_packed_data[DW-1:0];
+ M_AXIS_TSTRB <= w_packed_strb[DW/8-1:0];
+ M_AXIS_TKEEP <= w_packed_keep[DW/8-1:0];
+ M_AXIS_TLAST <= next_last;
+ end
+
+
+ if (OPT_LOWPOWER && !next_valid)
+ begin
+ M_AXIS_TDATA <= 0;
+ M_AXIS_TSTRB <= 0;
+ M_AXIS_TKEEP <= 0;
+ M_AXIS_TLAST <= 0;
+ end
+ end
+ // }}}
+
+ // }}}
+ // Keep Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0 };
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ reg f_past_valid;
+ localparam F_COUNT = COUNT_BITS + 4 + 16;
+ reg [F_COUNT-1:0] f_icount, f_ocount, f_ibeat, f_obeat,
+ f_mcount, f_mbeat;
+
+ initial f_past_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ f_past_valid <= 1;
+
+ always @(*)
+ if (!f_past_valid)
+ assume(!S_AXI_ARESETN);
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Incoming stream assumptions
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(posedge S_AXI_ACLK)
+ if (!f_past_valid || $past(!S_AXI_ARESETN))
+ begin
+ assume(!S_AXIS_TVALID);
+ end else if ($past(S_AXIS_TVALID && !S_AXIS_TREADY))
+ begin
+ assume(S_AXIS_TVALID);
+ assume($stable(S_AXIS_TDATA));
+ assume($stable(S_AXIS_TSTRB));
+ assume($stable(S_AXIS_TKEEP));
+ assume($stable(S_AXIS_TLAST));
+ end
+
+ // If TKEEP is low, TSTRB must be low as well
+ always @(*)
+ if (S_AXI_ARESETN)
+ assume(((~S_AXIS_TKEEP) & S_AXIS_TSTRB) == 0);
+
+ // TLAST requires at least one beat
+ always @(*)
+ if (S_AXI_ARESETN && S_AXIS_TVALID && S_AXIS_TLAST)
+ assume(S_AXIS_TKEEP != 0);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Outgoing stream assertions
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(posedge S_AXI_ACLK)
+ if (!f_past_valid || $past(!S_AXI_ARESETN))
+ begin
+ assert(!M_AXIS_TVALID);
+ end else if ($past(S_AXIS_TVALID && !S_AXIS_TREADY))
+ begin
+ assert(M_AXIS_TVALID);
+ assert($stable(M_AXIS_TDATA));
+ assert($stable(M_AXIS_TSTRB));
+ assert($stable(M_AXIS_TKEEP));
+ assert($stable(M_AXIS_TLAST));
+ end
+
+ // If TKEEP is low, TSTRB must be low as well
+ always @(*)
+ if (S_AXI_ARESETN && M_AXIS_TVALID)
+ assert(((~M_AXIS_TKEEP) & M_AXIS_TSTRB) == 0);
+
+ // Our output requirement is that if TLAST is ever low, TKEEP must
+ // be all ones
+ always @(*)
+ if (S_AXI_ARESETN && M_AXIS_TVALID && !M_AXIS_TLAST)
+ assert(&M_AXIS_TKEEP);
+
+ always @(*)
+ if (S_AXI_ARESETN && OPT_LOWPOWER && !M_AXIS_TVALID)
+ begin
+ assert(M_AXIS_TDATA == 0);
+ assert(M_AXIS_TSTRB == 0);
+ assert(M_AXIS_TKEEP == 0);
+ assert(M_AXIS_TLAST == 0);
+ end
+
+ // TLAST requires at least one beat
+ always @(*)
+ if (S_AXI_ARESETN && M_AXIS_TVALID && M_AXIS_TLAST)
+ assert(M_AXIS_TKEEP != 0);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Induction assertions for the middle
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ genvar gk;
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(mid_fill == { 1'b0, $countones(mid_keep) });
+
+ always @(*)
+ if (S_AXI_ARESETN && mid_last)
+ assert(mid_fill > 0);
+
+ // If TKEEP is low, TSTRB must be low as well
+ always @(*)
+ if (S_AXI_ARESETN)
+ begin
+ if (mid_fill > 0)
+ begin
+ assert(((~mid_keep) & mid_strb) == 0);
+ end else begin
+ // assert(mid_data == 0);
+ assert(mid_strb == 0);
+ end
+ end
+
+ // Our output requirement is that if TLAST is ever low, TKEEP must
+ // be all ones
+ generate for(gk=1; gk<DW/8; gk=gk+1)
+ begin
+ always @(*)
+ if (S_AXI_ARESETN && mid_fill > 0 && mid_keep[gk])
+ assert(&mid_keep[gk-1:0]);
+ end endgenerate
+
+ always @(*)
+ if (S_AXI_ARESETN && OPT_LOWPOWER && !M_AXIS_TVALID)
+ begin
+ assert(M_AXIS_TDATA == 0);
+ assert(M_AXIS_TSTRB == 0);
+ assert(M_AXIS_TKEEP == 0);
+ assert(M_AXIS_TLAST == 0);
+ end
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Contract properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // Pick a byte of the given packet. Force that byte to have a known
+ // value. Prove that the same byte on the output has the same known
+ // value.
+
+ (* anyconst *) reg [F_COUNT-1:0] fc_count;
+ (* anyconst *) reg [8-1:0] fc_data;
+ (* anyconst *) reg fc_strb, fc_last;
+ wire [F_COUNT:0] f_chk_count;
+
+ // Assume the special input
+ // {{{
+ generate for(gk=0; gk<DW/8; gk=gk+1)
+ begin
+ if (gk == 0)
+ begin
+ always @(*)
+ if (S_AXIS_TVALID && S_AXIS_TKEEP[0]
+ && f_icount == fc_count)
+ begin
+ assume(fc_data == S_AXIS_TDATA[7:0]);
+ assume(fc_strb == S_AXIS_TSTRB[0]);
+ if (fc_last)
+ begin
+ assume(S_AXIS_TKEEP[DW/8-1:1] == 0);
+ assume(S_AXIS_TLAST);
+ end else if (S_AXIS_TLAST)
+ assume(S_AXIS_TKEEP[DW/8-1:1] != 0);
+ end
+ end else begin
+
+ always @(*)
+ if (S_AXIS_TKEEP[gk] && (f_icount
+ // Verilator lint_off WIDTH
+ + $countones(S_AXIS_TKEEP[gk-1:0]) == fc_count))
+ // Verilator lint_on WIDTH
+ begin
+ assume(S_AXIS_TDATA[gk*8 +: 8] == fc_data);
+ assume(S_AXIS_TSTRB[gk] == fc_strb);
+ if (fc_last)
+ begin
+ if (gk < DW/8-1)
+ assume(S_AXIS_TKEEP[DW/8-1:gk+1] == 0);
+ assume(S_AXIS_TLAST);
+ end else if (gk < DW/8-1)
+ begin
+ if (S_AXIS_TLAST)
+ assume(S_AXIS_TKEEP[DW/8-1:gk+1] != 0);
+ end else
+ assume(!S_AXIS_TLAST);
+ end
+ end
+ end endgenerate
+ // }}}
+
+ // Assert the special output
+ // {{{
+ generate for(gk=0; gk<DW/8; gk=gk+1)
+ begin
+ if (gk == 0)
+ begin
+ always @(*)
+ if (S_AXI_ARESETN && M_AXIS_TVALID && M_AXIS_TKEEP[0]
+ && f_ocount == fc_count)
+ begin
+ assert(M_AXIS_TDATA[7:0] == fc_data);
+ assert(M_AXIS_TSTRB[0] == fc_strb);
+ if (fc_last)
+ begin
+ assert(M_AXIS_TKEEP[DW/8-1:1] == 0);
+ assert(M_AXIS_TLAST);
+ end else if (M_AXIS_TLAST)
+ assert(M_AXIS_TKEEP[DW/8-1:1] != 0);
+ end
+ end else begin
+
+ always @(*)
+ if (S_AXI_ARESETN && M_AXIS_TKEEP[gk] &&
+ // Verilator lint_off WIDTH
+ (f_ocount + $countones(M_AXIS_TKEEP[gk-1:0])
+ == fc_count))
+ // Verilator lint_on WIDTH
+ begin
+ assert(M_AXIS_TDATA[gk*8 +: 8] == fc_data);
+ assert(M_AXIS_TSTRB[gk] == fc_strb);
+ if (fc_last)
+ begin
+ if (gk < DW/8-1)
+ assert(M_AXIS_TKEEP[DW/8-1:gk+1] == 0);
+ assert(M_AXIS_TLAST);
+ end else if (gk < DW/8-1)
+ begin
+ if (M_AXIS_TLAST)
+ assert(M_AXIS_TKEEP[DW/8-1:gk+1] != 0);
+ end else
+ assert(!M_AXIS_TLAST);
+ end
+ end
+ end endgenerate
+ // }}}
+
+ // f_icount
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_icount <= 0;
+ else if (S_AXIS_TVALID && S_AXIS_TREADY)
+ // Verilator lint_off WIDTH
+ f_icount <= f_icount + $countones(S_AXIS_TKEEP);
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // f_ocount
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_ocount <= 0;
+ else if (M_AXIS_TVALID && M_AXIS_TREADY)
+ // Verilator lint_off WIDTH
+ f_ocount <= f_ocount + $countones(M_AXIS_TKEEP);
+ // Verilator lint_on WIDTH
+ // }}}
+
+ // Induction assertion(s) on mid_*
+ // {{{
+ always @(*)
+ // Verilator lint_off WIDTH
+ f_mcount = f_icount - mid_fill;
+ // Verilator lint_on WIDTH
+
+ generate for(gk=0; gk<DW/8; gk=gk+1)
+ begin
+ if (gk == 0)
+ begin
+ always @(*)
+ if (S_AXI_ARESETN && mid_fill > 0
+ && f_mcount == fc_count)
+ begin
+ assert(mid_data[7:0] == fc_data);
+ assert(mid_strb[0] == fc_strb);
+ assert(mid_keep[0]);
+ if (fc_last)
+ begin
+ assert(mid_fill == 1);
+ assert(mid_last);
+ end else if (mid_last)
+ assert(mid_fill > 1);
+ end else if (S_AXI_ARESETN && mid_fill == 0)
+ begin
+ assert(mid_data[7:0] == 8'h00);
+ assert(!mid_strb[0]);
+ assert(!mid_keep[0]);
+ end
+ end else begin
+
+ always @(*)
+ if (S_AXI_ARESETN && mid_fill > gk
+ && (f_mcount + gk == fc_count))
+ begin
+ assert(mid_data[gk*8 +: 8] == fc_data);
+ assert(mid_strb[gk] == fc_strb);
+ assert(mid_keep[gk]);
+ if (fc_last)
+ begin
+ assert(mid_fill == gk + 1);
+ assert(mid_last);
+ end else if (gk < DW/8-1)
+ begin
+ if (mid_last)
+ assert(mid_fill > gk + 1);
+ end else
+ assert(!mid_last);
+ end else if (S_AXI_ARESETN && mid_fill <= gk)
+ begin
+ assert(mid_data[gk*8 +: 8] == 8'h00);
+ assert(!mid_strb[gk]);
+ assert(!mid_keep[gk]);
+ end
+ end
+ end endgenerate
+ // }}}
+
+ // Relate icount to ocount
+ // {{{
+ // Verilator lint_off WIDTH
+ assign f_chk_count = f_ocount + mid_fill + $countones(M_AXIS_TKEEP);
+ // Verilator lint_on WIDTH
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ begin
+ assume(f_chk_count[F_COUNT] == 1'b0);
+ assert(f_icount == f_chk_count[F_COUNT-1:0]);
+ end
+ // }}}
+
+ // f_ibeat
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_ibeat <= 0;
+ else if (S_AXIS_TVALID && S_AXIS_TREADY)
+ begin
+ // Verilator lint_off WIDTH
+ f_ibeat <= f_ibeat + $countones(S_AXIS_TKEEP);
+ // Verilator lint_on WIDTH
+ if (M_AXIS_TLAST)
+ f_ibeat <= 0;
+ end
+ // }}}
+
+ // f_obeat
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_obeat <= 0;
+ else if (M_AXIS_TVALID && M_AXIS_TREADY)
+ begin
+ // Verilator lint_off WIDTH
+ f_obeat <= f_obeat + $countones(M_AXIS_TKEEP);
+ // Verilator lint_on WIDTH
+ if (M_AXIS_TLAST)
+ f_obeat <= 0;
+ end
+ // }}}
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover checks
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+ cover(M_AXIS_TVALID && M_AXIS_TREADY && M_AXIS_TLAST
+ && $past(M_AXIS_TVALID&& M_AXIS_TREADY&& M_AXIS_TLAST));
+
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+ cover(M_AXIS_TVALID && !M_AXIS_TLAST
+ && $past(M_AXIS_TVALID&& M_AXIS_TREADY&& M_AXIS_TLAST));
+
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_ARESETN && $past(S_AXI_ARESETN))
+ cover(M_AXIS_TVALID && M_AXIS_TLAST
+ && $past(M_AXIS_TVALID&& M_AXIS_TREADY&&!M_AXIS_TLAST));
+
+ // }}}
+
+ // Keep Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused_formal;
+ assign unused_formal = &{ 1'b0, f_ibeat, f_obeat, f_icount, f_ocount };
+ // Verilator lint_on UNUSED
+ // }}}
+`endif // FORMAL
+// }}}
+endmodule