summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/wbxclk.v
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
committerAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
commit3038edc09a2eb15762f2e58533f429489107520b (patch)
treef7a45e424d39e6fef0d59e329c1bf6ea206e2886 /rtl/wb2axip/wbxclk.v
parent3b62399f92e9faa2602ac30865e5fc3c7c4e12b8 (diff)
rtl/wb2axip: add to version control
Diffstat (limited to '')
-rw-r--r--rtl/wb2axip/wbxclk.v854
1 files changed, 854 insertions, 0 deletions
diff --git a/rtl/wb2axip/wbxclk.v b/rtl/wb2axip/wbxclk.v
new file mode 100644
index 0000000..5f404b0
--- /dev/null
+++ b/rtl/wb2axip/wbxclk.v
@@ -0,0 +1,854 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: rtl/wbxclk.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: To cross clock domains with a (pipelined) wishbone bus.
+//
+// Challenges:
+// 1. Wishbone has no capacity for back pressure. That means that we'll
+// need to be careful not to issue more STB requests than ACKs
+// that will fit in the return buffer.
+//
+// Imagine, for example, a faster return clock but a slave that needs
+// many clocks to get going. During that time, many requests
+// might be issued. If they all suddenly get returned at once,
+// flooding the return ACK FIFO, then we have a problem.
+//
+// 2. Bus aborts. If we ever have to abort a transaction, that's going
+// to be a pain. The FIFOs will need to be reset and the
+// downstream CYC line dropped. This needs to be done
+// synchronously in both domains, but there's no real choice but
+// to make the crossing asynchronous.
+//
+// 3. Synchronous CYC. Lowering CYC is a normal part of the protocol, as
+// is raising CYC. CYC is used as a bus locking scheme, so we'll
+// need to know when it is (properly) lowered downstream. This
+// can be done by passing a synchronous CYC drop request through
+// the pipeline in addition to the bus aborts above.
+//
+// Status:
+// Formally verified against a set of bus properties, not yet
+// used in any real or simulated designs
+//
+// 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
+// }}}
+module wbxclk #(
+ // {{{
+ parameter AW=32,
+ DW=32,
+ LGFIFO = 5
+ // }}}
+ ) (
+ // {{{
+ input wire i_wb_clk, i_reset,
+ // Input/master bus
+ input wire i_wb_cyc, i_wb_stb, i_wb_we,
+ input wire [(AW-1):0] i_wb_addr,
+ input wire [(DW-1):0] i_wb_data,
+ input wire [(DW/8-1):0] i_wb_sel,
+ output wire o_wb_stall,
+ output reg o_wb_ack,
+ output reg [(DW-1):0] o_wb_data,
+ output reg o_wb_err,
+ // Delayed bus
+ input wire i_xclk_clk,
+ output reg o_xclk_cyc,
+ output reg o_xclk_stb,
+ output reg o_xclk_we,
+ output reg [(AW-1):0] o_xclk_addr,
+ output reg [(DW-1):0] o_xclk_data,
+ output reg [(DW/8-1):0] o_xclk_sel,
+ input wire i_xclk_stall,
+ input wire i_xclk_ack,
+ input wire [(DW-1):0] i_xclk_data,
+ input wire i_xclk_err
+ // }}}
+ );
+
+ //
+ // Declare our signals
+ // {{{
+ localparam NFF = 2;
+ reg wb_active;
+ reg [NFF-2:0] bus_abort_pipe;
+ reg [LGFIFO:0] acks_outstanding;
+ reg ackfifo_single, ackfifo_empty, ackfifo_full;
+ wire ack_stb, err_stb;
+ wire [DW-1:0] ret_wb_data;
+ wire req_fifo_stall, no_returns;
+ //
+ // Verilator lint_off SYNCASYNCNET
+ reg bus_abort;
+ // Verilator lint_on SYNCASYNCNET
+ //
+ wire req_stb, req_fifo_empty;
+ reg xclk_err_state, ign_ackfifo_stall;
+ reg xck_reset;
+ reg [NFF-2:0] xck_reset_pipe;
+ wire req_we;
+ wire [AW-1:0] req_addr;
+ wire [DW-1:0] req_data;
+ wire [DW/8-1:0] req_sel;
+`ifdef FORMAL
+ wire [LGFIFO:0] ackfifo_prefill, reqfifo_prefill;
+`endif
+ // }}}
+
+ //
+ //
+ // On the original wishbone clock ...
+ //
+ // FIFO/queue up our requests
+ // {{{
+ initial wb_active = 1'b0;
+ always @(posedge i_wb_clk)
+ if (i_reset || !i_wb_cyc)
+ wb_active <= 1'b0;
+ else if (i_wb_stb && !o_wb_stall)
+ wb_active <= 1'b1;
+
+ initial { bus_abort, bus_abort_pipe } = -1;
+ always @(posedge i_wb_clk)
+ if (i_reset)
+ { bus_abort, bus_abort_pipe } <= -1;
+ else if (!i_wb_cyc && (!ackfifo_empty))
+ { bus_abort, bus_abort_pipe } <= -1;
+ else if (o_wb_err)
+ { bus_abort, bus_abort_pipe } <= -1;
+ else if (ackfifo_empty)
+ { bus_abort, bus_abort_pipe } <= { bus_abort_pipe, 1'b0 };
+`ifdef FORMAL
+ always @(*)
+ if (bus_abort_pipe)
+ assert(bus_abort);
+`endif
+ // }}}
+
+ //
+ // The request FIFO itself
+ // {{{
+ afifo #(
+`ifdef FORMAL
+ .OPT_REGISTER_READS(0),
+ .F_OPT_DATA_STB(1'b0),
+`endif
+ .NFF(NFF), .LGFIFO(LGFIFO),
+ .WIDTH(2+AW+DW+(DW/8))
+ ) reqfifo(.i_wclk(i_wb_clk), .i_wr_reset_n(!bus_abort),
+ .i_wr((i_wb_stb&&!o_wb_stall) || (wb_active && !i_wb_cyc)),
+ .i_wr_data({ i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel }),
+ .o_wr_full(req_fifo_stall),
+ //
+ .i_rclk(i_xclk_clk), .i_rd_reset_n(!xck_reset),
+ .i_rd(!o_xclk_stb || !i_xclk_stall),
+ .o_rd_data({ req_stb, req_we, req_addr, req_data, req_sel }),
+ .o_rd_empty(req_fifo_empty)
+`ifdef FORMAL
+ , .f_fill(reqfifo_prefill)
+`endif
+ );
+ // }}}
+
+ //
+ // Downstream bus--issuing requests
+ // {{{
+ initial { xck_reset, xck_reset_pipe } = -1;
+ always @(posedge i_xclk_clk or posedge bus_abort)
+ if (bus_abort)
+ { xck_reset, xck_reset_pipe } <= -1;
+ else
+ { xck_reset, xck_reset_pipe } <= { xck_reset_pipe, 1'b0 };
+`ifdef FORMAL
+ always @(*)
+ if (xck_reset_pipe)
+ assert(xck_reset);
+`endif
+
+ initial xclk_err_state = 1'b0;
+ always @(posedge i_xclk_clk)
+ if (xck_reset || (!req_fifo_empty && !req_stb))
+ xclk_err_state <= 1'b0;
+ else if (o_xclk_cyc && i_xclk_err)
+ xclk_err_state <= 1'b1;
+
+ initial o_xclk_cyc = 1'b0;
+ always @(posedge i_xclk_clk)
+ if (xck_reset || (o_xclk_cyc && i_xclk_err))
+ o_xclk_cyc <= 1'b0;
+ else if (!req_fifo_empty && !req_stb)
+ o_xclk_cyc <= 1'b0;
+ else if (!req_fifo_empty && !xclk_err_state)
+ o_xclk_cyc <= req_stb;
+
+ initial o_xclk_stb = 1'b0;
+ always @(posedge i_xclk_clk)
+ if (xck_reset || (o_xclk_cyc && i_xclk_err) || xclk_err_state)
+ o_xclk_stb <= 1'b0;
+ else if (!o_xclk_stb || !i_xclk_stall)
+ o_xclk_stb <= req_stb && !req_fifo_empty;
+
+ always @(posedge i_xclk_clk)
+ if ((!o_xclk_stb || !i_xclk_stall) && req_stb && !req_fifo_empty)
+ o_xclk_we <= req_we;
+
+ always @(posedge i_xclk_clk)
+ if (!o_xclk_stb || !i_xclk_stall)
+ begin
+ o_xclk_addr <= req_addr;
+ o_xclk_data <= req_data;
+ o_xclk_sel <= req_sel;
+ end
+ // }}}
+
+
+ //
+ // Request counting
+ // {{{
+ initial acks_outstanding = 0;
+ initial ackfifo_single = 0;
+ initial ackfifo_empty = 1;
+ initial ackfifo_full = 0;
+ always @(posedge i_wb_clk)
+ if (i_reset || !i_wb_cyc || o_wb_err)
+ begin
+ acks_outstanding <= 0;
+ ackfifo_single <= 0;
+ ackfifo_empty <= 1;
+ ackfifo_full <= 0;
+ end else case({ (i_wb_stb && !o_wb_stall), o_wb_ack })
+ 2'b10: begin
+ acks_outstanding <= acks_outstanding + 1;
+ ackfifo_empty <= 0;
+ ackfifo_single <= ackfifo_empty;
+ ackfifo_full <= (&acks_outstanding[LGFIFO-1:0]);
+ end
+ 2'b01: begin
+ acks_outstanding <= acks_outstanding - 1;
+ ackfifo_empty <= (acks_outstanding <= 1);
+ ackfifo_single <= (acks_outstanding == 2);
+ ackfifo_full <= 0;
+ end
+ default: begin end
+ endcase
+
+`ifdef FORMAL
+ always @(*)
+ begin
+ assert(ackfifo_single == (acks_outstanding == 1));
+ assert(ackfifo_empty == (acks_outstanding == 0));
+ assert(ackfifo_full == (acks_outstanding >= (1<<LGFIFO)));
+ assert(acks_outstanding <= (1<<LGFIFO));
+ end
+`endif
+
+ assign o_wb_stall = ackfifo_full || bus_abort || req_fifo_stall;
+ // }}}
+
+ //
+ // The return FIFO
+ // {{{
+ afifo #(
+ .OPT_REGISTER_READS(0),
+ .NFF(NFF), .LGFIFO(LGFIFO),
+ .WIDTH(2+DW)
+`ifdef FORMAL
+ , .F_OPT_DATA_STB(1'b0)
+`endif
+ ) ackfifo(.i_wclk(i_xclk_clk), .i_wr_reset_n(!xck_reset),
+ .i_wr(o_xclk_cyc && ( i_xclk_ack || i_xclk_err )),
+ .i_wr_data({ i_xclk_ack, i_xclk_err, i_xclk_data }),
+ .o_wr_full(ign_ackfifo_stall),
+ //
+ .i_rclk(i_wb_clk), .i_rd_reset_n(!bus_abort),
+ .i_rd(!no_returns),
+ .o_rd_data({ ack_stb, err_stb, ret_wb_data }),
+ .o_rd_empty(no_returns)
+`ifdef FORMAL
+ , .f_fill(ackfifo_prefill)
+`endif
+ );
+ // }}}
+
+ //
+ // Final return processing
+ // {{{
+ initial { o_wb_ack, o_wb_err } = 2'b00;
+ always @(posedge i_wb_clk)
+ if (i_reset || bus_abort || !i_wb_cyc || no_returns || o_wb_err)
+ { o_wb_ack, o_wb_err } <= 2'b00;
+ else
+ { o_wb_ack, o_wb_err } <= { ack_stb, err_stb };
+
+ always @(posedge i_wb_clk)
+ o_wb_data <= ret_wb_data;
+ // }}}
+
+ // Make Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, req_fifo_stall, ign_ackfifo_stall,
+ ackfifo_single };
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ // Register/net/macro declarations
+ // {{{
+`ifdef BMC
+`define BMC_ASSERT assert
+`else
+`define BMC_ASSERT assume
+`endif
+
+ (* gclk *) reg gbl_clk;
+
+ wire [LGFIFO:0] fwb_nreqs, fwb_nacks, fwb_outstanding;
+ wire [LGFIFO:0] fxck_nreqs, fxck_nacks, fxck_outstanding;
+ reg [LGFIFO:0] ackfifo_fill, reqfifo_fill;
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Assume a clock
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ (* anyconst *) reg [3:0] fwb_step, fxck_step;
+ reg [3:0] fwb_count, fxck_count;
+
+ always @(*)
+ begin
+ assume(fwb_step >= 2);
+ assume(fxck_step >= 2);
+
+ assume(fwb_step <= 4'b1000);
+ assume(fxck_step <= 4'b1000);
+
+ // assume(fwb_step == 4'b1000);
+ // assume(fxck_step == 4'b0111);
+ assume((fwb_step == 4'b0111)
+ || (fxck_step == 4'b0111));
+ end
+
+ always @(posedge gbl_clk)
+ begin
+ fwb_count <= fwb_count + fwb_step;
+ fxck_count <= fxck_count + fxck_step;
+ end
+
+ always @(*)
+ begin
+ assume(i_wb_clk == fwb_count[3]);
+ assume(i_xclk_clk == fxck_count[3]);
+ end
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ....
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ //
+ // Cross clock stability assumptions
+ // {{{
+ always @(posedge gbl_clk)
+ if (!$rose(i_wb_clk))
+ begin
+ assume($stable(i_reset));
+
+ assume($stable(i_wb_cyc));
+ assume($stable(i_wb_stb));
+ assume($stable(i_wb_we));
+ assume($stable(i_wb_addr));
+ assume($stable(i_wb_data));
+ assume($stable(i_wb_sel));
+ end
+
+ always @(posedge gbl_clk)
+ if (!$rose(i_xclk_clk))
+ begin
+ assume($stable(i_xclk_ack));
+ assume($stable(i_xclk_err));
+ assume($stable(i_xclk_data));
+ assume($stable(i_xclk_stall));
+ end
+
+ reg past_wb_clk, past_wb_stb, past_wb_we,
+ past_wb_cyc, past_wb_reset, past_wb_err;
+ reg past_xclk, past_xclk_stall, past_xclk_ack,
+ past_xclk_err;
+ reg [DW-1:0] past_xclk_data;
+ reg f_drop_cyc_request;
+
+ always @(posedge gbl_clk)
+ begin
+ past_wb_clk <= i_wb_clk;
+ past_wb_reset<= i_reset;
+ past_wb_cyc <= i_wb_cyc;
+ past_wb_stb <= i_wb_stb;
+ past_wb_we <= i_wb_we;
+ past_wb_err <= o_wb_err;
+ end
+
+ always @(*)
+ if (!i_wb_clk || past_wb_clk)
+ begin
+ assume(past_wb_reset== i_reset);
+ assume(past_wb_cyc == i_wb_cyc);
+ assume(past_wb_stb == i_wb_stb);
+ assume(past_wb_we == i_wb_we);
+ assume(past_wb_err == o_wb_err);
+ end else begin
+ if (past_wb_err && past_wb_cyc)
+ assume(!i_wb_cyc);
+ if (fwb_outstanding > 0)
+ assume(past_wb_we == i_wb_we);
+ end
+
+ always @(posedge gbl_clk)
+ begin
+ past_xclk <= i_xclk_clk;
+ past_xclk_stall <= i_xclk_stall;
+ past_xclk_data <= i_xclk_data;
+ past_xclk_ack <= i_xclk_ack;
+ past_xclk_err <= i_xclk_err;
+ end
+
+ always @(*)
+ if (!i_xclk_clk || past_xclk)
+ begin
+ assume(past_xclk_stall == i_xclk_stall);
+ assume(past_xclk_data == i_xclk_data);
+ assume(past_xclk_ack == i_xclk_ack);
+ assume(past_xclk_err == i_xclk_err);
+ end
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Wishbone bus property checks
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ fwb_slave #(
+ // {{{
+ .AW(AW), .DW(DW),
+ .F_LGDEPTH(LGFIFO+1), .F_OPT_DISCONTINUOUS(1)
+ // }}}
+ ) slv(
+ // {{{
+ i_wb_clk, i_reset,
+ i_wb_cyc, i_wb_stb, i_wb_we, i_wb_addr, i_wb_data, i_wb_sel,
+ o_wb_ack, o_wb_stall, o_wb_data, o_wb_err,
+ fwb_nreqs, fwb_nacks, fwb_outstanding
+ // }}}
+ );
+
+ fwb_master #(
+ // {{{
+ .AW(AW), .DW(DW),
+ .F_LGDEPTH(LGFIFO+1), .F_OPT_DISCONTINUOUS(1),
+ .F_MAX_STALL(4),
+ .F_MAX_ACK_DELAY(7)
+ // }}}
+ ) xclkwb(
+ // {{{
+ i_xclk_clk, xck_reset,
+ o_xclk_cyc, o_xclk_stb, o_xclk_we, o_xclk_addr, o_xclk_data, o_xclk_sel,
+ i_xclk_ack, i_xclk_stall, i_xclk_data, i_xclk_err,
+ fxck_nreqs, fxck_nacks, fxck_outstanding
+ // }}}
+ );
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // (Random/unsorted) properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ always @(*)
+ if (reqfifo_fill != (o_xclk_stb ? 1:0) && !req_stb)
+ assert(ackfifo_fill == 0 || xclk_err_state);
+
+ always @(*)
+ reqfifo_fill = reqfifo_prefill + (o_xclk_stb ? 1:0);
+
+ always @(*)
+ ackfifo_fill = ackfifo_prefill // + (no_returns ? 0:1)
+ + ((o_wb_ack || o_wb_err) ? 1:0);
+
+ always @(*)
+ if (fwb_outstanding > 0)
+ assert(wb_active);
+
+ always @(*)
+ if (f_drop_cyc_request && !bus_abort && !xclk_err_state)
+ begin
+ // req_stb is low, so cycle line has dropped normally
+
+ // If the cycle line has since risen, there may be requests
+ // within the request FIFO in addition to the drop-CYC message.
+ if (i_wb_cyc && wb_active)
+ assert(reqfifo_fill == fwb_outstanding + 1);
+
+ // We wouldn't place a drop CYC message into the FIFO
+ // unless XCLK-CYC was already high
+ assert(o_xclk_cyc && !o_xclk_stb);
+ assert(ackfifo_fill == 0);
+ assert(fxck_outstanding == 0);
+
+ if (reqfifo_fill > 1)
+ assert(wb_active);
+ else
+ assert(!wb_active);
+ end else if (!bus_abort && xclk_err_state)
+ begin
+ //
+ // Bus error downstream causes an abort
+ assert(fxck_outstanding == 0);
+ assert(xck_reset || wb_active || !i_wb_cyc);
+ assert(!o_xclk_stb);
+ if (ackfifo_fill == 1)
+ assert(no_returns || err_stb);
+ else if (!xck_reset && ackfifo_fill == 1)
+ assert(o_wb_err);
+ end else if (!bus_abort && i_wb_cyc && !xck_reset && !xclk_err_state)
+ begin
+ //
+ // Normal operation in operation
+ //
+ assert(reqfifo_fill <= fwb_outstanding + 1);
+ assert(ackfifo_fill <= fwb_outstanding);
+ assert(fxck_outstanding <= fwb_outstanding);
+ if (o_xclk_cyc)
+ assert(wb_active || f_drop_cyc_request);
+ if (reqfifo_fill == (o_xclk_stb ? 1:0) || req_stb)
+ // Either first request is for strobe, or other
+ // request counters are valid
+ assert(reqfifo_fill + ackfifo_fill
+ + fxck_outstanding == fwb_outstanding);
+ else begin
+ // First request is to drop CYC
+ assert(reqfifo_fill== fwb_outstanding + 1);
+ assert(ackfifo_fill == 0);
+ assert(fxck_outstanding == 0);
+ assert(!o_xclk_stb);
+ assert(o_xclk_cyc);
+ end
+ if (acks_outstanding == 0)
+ assert((reqfifo_fill == 0)||!req_stb);
+ end
+
+ always @(*)
+ if (o_wb_ack && wb_active)
+ begin
+ assert(o_xclk_cyc || xclk_err_state);
+ assert(!f_drop_cyc_request);
+ assert(!xck_reset || bus_abort);
+ end
+
+ always @(*)
+ if (!bus_abort && acks_outstanding == 0)
+ assert(reqfifo_fill <= (f_drop_cyc_request ? 1:0)
+ + ((o_xclk_stb && xck_reset) ? 1:0));
+
+ always @(*)
+ if (ackfifo_fill != 0)
+ assert(o_xclk_cyc || xck_reset || xclk_err_state);
+
+ always @(*)
+ if (fxck_outstanding > fwb_outstanding)
+ assert((!i_wb_cyc && wb_active)
+ || i_reset || bus_abort || xck_reset);
+
+ always @(*)
+ if (!i_reset && xck_reset && !o_xclk_cyc)
+ assert(!i_wb_cyc || fwb_outstanding == reqfifo_fill);
+
+ always @(*)
+ if (bus_abort && i_wb_cyc)
+ assert(!wb_active);
+
+ always @(*)
+ if (acks_outstanding < (1<<LGFIFO))
+ begin
+ // assert(!reqfifo_full);
+ assert(!ackfifo_full);
+ end
+
+ always @(*)
+ if (!i_reset && !xck_reset && (fwb_outstanding > 0)
+ && ((fxck_outstanding > 0) || o_xclk_stb))
+ assert(i_wb_we == o_xclk_we);
+
+ always @(*)
+ if (!i_reset && i_wb_cyc)
+ assert(acks_outstanding == fwb_outstanding);
+
+ always @(*)
+ if (xclk_err_state)
+ assert(!o_xclk_cyc);
+
+ always @(*)
+ if (!i_reset && !bus_abort && !i_wb_cyc)
+ begin
+ if (ackfifo_empty)
+ begin
+ if (reqfifo_fill > (o_xclk_stb ? 1:0))
+ assert(!req_stb || xck_reset);
+ assert(reqfifo_fill <= 1);
+ if (xck_reset && !xck_reset_pipe)
+ assert(!o_xclk_cyc);
+ end else begin
+ // ???
+ end
+ end
+
+ always @(*)
+ f_drop_cyc_request = !req_stb
+ && (reqfifo_fill > (o_xclk_stb ? 1:0));
+
+ always @(*)
+ if (!i_reset && !xck_reset && !bus_abort && i_wb_cyc)
+ begin
+ if (!o_xclk_cyc && !xclk_err_state)
+ assert(acks_outstanding == reqfifo_fill
+ - (f_drop_cyc_request ? 1:0));
+ else if (!o_xclk_cyc && xclk_err_state)
+ assert(acks_outstanding >= reqfifo_fill
+ + ackfifo_fill);
+ else if (o_xclk_cyc && !xclk_err_state)
+ begin
+ assert(acks_outstanding >= reqfifo_fill
+ - (f_drop_cyc_request ? 1:0));
+ assert(acks_outstanding >= ackfifo_fill);
+ assert(acks_outstanding >= fxck_outstanding);
+ assert(acks_outstanding ==
+ reqfifo_fill - (((reqfifo_fill > (o_xclk_stb ? 1:0))&&(!req_stb)) ? 1:0)
+ + ackfifo_fill
+ + fxck_outstanding);
+ end
+ if (f_drop_cyc_request)
+ assert(acks_outstanding +1 == reqfifo_fill);
+ else if (reqfifo_fill == 0)
+ assert(!wb_active || o_xclk_cyc || xclk_err_state);
+ end else if (!i_reset && !xck_reset && !bus_abort && f_drop_cyc_request)
+ begin
+ assert(acks_outstanding +1 == reqfifo_fill);
+ assert(ackfifo_fill == 0);
+ assert(fxck_outstanding == 0);
+ assert(!o_xclk_stb);
+ assert(o_xclk_cyc);
+ end
+
+
+ always @(*)
+ if (!bus_abort && wb_active && reqfifo_fill == 0 && !xclk_err_state)
+ assert(o_xclk_cyc);
+
+ always @(*)
+ if (f_drop_cyc_request && !bus_abort)
+ assert(!xck_reset);
+
+ always @(*)
+ assert(!xclk_err_state || acks_outstanding != 0 || xck_reset);
+
+ always @(*)
+ if (o_xclk_cyc && !i_wb_cyc)
+ begin
+ // assert(bus_abort || !xclk_err_state);
+ if (!wb_active && !bus_abort && !xck_reset)
+ assert(f_drop_cyc_request);
+ end else if (i_wb_cyc)
+ begin
+ if (wb_active && !xck_reset)
+ assert(o_xclk_cyc || xclk_err_state
+ ||(reqfifo_fill >= acks_outstanding));
+ end
+
+ // always @(*)
+ // if (acks_outstanding >= (1<<LGFIFO))
+ // assert(o_xclk_cyc || xclk_err_state || xck_reset); // !!!!
+
+ //
+ // !!!!!!!!!!!
+ //
+ // Fig me here
+ always @(*)
+ if (wb_active && !bus_abort && !xck_reset && i_wb_cyc && !xclk_err_state)
+ begin
+ if (reqfifo_fill == 0)
+ assert(o_xclk_cyc);
+ end
+
+ always @(*)
+ if (fxck_outstanding > 0 || o_xclk_stb)
+ assert(!ign_ackfifo_stall);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Sub properties for the REQ FIFO
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ always @(*)
+ if ((acks_outstanding > 0)&&(reqfifo_fill != (o_xclk_stb ? 1:0)))
+ begin
+ // Something valuable is in the request FIFO
+ if (i_wb_cyc && !f_drop_cyc_request)
+ `BMC_ASSERT(req_we == i_wb_we);
+ else if (req_stb && o_xclk_stb)
+ `BMC_ASSERT(o_xclk_we == req_we);
+
+ // if (acks_outstanding > 0)
+ if (!o_xclk_cyc || o_xclk_stb ||
+ fxck_outstanding > 0 || ackfifo_fill > 0)
+ `BMC_ASSERT(req_stb);
+ end // else the request FIFO is empty, nothing is in it
+ // No assumptions therefore need be made
+
+ always @(*)
+ if (!bus_abort && reqfifo_fill == acks_outstanding)
+ `BMC_ASSERT(!req_fifo_stall || !f_drop_cyc_request);
+
+ always @(*)
+ if (!i_reset && o_xclk_cyc && (reqfifo_fill != (o_xclk_stb ? 1:0)))
+ `BMC_ASSERT(!req_stb || req_we == o_xclk_we
+ || fxck_outstanding == 0);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Sub properties for the ACK FIFO
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ always @(*)
+ if (!no_returns)
+ begin
+ `BMC_ASSERT(ack_stb ^ err_stb);
+
+ if ((ackfifo_fill ==(o_wb_ack ? 2:1)) && xclk_err_state)
+ `BMC_ASSERT(err_stb);
+ else if (ackfifo_fill > (o_wb_ack ? 2:1))
+ `BMC_ASSERT(!err_stb);
+ end
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ reg cvr_abort;
+ reg [3:0] cvr_replies, cvr_post_abort;
+
+ initial cvr_abort = 0;
+ always @(posedge i_wb_clk)
+ if (i_reset)
+ cvr_abort <= 0;
+ else if (o_wb_err && acks_outstanding > 2)
+ cvr_abort <= 1;
+
+ initial cvr_replies = 0;
+ always @(posedge i_wb_clk)
+ if (i_reset)
+ cvr_replies <= 0;
+ else if (o_wb_ack || o_wb_err)
+ cvr_replies <= cvr_replies + 1;
+
+ initial cvr_post_abort = 0;
+ always @(posedge i_wb_clk)
+ if (i_reset)
+ cvr_post_abort <= 0;
+ else if (cvr_abort && o_wb_ack)
+ cvr_post_abort <= cvr_post_abort + 1;
+
+ always @(*)
+ begin
+ cover(cvr_replies > 1); // 33
+ cover(cvr_replies > 3); // 38
+ cover(cvr_replies > 9);
+
+ cover(cvr_abort); // 31
+ cover(cvr_post_abort > 1 && cvr_replies > 1); // 63
+ cover(cvr_post_abort > 1 && cvr_replies > 2); // 63
+ cover(cvr_post_abort > 1 && cvr_replies > 3); // 65
+ cover(cvr_post_abort > 2 && cvr_replies > 3); // 65
+ cover(cvr_post_abort > 3 && cvr_replies > 3); // 68
+ cover(cvr_post_abort > 4 && cvr_replies > 3); // 70
+ cover(cvr_post_abort > 3 && cvr_replies > 6); // 72
+ end
+
+ always @(posedge gbl_clk)
+ if (!i_reset)
+ cover(cvr_replies > 9 && !i_wb_clk && acks_outstanding == 0
+ && fwb_nreqs == fwb_nacks && fwb_nreqs == cvr_replies
+ && !bus_abort && fwb_count != fxck_count);
+
+ always @(posedge gbl_clk)
+ if (!i_reset)
+ cover(cvr_replies > 9 && !i_wb_clk && acks_outstanding == 0
+ && fwb_nreqs == fwb_nacks && fwb_nreqs == cvr_replies
+ && !bus_abort && fwb_count != fxck_count
+ && fwb_step != fxck_step);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Simplifying (careless) assumptions
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // None (at present)
+
+ // }}}
+`endif
+// }}}
+endmodule