652 lines
17 KiB
Verilog
652 lines
17 KiB
Verilog
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename: wbmarbiter.v
|
|
// {{{
|
|
// Project: 10Gb Ethernet switch
|
|
//
|
|
// Purpose: A *HIGH* speed N:1 WB arbiter. This works like an N:1 AXI
|
|
// arbiter: Wishbone requests are potentially interleaved between
|
|
// multiple (incoming) slave connections. Hence, an outgoing connection
|
|
// might include requests from slave 1, 2, 4, 3, etc, and the arbiter
|
|
// will be responsible for returning ACKs in the order they were received:
|
|
// 1, 2, 4, 3, etc. There are some unfortunate consequences to this,
|
|
// however, that break some key features of Wishbone.
|
|
//
|
|
// 1. If two slaves have outstanding requests and a bus error is returned,
|
|
// the bus error will be returned to *both* slaves, not just one,
|
|
// *EVEN IF* only one slave created an illegal access.
|
|
// 2. Read-Modify-Write accesses are now broken, because there is no longer
|
|
// any guarantee, when using this arbiter, that no other bus master
|
|
// (incoming slave) will not have modified a given address.
|
|
// 3. The property that bus requests will only ever be a string of reads,
|
|
// or a string of writes, is also broken.
|
|
//
|
|
// Creator: Dan Gisselquist, Ph.D.
|
|
// Gisselquist Technology, LLC
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// }}}
|
|
// Copyright (C) 2023, Gisselquist Technology, LLC
|
|
// {{{
|
|
// This file is part of the ETH10G project.
|
|
//
|
|
// The ETH10G 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, files
|
|
// 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 wbmarbiter #(
|
|
// {{{
|
|
parameter DW = 64,
|
|
parameter AW = 31-$clog2(DW/8),
|
|
parameter NIN = 4,
|
|
parameter LGFIFO = 5,
|
|
parameter [0:0] OPT_LOWPOWER = 0
|
|
// }}}
|
|
) (
|
|
// {{{
|
|
input wire i_clk, i_reset,
|
|
//
|
|
input wire [NIN-1:0] s_cyc, s_stb, s_we,
|
|
input wire [NIN*AW-1:0] s_addr,
|
|
input wire [NIN*DW-1:0] s_data,
|
|
input wire [NIN*DW/8-1:0] s_sel,
|
|
output wire [NIN-1:0] s_stall, s_ack,
|
|
output wire [NIN*DW-1:0] s_idata,
|
|
output wire [NIN-1:0] s_err,
|
|
//
|
|
output reg m_cyc, m_stb, m_we,
|
|
output reg [AW-1:0] m_addr,
|
|
output reg [DW-1:0] m_data,
|
|
output reg [DW/8-1:0] m_sel,
|
|
input wire m_stall, m_ack,
|
|
input wire [DW-1:0] m_idata,
|
|
input wire m_err
|
|
// }}}
|
|
);
|
|
|
|
// Register/net declarations
|
|
// {{{
|
|
genvar gk;
|
|
integer ik;
|
|
|
|
wire arb_stall;
|
|
wire [NIN-1:0] grant;
|
|
reg [NIN-1:0] ack, err;
|
|
reg [DW-1:0] data;
|
|
|
|
wire fifo_reset;
|
|
wire ack_wr, ack_rd;
|
|
reg [LGFIFO:0] fif_wraddr, fif_rdaddr;
|
|
wire [LGFIFO:0] ack_fill;
|
|
wire ack_empty, ack_full;
|
|
wire [NIN-1:0] ack_fifo_data;
|
|
|
|
reg [NIN-1:0] flushing;
|
|
|
|
reg nxt_stb, nxt_we;
|
|
reg [AW-1:0] nxt_addr;
|
|
reg [DW-1:0] nxt_data;
|
|
reg [DW/8-1:0] nxt_sel;
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Arbitrate among sources
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
pktarbiter #(
|
|
.W(NIN)
|
|
) u_arb (
|
|
.i_clk(i_clk), .i_reset_n(!i_reset),
|
|
.i_req(s_stb & ~flushing), .i_stall(arb_stall),
|
|
.o_grant(grant)
|
|
);
|
|
|
|
assign arb_stall = m_stb && m_stall;
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Log STBs, to know where to deliver ACKs
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
assign fifo_reset = i_reset || (m_cyc && m_err);
|
|
assign ack_wr =|(s_stb & ~s_stall);
|
|
assign ack_rd = m_ack;
|
|
|
|
`ifdef FORMAL
|
|
// {{{
|
|
wire [LGFIFO:0] f_first_addr, f_second_addr,
|
|
f_distance_to_first, f_distance_to_second;
|
|
wire f_first_in_fifo, f_second_in_fifo;
|
|
wire [NIN-1:0] f_first_data, f_second_data;
|
|
wire [LGFIFO:0] f_wraddr, f_rdaddr;
|
|
wire [NIN-1:0] f_ch_empty;
|
|
wire [NIN*(LGFIFO+1)-1:0] f_ch_last_addr;
|
|
// }}}
|
|
`endif
|
|
|
|
sfifo #(
|
|
.BW(NIN),
|
|
.LGFLEN(LGFIFO)
|
|
) u_ack_fifo (
|
|
// {{{
|
|
.i_clk(i_clk), .i_reset(fifo_reset),
|
|
.i_wr(ack_wr), .i_data(grant),
|
|
.o_full(ack_full), .o_fill(ack_fill),
|
|
.i_rd(ack_rd), .o_data(ack_fifo_data),
|
|
.o_empty(ack_empty)
|
|
`ifdef FORMAL
|
|
// {{{
|
|
, .f_first_addr(f_first_addr),
|
|
.f_second_addr(f_second_addr),
|
|
.f_first_data(f_first_data),
|
|
.f_second_data(f_second_data),
|
|
.f_first_in_fifo(f_first_in_fifo),
|
|
.f_second_in_fifo(f_second_in_fifo),
|
|
.f_distance_to_first(f_distance_to_first),
|
|
.f_distance_to_second(f_distance_to_second),
|
|
.f_wraddr(f_wraddr), .f_rdaddr(f_rdaddr)
|
|
// }}}
|
|
`endif
|
|
// }}}
|
|
);
|
|
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
fif_wraddr <= 0;
|
|
else if (ack_wr && !ack_full)
|
|
fif_wraddr <= fif_wraddr + 1;
|
|
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
fif_rdaddr <= 0;
|
|
else if (ack_rd && !ack_empty)
|
|
fif_rdaddr <= fif_rdaddr + 1;
|
|
|
|
`ifdef FORMAL
|
|
always @(*)
|
|
if (!fifo_reset)
|
|
assert(fif_wraddr == f_wraddr);
|
|
|
|
always @(*)
|
|
if (!fifo_reset)
|
|
assert(fif_rdaddr == f_rdaddr);
|
|
`endif
|
|
|
|
// Need to do some extra work, just to deal with potential bus errors
|
|
// and dropped CYC lines
|
|
initial ack = 0;
|
|
initial err = 0;
|
|
generate for(gk=0; gk<NIN; gk=gk+1)
|
|
begin : FLUSH_ACKS
|
|
// At issue is the fact that, if the slave drops CYC, we need
|
|
// to abort any ongoing transactions. Likewise, if the master
|
|
// returns a bus error--we'll also need to abort any ongoing
|
|
// transactions. In both of those cases we need to make sure
|
|
// nothing in the FIFO is returned to this slave as an ACK from
|
|
// any outstanding transactions.
|
|
reg empty;
|
|
reg [LGFIFO:0] last_addr;
|
|
|
|
// last_addr
|
|
// {{{
|
|
// last_addr == fif_rdaddr if we are empty, or if we have only
|
|
// one address in the FIFO
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
last_addr <= 0;
|
|
else if (ack_empty || s_stb[gk] && !s_stall[gk])
|
|
last_addr <= fif_wraddr;
|
|
else if (ack_rd && last_addr == fif_rdaddr)
|
|
last_addr <= fif_rdaddr + 1;
|
|
// }}}
|
|
|
|
// empty
|
|
// {{{
|
|
initial empty = 1;
|
|
always @(posedge i_clk)
|
|
if (fifo_reset || !s_cyc[gk])
|
|
empty <= 1;
|
|
else if (s_stb[gk] && !s_stall[gk])
|
|
empty <= 1'b0;
|
|
else if (ack_empty)
|
|
empty <= 1;
|
|
else if (ack_rd && last_addr == fif_rdaddr)
|
|
empty <= 1;
|
|
// }}}
|
|
|
|
// flushing[gk]
|
|
// {{{
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
flushing[gk] <= 0;
|
|
else if (ack_empty || (m_ack && last_addr == fif_rdaddr))
|
|
flushing[gk] <= 0;
|
|
else if (!s_cyc[gk])
|
|
flushing[gk] <= 1;
|
|
// }}}
|
|
|
|
assign s_stall[gk] = flushing[gk] || (grant != (1<<gk))
|
|
|| ack_full || (m_stb && m_stall)
|
|
|| (m_cyc && m_err);
|
|
|
|
// initial ack[gk] = 0;
|
|
// ack[gk]
|
|
// {{{
|
|
always @(posedge i_clk)
|
|
if (i_reset || !m_cyc || !s_cyc[gk] || empty)
|
|
ack[gk] <= 0;
|
|
else
|
|
ack[gk] <= m_ack && ack_fifo_data[gk];
|
|
// }}}
|
|
|
|
// err[gk]
|
|
// {{{
|
|
always @(posedge i_clk)
|
|
if (i_reset || !m_cyc || !s_cyc[gk])
|
|
err[gk] <= 0;
|
|
else if (empty && (!s_stb[gk] || s_stall[gk]))
|
|
err[gk] <= 0;
|
|
else if (m_err && !ack_empty)
|
|
err[gk] <= 1'b1;
|
|
// }}}
|
|
|
|
`ifdef FORMAL
|
|
// {{{
|
|
always @(*)
|
|
if (ack_empty)
|
|
assert(empty);
|
|
|
|
reg [LGFIFO:0] f_dist_to_last;
|
|
always @(*)
|
|
f_dist_to_last = last_addr - f_rdaddr;
|
|
|
|
always @(*)
|
|
if (!fifo_reset)
|
|
assert(f_dist_to_last <= ack_fill);
|
|
|
|
always @(*)
|
|
if (!fifo_reset && f_dist_to_last == ack_fill)
|
|
assert(empty);
|
|
|
|
/*
|
|
if (!fifo_reset)
|
|
assert(empty == ((f_dist_to_last == ack_fill)
|
|
&& (ack_empty || !ack_fifo_data[gk])));
|
|
*/
|
|
|
|
always @(*)
|
|
if (!fifo_reset && last_addr != fif_rdaddr
|
|
&& f_first_addr == last_addr)
|
|
assert(f_first_in_fifo && f_first_data & (1<<gk));
|
|
|
|
always @(*)
|
|
if (!fifo_reset && last_addr != fif_rdaddr
|
|
&& f_second_addr == last_addr)
|
|
assert(f_second_in_fifo && f_second_data & (1<<gk));
|
|
|
|
assign f_ch_empty[gk] = empty;
|
|
assign f_ch_last_addr[gk*(LGFIFO+1) +: (LGFIFO+1)] = last_addr;
|
|
// }}}
|
|
`endif
|
|
end endgenerate
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// m_*: Generate downstram outputs
|
|
// {{{
|
|
|
|
initial m_cyc = 1'b0;
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
m_cyc <= 1'b0;
|
|
else if (ack_wr)
|
|
m_cyc <= 1'b1;
|
|
else if (m_cyc && m_ack && ack_fill == 1)
|
|
m_cyc <= 1'b0;
|
|
|
|
always @(*)
|
|
begin
|
|
nxt_stb = |(s_stb & ~s_stall & ~s_err);
|
|
nxt_we = 0;
|
|
nxt_addr = 0;
|
|
nxt_data = 0;
|
|
nxt_sel = 0;
|
|
for(ik=0; ik<NIN; ik=ik+1)
|
|
if (grant[ik])
|
|
begin
|
|
nxt_we = nxt_we | s_we[ik];
|
|
nxt_addr = nxt_addr | s_addr[ik * AW +: AW ];
|
|
nxt_data = nxt_data | s_data[ik * DW +: DW ];
|
|
nxt_sel = nxt_sel | s_sel[ ik * DW/8 +: DW/8];
|
|
end
|
|
end
|
|
|
|
initial m_stb = 1'b0;
|
|
always @(posedge i_clk)
|
|
if (fifo_reset)
|
|
m_stb <= 1'b0;
|
|
else if (!m_stb || !m_stall)
|
|
m_stb <= nxt_stb;
|
|
|
|
always @(posedge i_clk)
|
|
if (OPT_LOWPOWER && fifo_reset)
|
|
begin
|
|
m_addr <= 0;
|
|
m_data <= 0;
|
|
m_sel <= 0;
|
|
end else if (!m_stb || !m_stall)
|
|
begin
|
|
m_we <= nxt_we;
|
|
m_addr <= nxt_addr;
|
|
m_data <= nxt_data;
|
|
m_sel <= nxt_sel;
|
|
|
|
if (OPT_LOWPOWER && !nxt_stb)
|
|
begin
|
|
m_we <= 1'b0;
|
|
m_addr <= {(AW ){1'b0}};
|
|
m_data <= {(DW ){1'b0}};
|
|
m_sel <= {(DW/8){1'b0}};
|
|
end
|
|
end
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// s_*: Generate return data
|
|
// {{{
|
|
assign s_ack = ack;
|
|
assign s_err = err;
|
|
|
|
always @(posedge i_clk)
|
|
data <= m_idata;
|
|
|
|
assign s_idata = {(NIN){data}};
|
|
// }}}
|
|
|
|
// Keep Verilator happy
|
|
// {{{
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Formal properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
`ifdef FORMAL
|
|
localparam F_LGDEPTH = LGFIFO+1;
|
|
reg f_past_valid;
|
|
wire [F_LGDEPTH-1:0] fwbm_nreqs, fwbm_nacks, fwbm_outstanding;
|
|
wire [F_LGDEPTH-1:0] fwbs_nreqs, fwbs_nacks, fwbs_outstanding;
|
|
(* anyconst *) reg [$clog2(NIN)-1:0] fc_checkid;
|
|
|
|
initial f_past_valid = 0;
|
|
always @(posedge i_clk)
|
|
f_past_valid <= 1;
|
|
|
|
always @(*)
|
|
if (!f_past_valid)
|
|
assume(i_reset);
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Bus checks
|
|
// {{{
|
|
fwb_slave #(
|
|
.AW(AW), .DW(DW), .F_LGDEPTH(F_LGDEPTH)
|
|
) fwb (
|
|
// {{{
|
|
.i_clk(i_clk), .i_reset(i_reset),
|
|
//
|
|
.i_wb_cyc(s_cyc[fc_checkid]), .i_wb_stb(s_stb[fc_checkid]),
|
|
.i_wb_we(s_we[fc_checkid]),
|
|
.i_wb_addr(s_addr[fc_checkid*AW +: AW]),
|
|
.i_wb_data(s_data[fc_checkid*DW +: DW]),
|
|
.i_wb_sel(s_sel[fc_checkid*DW/8 +: DW/8]),
|
|
.i_wb_ack(s_ack[fc_checkid]), .i_wb_stall(s_stall[fc_checkid]),
|
|
.i_wb_idata(s_idata[fc_checkid*DW +: DW]),
|
|
.i_wb_err(s_err[fc_checkid]),
|
|
.f_nreqs(fwbs_nreqs),
|
|
.f_nacks(fwbs_nacks),
|
|
.f_outstanding(fwbs_outstanding)
|
|
// }}}
|
|
);
|
|
|
|
fwb_master #(
|
|
.AW(AW), .DW(DW), .F_LGDEPTH(F_LGDEPTH)
|
|
) fwb_m (
|
|
// {{{
|
|
.i_clk(i_clk), .i_reset(i_reset),
|
|
//
|
|
.i_wb_cyc(m_cyc), .i_wb_stb(m_stb), .i_wb_we(1'b0 && m_we),
|
|
.i_wb_addr(m_addr), .i_wb_data(m_data), .i_wb_sel(m_sel),
|
|
.i_wb_ack(m_ack), .i_wb_stall(m_stall), .i_wb_idata(m_idata),
|
|
.i_wb_err(m_err),
|
|
.f_nreqs(fwbm_nreqs),
|
|
.f_nacks(fwbm_nacks),
|
|
.f_outstanding(fwbm_outstanding)
|
|
// }}}
|
|
);
|
|
|
|
|
|
wire f_known_data, fc_ack;
|
|
wire [LGFIFO:0] f_known_checkid, fc_last_addr, fc_last_distance,
|
|
f_known_noncheckid;
|
|
wire fc_empty;
|
|
|
|
assign fc_empty = f_ch_empty[fc_checkid];
|
|
assign fc_last_addr = f_ch_last_addr >> (fc_checkid * (LGFIFO+1));
|
|
assign fc_last_distance = fc_last_addr - f_rdaddr;
|
|
|
|
assign f_known_data = (f_first_in_fifo && f_distance_to_first == 0)
|
|
|| (f_second_in_fifo && f_distance_to_second == 0);
|
|
|
|
assign f_known_checkid =
|
|
((f_first_in_fifo && (f_first_data & (1<<fc_checkid))) ? 1:0)
|
|
+((f_second_in_fifo && (f_second_data & (1<<fc_checkid)))? 1:0);
|
|
|
|
assign f_known_noncheckid =
|
|
((f_first_in_fifo&&(0==(f_first_data & (1<<fc_checkid))))? 1:0)
|
|
+((f_second_in_fifo&&(0==(f_second_data&(1<<fc_checkid))))?1:0);
|
|
|
|
assign fc_ack = (s_ack & (1<<fc_checkid)) ? 1:0;
|
|
|
|
always @(*)
|
|
if (!i_reset)
|
|
assume((s_cyc & s_stb) == s_stb);
|
|
|
|
generate for(gk=0; gk<NIN; gk=gk+1)
|
|
begin
|
|
always @(*)
|
|
if (!i_reset && s_stb[gk])
|
|
assume(s_cyc[gk]);
|
|
|
|
always @(posedge i_clk)
|
|
if (!f_past_valid || $past(i_reset))
|
|
assume(!s_cyc[gk] && !s_stb[gk]);
|
|
else if ($past(s_stb[gk] && s_stall[gk]))
|
|
begin
|
|
assume(s_cyc[gk]);
|
|
assume(s_stb[gk]);
|
|
assume($stable(s_we[gk]));
|
|
assume($stable(s_addr[gk * AW +: AW]));
|
|
assume($stable(s_data[gk * DW +: DW]));
|
|
assume($stable(s_sel[ gk * (DW/8) +: (DW/8)]));
|
|
end
|
|
|
|
end endgenerate
|
|
|
|
always @(*)
|
|
if (!i_reset)
|
|
begin
|
|
// assert(empty == ((f_dist_to_last == ack_fill)
|
|
// && (ack_empty || !ack_fifo_data[gk])));
|
|
if (f_first_in_fifo)
|
|
begin
|
|
assert($onehot(f_first_data));
|
|
if (fc_last_addr == f_first_addr && f_first_addr != f_rdaddr)
|
|
assert(f_first_data & (1<<fc_checkid));
|
|
if (f_first_data & (1<<fc_checkid))
|
|
begin
|
|
assert(f_distance_to_first <= fc_last_distance);
|
|
end else begin
|
|
assert(fc_last_distance == 0
|
|
|| fc_last_distance != f_distance_to_first);
|
|
assert(f_distance_to_first < ack_fill);
|
|
end
|
|
end
|
|
|
|
if (f_second_in_fifo)
|
|
begin
|
|
assert($onehot(f_second_data));
|
|
if (fc_last_addr == f_second_addr && f_second_addr != f_rdaddr)
|
|
assert(f_second_data & (1<<fc_checkid));
|
|
if (f_second_data & (1<<fc_checkid))
|
|
begin
|
|
assert(f_distance_to_second <= fc_last_distance);
|
|
end else begin
|
|
assert(fc_last_distance == 0
|
|
|| fc_last_distance != f_distance_to_second);
|
|
assert(f_distance_to_second < ack_fill);
|
|
end
|
|
|
|
if (fc_last_distance >= f_distance_to_second) // ***
|
|
assert(fwbs_outstanding <= fc_last_distance+1
|
|
- f_known_noncheckid + fc_ack);
|
|
end
|
|
|
|
if (fc_last_addr == f_wraddr)
|
|
assert(ack_empty);
|
|
|
|
// f_known_checkid+fc_ack<= fwbs_outstanding <= ack_fill+fc_ack
|
|
assert(fwbs_outstanding >= f_known_checkid + fc_ack);
|
|
assert(fwbs_outstanding <= ack_fill+fc_ack-f_known_noncheckid);
|
|
assert(fc_last_distance <= ack_fill);
|
|
assert(fwbs_outstanding <= fc_last_distance
|
|
+ fc_ack + (ack_empty ? 0 :1));
|
|
assert(fwbm_outstanding + (m_stb ? 1:0) + (fc_ack ? 1:0)
|
|
>= fwbs_outstanding); // ***
|
|
assert(ack_fill == fwbm_outstanding + (m_stb ? 1:0));
|
|
if (fc_empty)
|
|
begin
|
|
assert(fwbs_outstanding == (fc_ack ? 1:0));
|
|
assert(fc_last_distance == 0);
|
|
assert(ack_empty
|
|
|| ((ack_fifo_data & (1<<fc_checkid))==0));
|
|
end else begin
|
|
assert(!ack_empty);
|
|
assert(fc_last_distance != 0
|
|
|| (ack_fifo_data & (1<<fc_checkid)));
|
|
end
|
|
|
|
assume((flushing & (1<<fc_checkid))==0);
|
|
if (ack_empty)
|
|
begin
|
|
end else if (!f_known_data)
|
|
begin
|
|
assume($onehot(ack_fifo_data));
|
|
|
|
if(fc_empty)
|
|
begin
|
|
assume((ack_fifo_data & (1<<fc_checkid))==0);
|
|
end else if (fc_last_distance == 0)
|
|
begin
|
|
assume(ack_fifo_data & (1<<fc_checkid));
|
|
end
|
|
|
|
if (fwbs_outstanding == f_known_checkid + fc_ack)
|
|
begin
|
|
assume((ack_fifo_data & (1<<fc_checkid))==0);
|
|
end
|
|
|
|
if (fwbs_outstanding == ack_fill - f_known_noncheckid + fc_ack)
|
|
begin
|
|
assume(ack_fifo_data & (1<<fc_checkid));
|
|
end
|
|
|
|
if (fwbs_outstanding == fc_last_distance + fc_ack + 1)
|
|
begin
|
|
assume(ack_fifo_data & (1<<fc_checkid));
|
|
end
|
|
|
|
if (fwbs_outstanding == fc_last_distance
|
|
+ fc_ack + (ack_empty ? 0 :1))
|
|
assume(ack_fifo_data & (1<<fc_checkid));
|
|
end
|
|
end
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OPT_LOWPOWER
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
generate if (OPT_LOWPOWER)
|
|
begin
|
|
always @(*)
|
|
if (!i_reset && !m_stb)
|
|
begin
|
|
assert(m_we == 1'b0);
|
|
assert(m_addr == {(AW){1'b0}});
|
|
assert(m_data == {(DW){1'b0}});
|
|
assert(m_sel == {(DW/8){1'b0}});
|
|
end
|
|
|
|
end endgenerate
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// "Careless" assumptions
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(*)
|
|
if (!i_reset && fwbm_nreqs != fwbm_nacks)
|
|
assume(m_cyc);
|
|
|
|
always @(*)
|
|
if (!i_reset && fwbs_nreqs != fwbs_nacks)
|
|
assume(s_cyc[fc_checkid]);
|
|
|
|
always @(*)
|
|
if (!i_reset && m_cyc)
|
|
assume(!m_err);
|
|
|
|
always @(*)
|
|
if (!i_reset)
|
|
assert(err == 0);
|
|
|
|
always @(*)
|
|
if (!i_reset)
|
|
assume(fc_checkid == 0);
|
|
|
|
`endif
|
|
// }}}
|
|
endmodule
|