summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axilxbar.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axilxbar.v')
-rw-r--r--rtl/wb2axip/axilxbar.v2421
1 files changed, 2421 insertions, 0 deletions
diff --git a/rtl/wb2axip/axilxbar.v b/rtl/wb2axip/axilxbar.v
new file mode 100644
index 0000000..4a1ed43
--- /dev/null
+++ b/rtl/wb2axip/axilxbar.v
@@ -0,0 +1,2421 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axilxbar.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: Create a full crossbar between NM AXI-lite sources (masters),
+// and NS AXI-lite slaves. Every master can talk to any slave,
+// provided it isn't already busy.
+//
+// Performance: This core has been designed with the goal of being able to push
+// one transaction through the interconnect, from any master to
+// any slave, per clock cycle. This may perhaps be its most unique
+// feature. While throughput is good, latency is something else.
+//
+// The arbiter requires a clock to switch, then another clock to send data
+// downstream. This creates a minimum two clock latency up front. The
+// return path suffers another clock of latency as well, placing the
+// minimum latency at four clocks. The minimum write latency is at
+// least one clock longer, since the write data must wait for the write
+// address before proceeeding.
+//
+// Usage: To use, you must first set NM and NS to the number of masters
+// and the number of slaves you wish to connect to. You then need to
+// adjust the addresses of the slaves, found SLAVE_ADDR array. Those
+// bits that are relevant in SLAVE_ADDR to then also be set in SLAVE_MASK.
+// Adjusting the data and address widths go without saying.
+//
+// Lower numbered masters are given priority in any "fight".
+//
+// Channel grants are given on the condition that 1) they are requested,
+// 2) no other channel has a grant, 3) all of the responses have been
+// received from the current channel, and 4) the internal counters are
+// not overflowing.
+//
+// The core limits the number of outstanding transactions on any channel to
+// 1<<LGMAXBURST-1.
+//
+// Channel grants are lost 1) after OPT_LINGER clocks of being idle, or
+// 2) when another master requests an idle (but still lingering) channel
+// assignment, or 3) once all the responses have been returned to the
+// current channel, and the current master is requesting another channel.
+//
+// A special slave is allocated for the case of no valid address.
+//
+// Since the write channel has no address information, the write data
+// channel always be delayed by at least one clock from the write address
+// channel.
+//
+// If OPT_LOWPOWER is set, then unused values will be set to zero.
+// This can also be used to help identify relevant values within any
+// trace.
+//
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2024, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License"). You may not use this project,
+// or this file, except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+`default_nettype none
+// }}}
+module axilxbar #(
+ // {{{
+ parameter integer C_AXI_DATA_WIDTH = 32,
+ parameter integer C_AXI_ADDR_WIDTH = 32,
+ //
+ // NM is the number of master interfaces this core supports
+ parameter NM = 4,
+ //
+ // NS is the number of slave interfaces
+ parameter NS = 8,
+ //
+ // AW, and DW, are short-hand abbreviations used locally.
+ localparam AW = C_AXI_ADDR_WIDTH,
+ localparam DW = C_AXI_DATA_WIDTH,
+ // SLAVE_ADDR is a bit vector containing AW bits for each of the
+ // slaves indicating the base address of the slave. This
+ // goes with SLAVE_MASK below.
+ parameter [NS*AW-1:0] SLAVE_ADDR = {
+ 3'b111, {(AW-3){1'b0}},
+ 3'b110, {(AW-3){1'b0}},
+ 3'b101, {(AW-3){1'b0}},
+ 3'b100, {(AW-3){1'b0}},
+ 3'b011, {(AW-3){1'b0}},
+ 3'b010, {(AW-3){1'b0}},
+ 4'b0001, {(AW-4){1'b0}},
+ 4'b0000, {(AW-4){1'b0}} },
+ //
+ // SLAVE_MASK indicates which bits in the SLAVE_ADDR bit vector
+ // need to be checked to determine if a given address request
+ // maps to the given slave or not
+ // Verilator lint_off WIDTH
+ parameter [NS*AW-1:0] SLAVE_MASK =
+ (NS <= 1) ? { 4'b1111, {(AW-4){1'b0}} }
+ : { {(NS-2){ 3'b111, {(AW-3){1'b0}} }},
+ {(2){ 4'b1111, {(AW-4){1'b0}} }} },
+ // Verilator lint_on WIDTH
+ //
+ // If set, OPT_LOWPOWER will set all unused registers, both
+ // internal and external, to zero anytime their corresponding
+ // *VALID bit is clear
+ parameter [0:0] OPT_LOWPOWER = 1,
+ //
+ // OPT_LINGER is the number of cycles to wait, following a
+ // transaction, before tearing down the bus grant.
+ parameter OPT_LINGER = 4,
+ //
+ // LGMAXBURST is the log (base two) of the maximum number of
+ // requests that can be outstanding on any given channel at any
+ // given time. It is used within this core to control the
+ // counters that are used to determine if a particular channel
+ // grant must stay open, or if it may be closed.
+ parameter LGMAXBURST = 5
+ // }}}
+ ) (
+ // {{{
+ input wire S_AXI_ACLK,
+ input wire S_AXI_ARESETN,
+ // Incoming AXI4-lite slave port(s)
+ // {{{
+ input wire [NM-1:0] S_AXI_AWVALID,
+ output wire [NM-1:0] S_AXI_AWREADY,
+ input wire [NM*C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR,
+ // Verilator coverage_off
+ input wire [NM*3-1:0] S_AXI_AWPROT,
+ // Verilator coverage_on
+ //
+ input wire [NM-1:0] S_AXI_WVALID,
+ output wire [NM-1:0] S_AXI_WREADY,
+ input wire [NM*C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA,
+ input wire [NM*C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB,
+ //
+ output wire [NM-1:0] S_AXI_BVALID,
+ input wire [NM-1:0] S_AXI_BREADY,
+ output wire [NM*2-1:0] S_AXI_BRESP,
+ //
+ input wire [NM-1:0] S_AXI_ARVALID,
+ output wire [NM-1:0] S_AXI_ARREADY,
+ input wire [NM*C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,
+ // Verilator coverage_off
+ input wire [NM*3-1:0] S_AXI_ARPROT,
+ // Verilator coverage_on
+ //
+ output wire [NM-1:0] S_AXI_RVALID,
+ input wire [NM-1:0] S_AXI_RREADY,
+ output wire [NM*C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
+ output wire [NM*2-1:0] S_AXI_RRESP,
+ // }}}
+ // Outgoing AXI4-lite master port(s)
+ // {{{
+ output wire [NS*C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR,
+ output wire [NS*3-1:0] M_AXI_AWPROT,
+ output wire [NS-1:0] M_AXI_AWVALID,
+ input wire [NS-1:0] M_AXI_AWREADY,
+ //
+ output wire [NS*C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA,
+ output wire [NS*C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
+ output wire [NS-1:0] M_AXI_WVALID,
+ input wire [NS-1:0] M_AXI_WREADY,
+ //
+ input wire [NS*2-1:0] M_AXI_BRESP,
+ input wire [NS-1:0] M_AXI_BVALID,
+ output wire [NS-1:0] M_AXI_BREADY,
+ //
+ output wire [NS*C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR,
+ output wire [NS*3-1:0] M_AXI_ARPROT,
+ output wire [NS-1:0] M_AXI_ARVALID,
+ input wire [NS-1:0] M_AXI_ARREADY,
+ //
+ input wire [NS*C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA,
+ input wire [NS*2-1:0] M_AXI_RRESP,
+ input wire [NS-1:0] M_AXI_RVALID,
+ output wire [NS-1:0] M_AXI_RREADY
+ // }}}
+ // }}}
+ );
+ //
+ // Local parameters, derived from those above
+ // {{{
+ localparam LGLINGER = (OPT_LINGER>1) ? $clog2(OPT_LINGER+1) : 1;
+ //
+ localparam LGNM = (NM>1) ? $clog2(NM) : 1;
+ localparam LGNS = (NS>1) ? $clog2(NS+1) : 1;
+ //
+ // In order to use indexes, and hence fully balanced mux trees, it helps
+ // to make certain that we have a power of two based lookup. NMFULL
+ // is the number of masters in this lookup, with potentially some
+ // unused extra ones. NSFULL is defined similarly.
+ localparam NMFULL = (NM>1) ? (1<<LGNM) : 1;
+ localparam NSFULL = (NS>1) ? (1<<LGNS) : 2;
+ //
+ localparam [1:0] INTERCONNECT_ERROR = 2'b11;
+ localparam [0:0] OPT_SKID_INPUT = 0;
+ localparam [0:0] OPT_BUFFER_DECODER = 1;
+
+ genvar N,M;
+ integer iN, iM;
+ // }}}
+
+ // {{{
+ reg [NSFULL-1:0] wrequest [0:NM-1];
+ reg [NSFULL-1:0] rrequest [0:NM-1];
+ reg [NSFULL-1:0] wrequested [0:NM];
+ reg [NSFULL-1:0] rrequested [0:NM];
+ reg [NS:0] wgrant [0:NM-1];
+ reg [NS:0] rgrant [0:NM-1];
+ reg [NM-1:0] swgrant;
+ reg [NM-1:0] srgrant;
+ reg [NS-1:0] mwgrant;
+ reg [NS-1:0] mrgrant;
+
+ // verilator lint_off UNUSED
+ wire [LGMAXBURST-1:0] w_sawpending [0:NM-1];
+`ifdef FORMAL
+ wire [LGMAXBURST-1:0] w_swpending [0:NM-1];
+`endif
+ wire [LGMAXBURST-1:0] w_srpending [0:NM-1];
+ // verilator lint_on UNUSED
+ reg [NM-1:0] swfull;
+ reg [NM-1:0] srfull;
+ reg [NM-1:0] swempty;
+ reg [NM-1:0] srempty;
+ //
+ wire [LGNS-1:0] swindex [0:NMFULL-1];
+ wire [LGNS-1:0] srindex [0:NMFULL-1];
+ wire [LGNM-1:0] mwindex [0:NSFULL-1];
+ wire [LGNM-1:0] mrindex [0:NSFULL-1];
+
+ wire [NM-1:0] wdata_expected;
+
+ // The shadow buffers
+ wire [NMFULL-1:0] m_awvalid, m_wvalid, m_arvalid;
+ wire [NM-1:0] dcd_awvalid, dcd_arvalid;
+
+ wire [C_AXI_ADDR_WIDTH-1:0] m_awaddr [0:NMFULL-1];
+ wire [2:0] m_awprot [0:NMFULL-1];
+ wire [C_AXI_DATA_WIDTH-1:0] m_wdata [0:NMFULL-1];
+ wire [C_AXI_DATA_WIDTH/8-1:0] m_wstrb [0:NMFULL-1];
+
+ wire [C_AXI_ADDR_WIDTH-1:0] m_araddr [0:NMFULL-1];
+ wire [2:0] m_arprot [0:NMFULL-1];
+ //
+
+ wire [NM-1:0] skd_awvalid, skd_awstall, skd_wvalid;
+ wire [NM-1:0] skd_arvalid, skd_arstall;
+ wire [AW-1:0] skd_awaddr [0:NM-1];
+ wire [3-1:0] skd_awprot [0:NM-1];
+ wire [AW-1:0] skd_araddr [0:NM-1];
+ wire [3-1:0] skd_arprot [0:NM-1];
+
+ reg [NM-1:0] r_bvalid;
+ reg [1:0] r_bresp [0:NM-1];
+
+ reg [NSFULL-1:0] m_axi_awvalid;
+ reg [NSFULL-1:0] m_axi_awready;
+ reg [NSFULL-1:0] m_axi_wvalid;
+ reg [NSFULL-1:0] m_axi_wready;
+ reg [NSFULL-1:0] m_axi_bvalid;
+`ifdef FORMAL
+ reg [NSFULL-1:0] m_axi_bready;
+`endif
+ reg [1:0] m_axi_bresp [0:NSFULL-1];
+
+ reg [NSFULL-1:0] m_axi_arvalid;
+ // Verilator lint_off UNUSED
+ reg [NSFULL-1:0] m_axi_arready;
+ // Verilator lint_on UNUSED
+ reg [NSFULL-1:0] m_axi_rvalid;
+ // Verilator lint_off UNUSED
+ reg [NSFULL-1:0] m_axi_rready;
+ // Verilator lint_on UNUSED
+
+ reg [NM-1:0] r_rvalid;
+ reg [1:0] r_rresp [0:NM-1];
+ reg [DW-1:0] r_rdata [0:NM-1];
+
+ reg [DW-1:0] m_axi_rdata [0:NSFULL-1];
+ reg [1:0] m_axi_rresp [0:NSFULL-1];
+
+ reg [NM-1:0] slave_awaccepts;
+ reg [NM-1:0] slave_waccepts;
+ reg [NM-1:0] slave_raccepts;
+ // }}}
+
+ // m_axi_[aw|w|b]*
+ // {{{
+ always @(*)
+ begin
+ m_axi_awvalid = -1;
+ m_axi_awready = -1;
+ m_axi_wvalid = -1;
+ m_axi_wready = -1;
+ m_axi_bvalid = 0;
+
+ m_axi_awvalid[NS-1:0] = M_AXI_AWVALID;
+ m_axi_awready[NS-1:0] = M_AXI_AWREADY;
+ m_axi_wvalid[NS-1:0] = M_AXI_WVALID;
+ m_axi_wready[NS-1:0] = M_AXI_WREADY;
+ m_axi_bvalid[NS-1:0] = M_AXI_BVALID;
+
+ for(iM=0; iM<NS; iM=iM+1)
+ begin
+ m_axi_bresp[iM] = M_AXI_BRESP[iM* 2 +: 2];
+
+ m_axi_rdata[iM] = M_AXI_RDATA[iM*DW +: DW];
+ m_axi_rresp[iM] = M_AXI_RRESP[iM* 2 +: 2];
+ end
+ for(iM=NS; iM<NSFULL; iM=iM+1)
+ begin
+ m_axi_bresp[iM] = INTERCONNECT_ERROR;
+
+ m_axi_rdata[iM] = 0;
+ m_axi_rresp[iM] = INTERCONNECT_ERROR;
+ end
+
+`ifdef FORMAL
+ m_axi_bready = -1;
+ m_axi_bready[NS-1:0] = M_AXI_BREADY;
+`endif
+ end
+ // }}}
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : DECODE_WRITE_REQUEST
+ // {{{
+ wire [NS:0] wdecode;
+ reg r_mawvalid, r_mwvalid;
+
+ // awskid
+ // {{{
+ skidbuffer #(
+ // {{{
+ .DW(AW+3), .OPT_OUTREG(OPT_SKID_INPUT)
+ // }}}
+ ) awskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXI_AWVALID[N]), .o_ready(S_AXI_AWREADY[N]),
+ .i_data({ S_AXI_AWADDR[N*AW +: AW], S_AXI_AWPROT[N*3 +: 3] }),
+ .o_valid(skd_awvalid[N]), .i_ready(!skd_awstall[N]),
+ .o_data({ skd_awaddr[N], skd_awprot[N] })
+ // }}}
+ );
+ // }}}
+
+ // write address decoding
+ // {{{
+ addrdecode #(
+ // {{{
+ .AW(AW), .DW(3), .NS(NS),
+ .SLAVE_ADDR(SLAVE_ADDR),
+ .SLAVE_MASK(SLAVE_MASK),
+ .OPT_REGISTERED(OPT_BUFFER_DECODER)
+ // }}}
+ ) wraddr(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(skd_awvalid[N]), .o_stall(skd_awstall[N]),
+ .i_addr(skd_awaddr[N]), .i_data(skd_awprot[N]),
+ .o_valid(dcd_awvalid[N]),
+ .i_stall(!dcd_awvalid[N]||!slave_awaccepts[N]),
+ .o_decode(wdecode), .o_addr(m_awaddr[N]),
+ .o_data(m_awprot[N])
+ // }}}
+ );
+ // }}}
+
+ // wskid
+ // {{{
+ skidbuffer #(
+ // {{{
+ .DW(DW+DW/8), .OPT_OUTREG(OPT_SKID_INPUT)
+ // }}}
+ ) wskid (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXI_WVALID[N]), .o_ready(S_AXI_WREADY[N]),
+ .i_data({ S_AXI_WDATA[N*DW +: DW],
+ S_AXI_WSTRB[N*DW/8 +: DW/8]}),
+ .o_valid(skd_wvalid[N]),
+ .i_ready(m_wvalid[N] && slave_waccepts[N]),
+ .o_data({ m_wdata[N], m_wstrb[N] })
+ // }}}
+ );
+ // }}}
+
+ // slave_awaccepts
+ // {{{
+ always @(*)
+ begin
+ slave_awaccepts[N] = 1'b1;
+ if (!swgrant[N])
+ slave_awaccepts[N] = 1'b0;
+ if (swfull[N])
+ slave_awaccepts[N] = 1'b0;
+ if (!wrequest[N][swindex[N]])
+ slave_awaccepts[N] = 1'b0;
+ if (!wgrant[N][NS]&&(m_axi_awvalid[swindex[N]] && !m_axi_awready[swindex[N]]))
+ slave_awaccepts[N] = 1'b0;
+ // ERRORs are always accepted
+ // back pressure is handled in the write side
+ end
+ // }}}
+
+ // slave_waccepts
+ // {{{
+ always @(*)
+ begin
+ slave_waccepts[N] = 1'b1;
+ if (!swgrant[N])
+ slave_waccepts[N] = 1'b0;
+ if (!wdata_expected[N])
+ slave_waccepts[N] = 1'b0;
+ if (!wgrant[N][NS] &&(m_axi_wvalid[swindex[N]]
+ && !m_axi_wready[swindex[N]]))
+ slave_waccepts[N] = 1'b0;
+ if (wgrant[N][NS]&&(S_AXI_BVALID[N]&& !S_AXI_BREADY[N]))
+ slave_waccepts[N] = 1'b0;
+ end
+ // }}}
+
+ // r_mawvalid, r_mwvalid
+ // {{{
+ always @(*)
+ begin
+ r_mawvalid= dcd_awvalid[N] && !swfull[N];
+ r_mwvalid = skd_wvalid[N];
+ wrequest[N]= 0;
+ if (!swfull[N])
+ wrequest[N][NS:0] = wdecode;
+ end
+
+ assign m_awvalid[N] = r_mawvalid;
+ assign m_wvalid[N] = r_mwvalid;
+ // }}}
+
+ // }}}
+ end for (N=NM; N<NMFULL; N=N+1)
+ begin : UNUSED_WSKID_BUFFERS
+ // {{{
+ assign m_awvalid[N] = 0;
+ assign m_awaddr[N] = 0;
+ assign m_awprot[N] = 0;
+ assign m_wdata[N] = 0;
+ assign m_wstrb[N] = 0;
+ // }}}
+ end endgenerate
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : DECODE_READ_REQUEST
+ // {{{
+ wire [NS:0] rdecode;
+ reg r_marvalid;
+
+ // arskid
+ // {{{
+ skidbuffer #(
+ // {{{
+ .DW(AW+3), .OPT_OUTREG(OPT_SKID_INPUT)
+ // }}}
+ ) arskid(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXI_ARVALID[N]), .o_ready(S_AXI_ARREADY[N]),
+ .i_data({ S_AXI_ARADDR[N*AW +: AW], S_AXI_ARPROT[N*3 +: 3] }),
+ .o_valid(skd_arvalid[N]), .i_ready(!skd_arstall[N]),
+ .o_data({ skd_araddr[N], skd_arprot[N] })
+ // }}}
+ );
+ // }}}
+
+ // Read address decoding
+ // {{{
+ addrdecode #(
+ // {{{
+ .AW(AW), .DW(3), .NS(NS),
+ .SLAVE_ADDR(SLAVE_ADDR), .SLAVE_MASK(SLAVE_MASK),
+ .OPT_REGISTERED(OPT_BUFFER_DECODER)
+ // }}}
+ ) rdaddr(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(skd_arvalid[N]), .o_stall(skd_arstall[N]),
+ .i_addr(skd_araddr[N]), .i_data(skd_arprot[N]),
+ .o_valid(dcd_arvalid[N]),
+ .i_stall(!m_arvalid[N] || !slave_raccepts[N]),
+ .o_decode(rdecode), .o_addr(m_araddr[N]),
+ .o_data(m_arprot[N])
+ // }}}
+ );
+ // }}}
+
+ // r_marvalid -> m_arvalid[N]
+ // {{{
+ always @(*)
+ begin
+ r_marvalid = dcd_arvalid[N] && !srfull[N];
+ rrequest[N] = 0;
+ if (!srfull[N])
+ rrequest[N][NS:0] = rdecode;
+ end
+
+ assign m_arvalid[N] = r_marvalid;
+ // }}}
+
+ // slave_raccepts
+ // {{{
+ always @(*)
+ begin
+ slave_raccepts[N] = 1'b1;
+ if (!srgrant[N])
+ slave_raccepts[N] = 1'b0;
+ if (srfull[N])
+ slave_raccepts[N] = 1'b0;
+ // verilator lint_off WIDTH
+ if (!rrequest[N][srindex[N]])
+ slave_raccepts[N] = 1'b0;
+ // verilator lint_on WIDTH
+ if (!rgrant[N][NS])
+ begin
+ if (m_axi_arvalid[srindex[N]] && !m_axi_arready[srindex[N]])
+ slave_raccepts[N] = 1'b0;
+ end else if (S_AXI_RVALID[N] && !S_AXI_RREADY[N])
+ slave_raccepts[N] = 1'b0;
+ end
+ // }}}
+
+ // }}}
+ end for (N=NM; N<NMFULL; N=N+1)
+ begin : UNUSED_RSKID_BUFFERS
+ // {{{
+ assign m_arvalid[N] = 0;
+ assign m_araddr[N] = 0;
+ assign m_arprot[N] = 0;
+ // }}}
+ end endgenerate
+
+ // wrequested
+ // {{{
+ always @(*)
+ begin : DECONFLICT_WRITE_REQUESTS
+
+ for(iN=1; iN<NM ; iN=iN+1)
+ wrequested[iN] = 0;
+
+ // Vivado may complain about too many bits for wrequested.
+ // This is (currrently) expected. swindex is used to index
+ // into wrequested, and swindex has LGNS bits, where LGNS
+ // is $clog2(NS+1) rather than $clog2(NS). The extra bits
+ // are defined to be zeros, but the point is there are defined.
+ // Therefore, no matter what swindex is, it will always
+ // reference something valid.
+ wrequested[NM] = 0;
+
+ for(iM=0; iM<NS; iM=iM+1)
+ begin
+ wrequested[0][iM] = 1'b0;
+ for(iN=1; iN<NM ; iN=iN+1)
+ begin
+ // Continue to request any channel with
+ // a grant and pending operations
+ if (wrequest[iN-1][iM] && wgrant[iN-1][iM])
+ wrequested[iN][iM] = 1;
+ if (wrequest[iN-1][iM] && (!swgrant[iN-1]||swempty[iN-1]))
+ wrequested[iN][iM] = 1;
+ // Otherwise, if it's already claimed, then
+ // it can't be claimed again
+ if (wrequested[iN-1][iM])
+ wrequested[iN][iM] = 1;
+ end
+ wrequested[NM][iM] = wrequest[NM-1][iM] || wrequested[NM-1][iM];
+ end
+ end
+ // }}}
+
+ // rrequested
+ // {{{
+ always @(*)
+ begin : DECONFLICT_READ_REQUESTS
+
+ for(iN=0; iN<NM ; iN=iN+1)
+ rrequested[iN] = 0;
+
+ // See the note above for wrequested. This applies to
+ // rrequested as well.
+ rrequested[NM] = 0;
+
+ for(iM=0; iM<NS; iM=iM+1)
+ begin
+ rrequested[0][iM] = 0;
+ for(iN=1; iN<NM ; iN=iN+1)
+ begin
+ // Continue to request any channel with
+ // a grant and pending operations
+ if (rrequest[iN-1][iM] && rgrant[iN-1][iM])
+ rrequested[iN][iM] = 1;
+ if (rrequest[iN-1][iM] && (!srgrant[iN-1] || srempty[iN-1]))
+ rrequested[iN][iM] = 1;
+ // Otherwise, if it's already claimed, then
+ // it can't be claimed again
+ if (rrequested[iN-1][iM])
+ rrequested[iN][iM] = 1;
+ end
+ rrequested[NM][iM] = rrequest[NM-1][iM] || rrequested[NM-1][iM];
+ end
+ end
+ // }}}
+
+ // mwgrant, mrgrant
+ // {{{
+ generate for(M=0; M<NS; M=M+1)
+ begin : GEN_GRANT
+ // {{{
+ initial mwgrant[M] = 0;
+ always @(*)
+ begin
+ mwgrant[M] = 0;
+ for(iN=0; iN<NM; iN=iN+1)
+ if (wgrant[iN][M])
+ mwgrant[M] = 1;
+ end
+
+ always @(*)
+ begin
+ mrgrant[M] = 0;
+ for(iN=0; iN<NM; iN=iN+1)
+ if (rgrant[iN][M])
+ mrgrant[M] = 1;
+ end
+ // }}}
+ end endgenerate
+ // }}}
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : ARBITRATE_WRITE_REQUESTS
+ // {{{
+ // Declarations
+ // {{{
+ reg stay_on_channel;
+ reg requested_channel_is_available;
+ reg leave_channel;
+ reg [LGNS-1:0] requested_index;
+ wire linger;
+ // }}}
+
+ // stay_on_channel
+ // {{{
+ always @(*)
+ begin
+ stay_on_channel = |(wrequest[N][NS:0] & wgrant[N]);
+
+ if (swgrant[N] && !swempty[N])
+ stay_on_channel = 1;
+ end
+ // }}}
+
+ // requested_channel_is_available
+ // {{{
+ always @(*)
+ begin
+ requested_channel_is_available =
+ |(wrequest[N][NS-1:0] & ~mwgrant
+ & ~wrequested[N][NS-1:0]);
+ if (wrequest[N][NS])
+ requested_channel_is_available = 1;
+
+ if (NM < 2)
+ requested_channel_is_available = m_awvalid[N];
+ end
+ // }}}
+
+ if (OPT_LINGER == 0)
+ begin : NO_LINGER
+ // {{{
+ assign linger = 0;
+ // }}}
+ end else begin : WRITE_LINGER
+ // {{{
+ reg [LGLINGER-1:0] linger_counter;
+ reg r_linger;
+
+ initial r_linger = 0;
+ initial linger_counter = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || wgrant[N][NS])
+ begin
+ r_linger <= 0;
+ linger_counter <= 0;
+ end else if (!swempty[N] || S_AXI_BVALID[N])
+ begin
+ linger_counter <= OPT_LINGER;
+ r_linger <= 1;
+ end else if (linger_counter > 0)
+ begin
+ r_linger <= (linger_counter > 1);
+ linger_counter <= linger_counter - 1;
+ end else
+ r_linger <= 0;
+
+ assign linger = r_linger;
+
+`ifdef FORMAL
+ // {{{
+ always @(*)
+ assert(linger == (linger_counter != 0));
+ // }}}
+`endif
+ // }}}
+ end
+
+ // leave_channel
+ // {{{
+ always @(*)
+ begin
+ leave_channel = 0;
+ if (!m_awvalid[N]
+ && (!linger || wrequested[NM][swindex[N]]))
+ // Leave the channel after OPT_LINGER counts
+ // of the channel being idle, or when someone
+ // else asks for the channel
+ leave_channel = 1;
+ if (m_awvalid[N] && !wrequest[N][swindex[N]])
+ // Need to leave this channel to connect
+ // to any other channel
+ leave_channel = 1;
+ end
+ // }}}
+
+ // wgrant, swgrant
+ // {{{
+ initial wgrant[N] = 0;
+ initial swgrant[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ wgrant[N] <= 0;
+ swgrant[N] <= 0;
+ end else if (!stay_on_channel)
+ begin
+ if (requested_channel_is_available)
+ begin
+ // Switching channels
+ swgrant[N] <= 1'b1;
+ wgrant[N] <= wrequest[N][NS:0];
+ end else if (leave_channel)
+ begin
+ swgrant[N] <= 1'b0;
+ wgrant[N] <= 0;
+ end
+ end
+ // }}}
+
+ // requested_index
+ // {{{
+ always @(wrequest[N])
+ begin
+ requested_index = 0;
+ for(iM=0; iM<=NS; iM=iM+1)
+ if (wrequest[N][iM])
+ requested_index= requested_index | iM[LGNS-1:0];
+ end
+ // }}}
+
+ // Now for swindex
+ // {{{
+ reg [LGNS-1:0] r_swindex;
+
+ initial r_swindex = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!stay_on_channel && requested_channel_is_available)
+ r_swindex <= requested_index;
+
+ assign swindex[N] = r_swindex;
+ // }}}
+ // }}}
+ end for (N=NM; N<NMFULL; N=N+1)
+ begin : EMPTY_WRITE_REQUEST
+ // {{{
+ assign swindex[N] = 0;
+ // }}}
+ end endgenerate
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : ARBITRATE_READ_REQUESTS
+ // {{{
+ // Declarations
+ // {{{
+ reg stay_on_channel;
+ reg requested_channel_is_available;
+ reg leave_channel;
+ reg [LGNS-1:0] requested_index;
+ wire linger;
+ // }}}
+
+ // stay_on_channel
+ // {{{
+ always @(*)
+ begin
+ stay_on_channel = |(rrequest[N][NS:0] & rgrant[N]);
+
+ if (srgrant[N] && !srempty[N])
+ stay_on_channel = 1;
+ end
+ // }}}
+
+ // requested_channel_is_available
+ // {{{
+ always @(*)
+ begin
+ requested_channel_is_available =
+ |(rrequest[N][NS-1:0] & ~mrgrant
+ & ~rrequested[N][NS-1:0]);
+ if (rrequest[N][NS])
+ requested_channel_is_available = 1;
+
+ if (NM < 2)
+ requested_channel_is_available = m_arvalid[N];
+ end
+ // }}}
+
+ if (OPT_LINGER == 0)
+ begin : NO_LINGER
+ // {{{
+ assign linger = 0;
+ // }}}
+ end else begin : READ_LINGER
+ // {{{
+ reg [LGLINGER-1:0] linger_counter;
+ reg r_linger;
+
+ initial r_linger = 0;
+ initial linger_counter = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || rgrant[N][NS])
+ begin
+ r_linger <= 0;
+ linger_counter <= 0;
+ end else if (!srempty[N] || S_AXI_RVALID[N])
+ begin
+ linger_counter <= OPT_LINGER;
+ r_linger <= 1;
+ end else if (linger_counter > 0)
+ begin
+ r_linger <= (linger_counter > 1);
+ linger_counter <= linger_counter - 1;
+ end else
+ r_linger <= 0;
+
+ assign linger = r_linger;
+`ifdef FORMAL
+ // {{{
+ always @(*)
+ assert(linger == (linger_counter != 0));
+ // }}}
+`endif
+ // }}}
+ end
+
+ // leave_channel
+ // {{{
+ always @(*)
+ begin
+ leave_channel = 0;
+ if (!m_arvalid[N]
+ && (!linger || rrequested[NM][srindex[N]]))
+ // Leave the channel after OPT_LINGER counts
+ // of the channel being idle, or when someone
+ // else asks for the channel
+ leave_channel = 1;
+ if (m_arvalid[N] && !rrequest[N][srindex[N]])
+ // Need to leave this channel to connect
+ // to any other channel
+ leave_channel = 1;
+ end
+ // }}}
+
+ // rgrant, srgrant
+ // {{{
+ initial rgrant[N] = 0;
+ initial srgrant[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ rgrant[N] <= 0;
+ srgrant[N] <= 0;
+ end else if (!stay_on_channel)
+ begin
+ if (requested_channel_is_available)
+ begin
+ // Switching channels
+ srgrant[N] <= 1'b1;
+ rgrant[N] <= rrequest[N][NS:0];
+ end else if (leave_channel)
+ begin
+ srgrant[N] <= 1'b0;
+ rgrant[N] <= 0;
+ end
+ end
+ // }}}
+
+ // requested_index
+ // {{{
+ always @(rrequest[N])
+ begin
+ requested_index = 0;
+ for(iM=0; iM<=NS; iM=iM+1)
+ if (rrequest[N][iM])
+ requested_index = requested_index|iM[LGNS-1:0];
+ end
+ // }}}
+
+ // Now for srindex
+ // {{{
+ reg [LGNS-1:0] r_srindex;
+
+ initial r_srindex = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!stay_on_channel && requested_channel_is_available)
+ r_srindex <= requested_index;
+
+ assign srindex[N] = r_srindex;
+ // }}}
+ // }}}
+ end for (N=NM; N<NMFULL; N=N+1)
+ begin : EMPTY_READ_REQUEST
+ // {{{
+ assign srindex[N] = 0;
+ // }}}
+ end endgenerate
+
+ // Calculate mwindex
+ generate for (M=0; M<NS; M=M+1)
+ begin : SLAVE_WRITE_INDEX
+ // {{{
+ if (NM <= 1)
+ begin : ONE_MASTER
+ // {{{
+ assign mwindex[M] = 0;
+ // }}}
+ end else begin : MULTIPLE_MASTERS
+ // {{{
+ reg [LGNM-1:0] reswindex;
+ reg [LGNM-1:0] r_mwindex;
+
+ always @(*)
+ begin
+ reswindex = 0;
+ for(iN=0; iN<NM; iN=iN+1)
+ if ((!swgrant[iN] || swempty[iN])
+ &&(wrequest[iN][M] && !wrequested[iN][M]))
+ reswindex = reswindex | iN[LGNM-1:0];
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (!mwgrant[M])
+ r_mwindex <= reswindex;
+
+ assign mwindex[M] = r_mwindex;
+ // }}}
+ end
+ // }}}
+ end for (M=NS; M<NSFULL; M=M+1)
+ begin : NO_WRITE_INDEX
+ // {{{
+ assign mwindex[M] = 0;
+ // }}}
+ end endgenerate
+
+ // Calculate mrindex
+ generate for (M=0; M<NS; M=M+1)
+ begin : SLAVE_READ_INDEX
+ // {{{
+ if (NM <= 1)
+ begin : ONE_MASTER
+ // {{{
+ assign mrindex[M] = 0;
+ // }}}
+ end else begin : MULTIPLE_MASTERS
+ // {{{
+ reg [LGNM-1:0] resrindex;
+ reg [LGNM-1:0] r_mrindex;
+
+ always @(*)
+ begin
+ resrindex = 0;
+ for(iN=0; iN<NM; iN=iN+1)
+ if ((!srgrant[iN] || srempty[iN])
+ &&(rrequest[iN][M] && !rrequested[iN][M]))
+ resrindex = resrindex | iN[LGNM-1:0];
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (!mrgrant[M])
+ r_mrindex <= resrindex;
+
+ assign mrindex[M] = r_mrindex;
+ // }}}
+ end
+ // }}}
+ end for (M=NS; M<NSFULL; M=M+1)
+ begin : NO_READ_INDEX
+ // {{{
+ assign mrindex[M] = 0;
+ // }}}
+ end endgenerate
+
+ // Assign outputs to the various slaves
+ generate for(M=0; M<NS; M=M+1)
+ begin : WRITE_SLAVE_OUTPUTS
+ // {{{
+
+ // Declarations
+ // {{{
+ reg axi_awvalid;
+ reg [AW-1:0] axi_awaddr;
+ reg [2:0] axi_awprot;
+
+ reg axi_wvalid;
+ reg [DW-1:0] axi_wdata;
+ reg [DW/8-1:0] axi_wstrb;
+ //
+ reg axi_bready;
+
+ wire sawstall, swstall, mbstall;
+ // }}}
+ assign sawstall= (M_AXI_AWVALID[M]&& !M_AXI_AWREADY[M]);
+ assign swstall = (M_AXI_WVALID[M] && !M_AXI_WREADY[M]);
+ assign mbstall = (S_AXI_BVALID[mwindex[M]] && !S_AXI_BREADY[mwindex[M]]);
+
+ // axi_awvalid
+ // {{{
+ initial axi_awvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !mwgrant[M])
+ axi_awvalid <= 0;
+ else if (!sawstall)
+ begin
+ axi_awvalid <= m_awvalid[mwindex[M]]
+ &&(slave_awaccepts[mwindex[M]]);
+ end
+ // }}}
+
+ // axi_awaddr, axi_awprot
+ // {{{
+ initial axi_awaddr = 0;
+ initial axi_awprot = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ axi_awaddr <= 0;
+ axi_awprot <= 0;
+ end else if (OPT_LOWPOWER && !mwgrant[M])
+ begin
+ axi_awaddr <= 0;
+ axi_awprot <= 0;
+ end else if (!sawstall)
+ begin
+ if (!OPT_LOWPOWER||(m_awvalid[mwindex[M]]&&slave_awaccepts[mwindex[M]]))
+ begin
+ axi_awaddr <= m_awaddr[mwindex[M]];
+ axi_awprot <= m_awprot[mwindex[M]];
+ end else begin
+ axi_awaddr <= 0;
+ axi_awprot <= 0;
+ end
+ end
+ // }}}
+
+ // axi_wvalid
+ // {{{
+ initial axi_wvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !mwgrant[M])
+ axi_wvalid <= 0;
+ else if (!swstall)
+ begin
+ axi_wvalid <= (m_wvalid[mwindex[M]])
+ &&(slave_waccepts[mwindex[M]]);
+ end
+ // }}}
+
+ // axi_wdata, axi_wstrb
+ // {{{
+ initial axi_wdata = 0;
+ initial axi_wstrb = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ axi_wdata <= 0;
+ axi_wstrb <= 0;
+ end else if (OPT_LOWPOWER && !mwgrant[M])
+ begin
+ axi_wdata <= 0;
+ axi_wstrb <= 0;
+ end else if (!swstall)
+ begin
+ if (!OPT_LOWPOWER || (m_wvalid[mwindex[M]]&&slave_waccepts[mwindex[M]]))
+ begin
+ axi_wdata <= m_wdata[mwindex[M]];
+ axi_wstrb <= m_wstrb[mwindex[M]];
+ end else begin
+ axi_wdata <= 0;
+ axi_wstrb <= 0;
+ end
+ end
+ // }}}
+
+ // axi_bready
+ // {{{
+ initial axi_bready = 1;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !mwgrant[M])
+ axi_bready <= 1;
+ else if (!mbstall)
+ axi_bready <= 1;
+ else if (M_AXI_BVALID[M]) // && mbstall
+ axi_bready <= 0;
+ // }}}
+
+ //
+ assign M_AXI_AWVALID[M] = axi_awvalid;
+ assign M_AXI_AWADDR[M*AW +: AW] = axi_awaddr;
+ assign M_AXI_AWPROT[M*3 +: 3] = axi_awprot;
+ //
+ //
+ assign M_AXI_WVALID[M] = axi_wvalid;
+ assign M_AXI_WDATA[M*DW +: DW] = axi_wdata;
+ assign M_AXI_WSTRB[M*DW/8 +: DW/8] = axi_wstrb;
+ //
+ //
+ assign M_AXI_BREADY[M] = axi_bready;
+ //
+`ifdef FORMAL
+ // {{{
+ if (OPT_LOWPOWER)
+ begin
+ always @(*)
+ if (!axi_awvalid)
+ begin
+ assert(axi_awaddr == 0);
+ assert(axi_awprot == 0);
+ end
+
+ always @(*)
+ if (!axi_wvalid)
+ begin
+ assert(axi_wdata == 0);
+ assert(axi_wstrb == 0);
+ end
+ end
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+
+ generate for(M=0; M<NS; M=M+1)
+ begin : READ_SLAVE_OUTPUTS
+ // {{{
+ // Declarations
+ // {{{
+ reg axi_arvalid;
+ reg [C_AXI_ADDR_WIDTH-1:0] axi_araddr;
+ reg [2:0] axi_arprot;
+ //
+ reg axi_rready;
+
+ wire arstall, srstall;
+ // }}}
+ assign arstall= (M_AXI_ARVALID[M]&& !M_AXI_ARREADY[M]);
+ assign srstall = (S_AXI_RVALID[mrindex[M]]
+ && !S_AXI_RREADY[mrindex[M]]);
+
+ // axi_arvalid
+ // {{{
+ initial axi_arvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !mrgrant[M])
+ axi_arvalid <= 0;
+ else if (!arstall)
+ begin
+ axi_arvalid <= m_arvalid[mrindex[M]] && slave_raccepts[mrindex[M]];
+ end
+ // }}}
+
+ // axi_araddr, axi_arprot
+ // {{{
+ initial axi_araddr = 0;
+ initial axi_arprot = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ axi_araddr <= 0;
+ axi_arprot <= 0;
+ end else if (OPT_LOWPOWER && !mrgrant[M])
+ begin
+ axi_araddr <= 0;
+ axi_arprot <= 0;
+ end else if (!arstall)
+ begin
+ if (!OPT_LOWPOWER || (m_arvalid[mrindex[M]] && slave_raccepts[mrindex[M]]))
+ begin
+ if (NM == 1)
+ begin
+ axi_araddr <= m_araddr[0];
+ axi_arprot <= m_arprot[0];
+ end else begin
+ axi_araddr <= m_araddr[mrindex[M]];
+ axi_arprot <= m_arprot[mrindex[M]];
+ end
+ end else begin
+ axi_araddr <= 0;
+ axi_arprot <= 0;
+ end
+ end
+ // }}}
+
+ // axi_rready
+ // {{{
+ initial axi_rready = 1;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !mrgrant[M])
+ axi_rready <= 1;
+ else if (!srstall)
+ axi_rready <= 1;
+ else if (M_AXI_RVALID[M] && M_AXI_RREADY[M]) // && srstall
+ axi_rready <= 0;
+ // }}}
+
+ //
+ assign M_AXI_ARVALID[M] = axi_arvalid;
+ assign M_AXI_ARADDR[M*AW +: AW] = axi_araddr;
+ assign M_AXI_ARPROT[M*3 +: 3] = axi_arprot;
+ //
+ assign M_AXI_RREADY[M] = axi_rready;
+ //
+`ifdef FORMAL
+ // {{{
+ if (OPT_LOWPOWER)
+ begin
+ always @(*)
+ if (!axi_arvalid)
+ begin
+ assert(axi_araddr == 0);
+ assert(axi_arprot == 0);
+ end
+ end
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+ // Return values
+ generate for (N=0; N<NM; N=N+1)
+ begin : WRITE_RETURN_CHANNEL
+ // {{{
+ reg axi_bvalid;
+ reg [1:0] axi_bresp;
+ reg i_axi_bvalid;
+ wire [1:0] i_axi_bresp;
+ wire mbstall;
+
+ initial i_axi_bvalid = 1'b0;
+ always @(*)
+ if (wgrant[N][NS])
+ i_axi_bvalid = m_wvalid[N] && slave_waccepts[N];
+ else
+ i_axi_bvalid = m_axi_bvalid[swindex[N]];
+
+ assign i_axi_bresp = m_axi_bresp[swindex[N]];
+
+ assign mbstall = S_AXI_BVALID[N] && !S_AXI_BREADY[N];
+
+ // r_bvalid
+ // {{{
+ initial r_bvalid[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_bvalid[N] <= 0;
+ else if (mbstall && !r_bvalid[N] && !wgrant[N][NS])
+ r_bvalid[N] <= swgrant[N] && i_axi_bvalid;
+ else if (!mbstall)
+ r_bvalid[N] <= 1'b0;
+ // }}}
+
+ // r_bresp
+ // {{{
+ initial r_bresp[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ r_bresp[N] <= 0;
+ else if (OPT_LOWPOWER && (!swgrant[N] || S_AXI_BREADY[N]))
+ r_bresp[N] <= 0;
+ else if (!r_bvalid[N])
+ begin
+ if (!OPT_LOWPOWER ||(i_axi_bvalid && !wgrant[N][NS] && mbstall))
+ begin
+ r_bresp[N] <= i_axi_bresp;
+ end else
+ r_bresp[N] <= 0;
+ end
+ // }}}
+
+ // axi_bvalid
+ // {{{
+ initial axi_bvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ axi_bvalid <= 0;
+ else if (!mbstall)
+ axi_bvalid <= swgrant[N] && (r_bvalid[N] || i_axi_bvalid);
+ // }}}
+
+ // axi_bresp
+ // {{{
+ initial axi_bresp = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ axi_bresp <= 0;
+ else if (OPT_LOWPOWER && !swgrant[N])
+ axi_bresp <= 0;
+ else if (!mbstall)
+ begin
+ if (r_bvalid[N])
+ axi_bresp <= r_bresp[N];
+ else if (!OPT_LOWPOWER || i_axi_bvalid)
+ axi_bresp <= i_axi_bresp;
+ else
+ axi_bresp <= 0;
+
+ if (wgrant[N][NS] && (!OPT_LOWPOWER || i_axi_bvalid))
+ axi_bresp <= INTERCONNECT_ERROR;
+ end
+ // }}}
+
+ //
+ assign S_AXI_BVALID[N] = axi_bvalid;
+ assign S_AXI_BRESP[N*2 +: 2] = axi_bresp;
+`ifdef FORMAL
+ // {{{
+ always @(*)
+ if (r_bvalid[N])
+ assert(r_bresp[N] != 2'b01);
+ always @(*)
+ if (swgrant[N])
+ assert(m_axi_bready[swindex[N]] == !r_bvalid[N]);
+ else
+ assert(!r_bvalid[N]);
+ always @(*)
+ if (OPT_LOWPOWER && !r_bvalid[N])
+ assert(r_bresp[N] == 0);
+
+ always @(*)
+ if (OPT_LOWPOWER && !axi_bvalid)
+ assert(axi_bresp == 0);
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+ // m_axi_?r* values
+ // {{{
+ always @(*)
+ begin
+ m_axi_arvalid = 0;
+ m_axi_arready = 0;
+ m_axi_rvalid = 0;
+ m_axi_rready = 0;
+
+ m_axi_arvalid[NS-1:0] = M_AXI_ARVALID;
+ m_axi_arready[NS-1:0] = M_AXI_ARREADY;
+ m_axi_rvalid[NS-1:0] = M_AXI_RVALID;
+ m_axi_rready[NS-1:0] = M_AXI_RREADY;
+ end
+ // }}}
+
+ // Return values
+ generate for (N=0; N<NM; N=N+1)
+ begin : READ_RETURN_CHANNEL
+ // {{{
+ reg axi_rvalid;
+ reg [1:0] axi_rresp;
+ reg [DW-1:0] axi_rdata;
+ wire srstall;
+ reg i_axi_rvalid;
+
+ initial i_axi_rvalid = 1'b0;
+ always @(*)
+ if (rgrant[N][NS])
+ i_axi_rvalid = m_arvalid[N] && slave_raccepts[N];
+ else
+ i_axi_rvalid = m_axi_rvalid[srindex[N]];
+
+ assign srstall = S_AXI_RVALID[N] && !S_AXI_RREADY[N];
+
+ initial r_rvalid[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_rvalid[N] <= 0;
+ else if (srstall && !r_rvalid[N])
+ r_rvalid[N] <= srgrant[N] && !rgrant[N][NS]&&i_axi_rvalid;
+ else if (!srstall)
+ r_rvalid[N] <= 0;
+
+ initial r_rresp[N] = 0;
+ initial r_rdata[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ r_rresp[N] <= 0;
+ r_rdata[N] <= 0;
+ end else if (OPT_LOWPOWER && (!srgrant[N] || S_AXI_RREADY[N]))
+ begin
+ r_rresp[N] <= 0;
+ r_rdata[N] <= 0;
+ end else if (!r_rvalid[N])
+ begin
+ if (!OPT_LOWPOWER || (i_axi_rvalid && !rgrant[N][NS] && srstall))
+ begin
+ if (NS == 1)
+ begin
+ r_rresp[N] <= m_axi_rresp[0];
+ r_rdata[N] <= m_axi_rdata[0];
+ end else begin
+ r_rresp[N] <= m_axi_rresp[srindex[N]];
+ r_rdata[N] <= m_axi_rdata[srindex[N]];
+ end
+ end else begin
+ r_rresp[N] <= 0;
+ r_rdata[N] <= 0;
+ end
+ end
+
+ initial axi_rvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ axi_rvalid <= 0;
+ else if (!srstall)
+ axi_rvalid <= srgrant[N] && (r_rvalid[N] || i_axi_rvalid);
+
+ initial axi_rresp = 0;
+ initial axi_rdata = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ axi_rresp <= 0;
+ axi_rdata <= 0;
+ end else if (OPT_LOWPOWER && !srgrant[N])
+ begin
+ axi_rresp <= 0;
+ axi_rdata <= 0;
+ end else if (!srstall)
+ begin
+ if (r_rvalid[N])
+ begin
+ axi_rresp <= r_rresp[N];
+ axi_rdata <= r_rdata[N];
+ end else if (!OPT_LOWPOWER || i_axi_rvalid)
+ begin
+ if (NS == 1)
+ begin
+ axi_rresp <= m_axi_rresp[0];
+ axi_rdata <= m_axi_rdata[0];
+ end else begin
+ axi_rresp <= m_axi_rresp[srindex[N]];
+ axi_rdata <= m_axi_rdata[srindex[N]];
+ end
+
+ if (rgrant[N][NS])
+ axi_rresp <= INTERCONNECT_ERROR;
+ end else begin
+ axi_rresp <= 0;
+ axi_rdata <= 0;
+ end
+ end
+
+ assign S_AXI_RVALID[N] = axi_rvalid;
+ assign S_AXI_RRESP[N*2 +: 2] = axi_rresp;
+ assign S_AXI_RDATA[N*DW +: DW]= axi_rdata;
+`ifdef FORMAL
+ // {{{
+ always @(*)
+ if (r_rvalid[N])
+ assert(r_rresp[N] != 2'b01);
+ always @(*)
+ if (srgrant[N] && !rgrant[N][NS])
+ assert(m_axi_rready[srindex[N]] == !r_rvalid[N]);
+ else
+ assert(!r_rvalid[N]);
+ always @(*)
+ if (OPT_LOWPOWER && !r_rvalid[N])
+ begin
+ assert(r_rresp[N] == 0);
+ assert(r_rdata[N] == 0);
+ end
+
+ always @(*)
+ if (OPT_LOWPOWER && !axi_rvalid)
+ begin
+ assert(axi_rresp == 0);
+ assert(axi_rdata == 0);
+ end
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+ // Count pending transactions
+ generate for (N=0; N<NM; N=N+1)
+ begin : COUNT_PENDING
+ // {{{
+ reg [LGMAXBURST-1:0] awpending, rpending,
+ missing_wdata;
+ //reg rempty, awempty; // wempty;
+ reg r_wdata_expected;
+
+ initial awpending = 0;
+ initial swempty[N] = 1;
+ initial swfull[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ awpending <= 0;
+ swempty[N] <= 1;
+ swfull[N] <= 0;
+ end else case ({(m_awvalid[N] && slave_awaccepts[N]),
+ (S_AXI_BVALID[N] && S_AXI_BREADY[N])})
+ 2'b01: begin
+ awpending <= awpending - 1;
+ swempty[N] <= (awpending <= 1);
+ swfull[N] <= 0;
+ end
+ 2'b10: begin
+ awpending <= awpending + 1;
+ swempty[N] <= 0;
+ swfull[N] <= &awpending[LGMAXBURST-1:1];
+ end
+ default: begin end
+ endcase
+
+ initial missing_wdata = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ missing_wdata <= 0;
+ else begin
+ missing_wdata <= missing_wdata
+ +((m_awvalid[N] && slave_awaccepts[N])? 1:0)
+ -((m_wvalid[N] && slave_waccepts[N])? 1:0);
+ end
+
+ initial r_wdata_expected = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_wdata_expected <= 0;
+ else case({ m_awvalid[N] && slave_awaccepts[N],
+ m_wvalid[N] && slave_waccepts[N] })
+ 2'b10: r_wdata_expected <= 1;
+ 2'b01: r_wdata_expected <= (missing_wdata > 1);
+ default: begin end
+ endcase
+
+
+ initial rpending = 0;
+ initial srempty[N] = 1;
+ initial srfull[N] = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ rpending <= 0;
+ srempty[N]<= 1;
+ srfull[N] <= 0;
+ end else case ({(m_arvalid[N] && slave_raccepts[N]),
+ (S_AXI_RVALID[N] && S_AXI_RREADY[N])})
+ 2'b01: begin
+ rpending <= rpending - 1;
+ srempty[N] <= (rpending == 1);
+ srfull[N] <= 0;
+ end
+ 2'b10: begin
+ rpending <= rpending + 1;
+ srfull[N] <= &rpending[LGMAXBURST-1:1];
+ srempty[N] <= 0;
+ end
+ default: begin end
+ endcase
+
+ assign w_sawpending[N] = awpending;
+ assign w_srpending[N] = rpending;
+
+ assign wdata_expected[N] = r_wdata_expected;
+
+`ifdef FORMAL
+ // {{{
+ reg [LGMAXBURST-1:0] wpending;
+ reg [LGMAXBURST-1:0] f_missing_wdata;
+
+ initial wpending = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ wpending <= 0;
+ else case ({(m_wvalid[N] && slave_waccepts[N]),
+ (S_AXI_BVALID[N] && S_AXI_BREADY[N])})
+ 2'b01: wpending <= wpending - 1;
+ 2'b10: wpending <= wpending + 1;
+ default: begin end
+ endcase
+
+ assign w_swpending[N] = wpending;
+
+ always @(*)
+ assert(missing_wdata == awpending - wpending);
+ always @(*)
+ assert(r_wdata_expected == (missing_wdata > 0));
+ always @(*)
+ assert(awpending >= wpending);
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+ // Property validation
+ // {{{
+ initial begin
+ if (NM == 0) begin
+ $display("At least one master must be defined");
+ $stop;
+ end
+
+ if (NS == 0) begin
+ $display("At least one slave must be defined");
+ $stop;
+ end
+ end
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties used to verify this core
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ // Local declarations
+ // {{{
+ localparam F_LGDEPTH = LGMAXBURST+1;
+ wire [F_LGDEPTH-1:0] fm_rd_outstanding [0:NM-1];
+ wire [F_LGDEPTH-1:0] fm_wr_outstanding [0:NM-1];
+ wire [F_LGDEPTH-1:0] fm_awr_outstanding [0:NM-1];
+
+ wire [F_LGDEPTH-1:0] fs_rd_outstanding [0:NS-1];
+ wire [F_LGDEPTH-1:0] fs_wr_outstanding [0:NS-1];
+ wire [F_LGDEPTH-1:0] fs_awr_outstanding [0:NS-1];
+
+ initial assert(NS >= 1);
+ initial assert(NM >= 1);
+ // }}}
+
+`ifdef VERIFIC
+ reg f_past_valid;
+
+ initial f_past_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ f_past_valid <= 1;
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Initial value checks
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+`ifdef VERIFIC
+`define INITIAL_CHECK assume
+`else
+`define INITIAL_CHECK assert
+`endif // VERIFIC
+ always @(*)
+ if (!f_past_valid)
+ begin
+ `INITIAL_CHECK(!S_AXI_ARESETN);
+ `INITIAL_CHECK(S_AXI_BVALID == 0);
+ `INITIAL_CHECK(S_AXI_RVALID == 0);
+ `INITIAL_CHECK(swgrant == 0);
+ `INITIAL_CHECK(srgrant == 0);
+ `INITIAL_CHECK(swfull == 0);
+ `INITIAL_CHECK(srfull == 0);
+ `INITIAL_CHECK(&swempty);
+ `INITIAL_CHECK(&srempty);
+ for(iN=0; iN<NM; iN=iN+1)
+ begin
+ `INITIAL_CHECK(wgrant[iN] == 0);
+ assume(swindex[iN] == 0);
+
+ `INITIAL_CHECK(rgrant[iN] == 0);
+ assume(srindex[iN] == 0);
+
+ `INITIAL_CHECK(r_bvalid[iN] == 0);
+ `INITIAL_CHECK(r_rvalid[iN] == 0);
+ //
+ `INITIAL_CHECK(r_bresp[iN] == 0);
+ //
+ `INITIAL_CHECK(r_rresp[iN] == 0);
+ `INITIAL_CHECK(r_rdata[iN] == 0);
+ end
+
+ `INITIAL_CHECK(M_AXI_AWVALID == 0);
+ `INITIAL_CHECK(M_AXI_WVALID == 0);
+ `INITIAL_CHECK(M_AXI_RVALID == 0);
+ end
+`endif
+ // }}}
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : CHECK_MASTER_GRANTS
+ // {{{
+
+ ////////////////////////////////////////////////////////////////
+ // Write grant checks
+ // {{{
+ always @(*)
+ for(iM=0; iM<=NS; iM=iM+1)
+ begin
+ if (wgrant[N][iM])
+ begin
+ assert((wgrant[N] ^ (1<<iM))==0);
+ assert(swgrant[N]);
+ assert(swindex[N] == iM);
+ if (iM < NS)
+ begin
+ assert(mwgrant[iM]);
+ assert(mwindex[iM] == N);
+ end
+ end
+ end
+
+ always @(*)
+ if (swgrant[N])
+ assert(wgrant[N] != 0);
+
+ always @(*)
+ if (wrequest[N][NS])
+ assert(wrequest[N][NS-1:0] == 0);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // Read grant checking
+ // {{{
+ always @(*)
+ for(iM=0; iM<=NS; iM=iM+1)
+ begin
+ if (rgrant[N][iM])
+ begin
+ assert((rgrant[N] ^ (1<<iM))==0);
+ assert(srgrant[N]);
+ assert(srindex[N] == iM);
+ if (iM < NS)
+ begin
+ assert(mrgrant[iM]);
+ assert(mrindex[iM] == N);
+ end
+ end
+ end
+
+ always @(*)
+ if (srgrant[N])
+ assert(rgrant[N] != 0);
+
+ always @(*)
+ if (rrequest[N][NS])
+ assert(rrequest[N][NS-1:0] == 0);
+ // }}}
+ // }}}
+ end endgenerate
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : CHECK_MASTERS
+ // {{{
+ faxil_slave #(
+ .C_AXI_DATA_WIDTH(DW),
+ .C_AXI_ADDR_WIDTH(AW),
+ .F_OPT_ASSUME_RESET(1'b1),
+ .F_AXI_MAXWAIT(0),
+ .F_AXI_MAXDELAY(0),
+ .F_LGDEPTH(F_LGDEPTH))
+ mstri(.i_clk(S_AXI_ACLK),
+ .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(S_AXI_AWVALID[N]),
+ .i_axi_awready(S_AXI_AWREADY[N]),
+ .i_axi_awaddr(S_AXI_AWADDR[N*AW +: AW]),
+ .i_axi_awprot(S_AXI_AWPROT[N*3 +: 3]),
+ //
+ .i_axi_wvalid(S_AXI_WVALID[N]),
+ .i_axi_wready(S_AXI_WREADY[N]),
+ .i_axi_wdata( S_AXI_WDATA[N*DW +: DW]),
+ .i_axi_wstrb( S_AXI_WSTRB[N*DW/8 +: DW/8]),
+ //
+ .i_axi_bvalid(S_AXI_BVALID[N]),
+ .i_axi_bready(S_AXI_BREADY[N]),
+ .i_axi_bresp( S_AXI_BRESP[N*2 +: 2]),
+ //
+ .i_axi_arvalid(S_AXI_ARVALID[N]),
+ .i_axi_arready(S_AXI_ARREADY[N]),
+ .i_axi_araddr( S_AXI_ARADDR[N*AW +: AW]),
+ .i_axi_arprot( S_AXI_ARPROT[N*3 +: 3]),
+ //
+ //
+ .i_axi_rvalid(S_AXI_RVALID[N]),
+ .i_axi_rready(S_AXI_RREADY[N]),
+ .i_axi_rdata( S_AXI_RDATA[N*DW +: DW]),
+ .i_axi_rresp( S_AXI_RRESP[N*2 +: 2]),
+ //
+ .f_axi_rd_outstanding( fm_rd_outstanding[N]),
+ .f_axi_wr_outstanding( fm_wr_outstanding[N]),
+ .f_axi_awr_outstanding(fm_awr_outstanding[N]));
+
+ //
+ // Check write counters
+ //
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_awr_outstanding[N] == { 1'b0, w_sawpending[N] }
+ +((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0)
+ + (S_AXI_AWREADY[N] ? 0:1));
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_wr_outstanding[N] == { 1'b0, w_swpending[N] }
+ + (S_AXI_WREADY[N] ? 0:1));
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_awr_outstanding[N] >=
+ (S_AXI_AWREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0)
+ + (S_AXI_BVALID[N] ? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_wr_outstanding[N] >=
+ (S_AXI_WREADY[N] ? 0:1)
+ + (S_AXI_BVALID[N]? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_wr_outstanding[N]-(S_AXI_WREADY[N] ? 0:1)
+ <= fm_awr_outstanding[N]-(S_AXI_AWREADY[N] ? 0:1));
+
+ always @(*)
+ if (S_AXI_ARESETN && wgrant[N][NS])
+ assert(fm_wr_outstanding[N] == (S_AXI_WREADY[N] ? 0:1)
+ + (S_AXI_BVALID[N] ? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN && !swgrant[N])
+ begin
+ assert(!S_AXI_BVALID[N]);
+
+ assert(fm_awr_outstanding[N]==(S_AXI_AWREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER & dcd_awvalid[N]) ? 1:0));
+ assert(fm_wr_outstanding[N] == (S_AXI_WREADY[N] ? 0:1));
+ assert(w_sawpending[N] == 0);
+ assert(w_swpending[N] == 0);
+ end
+
+
+ //
+ // Check read counters
+ //
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_rd_outstanding[N] >=
+ (S_AXI_ARREADY[N] ? 0:1)
+ +(S_AXI_RVALID[N] ? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN && (!srgrant[N] || rgrant[N][NS]))
+ assert(fm_rd_outstanding[N] ==
+ (S_AXI_ARREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+ +(S_AXI_RVALID[N] ? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN)
+ assert(fm_rd_outstanding[N] == { 1'b0, w_srpending[N] }
+ +((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+ + (S_AXI_ARREADY[N] ? 0:1));
+
+ always @(*)
+ if (S_AXI_ARESETN && rgrant[N][NS])
+ assert(fm_rd_outstanding[N] == (S_AXI_ARREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER & dcd_arvalid[N]) ? 1:0)
+ +(S_AXI_RVALID[N] ? 1:0));
+
+ always @(*)
+ if (S_AXI_ARESETN && !srgrant[N])
+ begin
+ assert(!S_AXI_RVALID[N]);
+ assert(fm_rd_outstanding[N]== (S_AXI_ARREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER && dcd_arvalid[N])? 1:0));
+ assert(w_srpending[N] == 0);
+ end
+
+ //
+ // Check full/empty flags
+ //
+ localparam [LGMAXBURST-1:0] NEAR_THRESHOLD = -2;
+
+ always @(*)
+ begin
+ assert(swfull[N] == &w_sawpending[N]);
+ assert(swempty[N] == (w_sawpending[N] == 0));
+ end
+
+ always @(*)
+ begin
+ assert(srfull[N] == &w_srpending[N]);
+ assert(srempty[N] == (w_srpending[N] == 0));
+ end
+ // }}}
+ end endgenerate
+
+ generate for(M=0; M<NS; M=M+1)
+ begin : CHECK_SLAVES
+ // {{{
+ faxil_master #(
+ .C_AXI_DATA_WIDTH(DW),
+ .C_AXI_ADDR_WIDTH(AW),
+ .F_OPT_ASSUME_RESET(1'b1),
+ .F_AXI_MAXRSTALL(0),
+ .F_LGDEPTH(F_LGDEPTH))
+ slvi(.i_clk(S_AXI_ACLK),
+ .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(M_AXI_AWVALID[M]),
+ .i_axi_awready(M_AXI_AWREADY[M]),
+ .i_axi_awaddr(M_AXI_AWADDR[M*AW +: AW]),
+ .i_axi_awprot(M_AXI_AWPROT[M*3 +: 3]),
+ //
+ .i_axi_wvalid(M_AXI_WVALID[M]),
+ .i_axi_wready(M_AXI_WREADY[M]),
+ .i_axi_wdata( M_AXI_WDATA[M*DW +: DW]),
+ .i_axi_wstrb( M_AXI_WSTRB[M*DW/8 +: DW/8]),
+ //
+ .i_axi_bvalid(M_AXI_BVALID[M]),
+ .i_axi_bready(M_AXI_BREADY[M]),
+ .i_axi_bresp( M_AXI_BRESP[M*2 +: 2]),
+ //
+ .i_axi_arvalid(M_AXI_ARVALID[M]),
+ .i_axi_arready(M_AXI_ARREADY[M]),
+ .i_axi_araddr( M_AXI_ARADDR[M*AW +: AW]),
+ .i_axi_arprot( M_AXI_ARPROT[M*3 +: 3]),
+ //
+ //
+ .i_axi_rvalid(M_AXI_RVALID[M]),
+ .i_axi_rready(M_AXI_RREADY[M]),
+ .i_axi_rdata( M_AXI_RDATA[M*DW +: DW]),
+ .i_axi_rresp( M_AXI_RRESP[M*2 +: 2]),
+ //
+ .f_axi_rd_outstanding( fs_rd_outstanding[M]),
+ .f_axi_wr_outstanding( fs_wr_outstanding[M]),
+ .f_axi_awr_outstanding(fs_awr_outstanding[M]));
+
+ always @(*)
+ assert(fs_wr_outstanding[M] + (M_AXI_WVALID[M] ? 1:0)
+ <= fs_awr_outstanding[M] + (M_AXI_AWVALID[M]? 1:0));
+
+ always @(*)
+ if (!mwgrant[M])
+ begin
+ assert(fs_awr_outstanding[M] == 0);
+ assert(fs_wr_outstanding[M] == 0);
+ end
+
+ always @(*)
+ if (!mrgrant[M])
+ assert(fs_rd_outstanding[M] == 0);
+
+ always @(*)
+ assert(fs_awr_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}} });
+ always @(*)
+ assert(fs_wr_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}} });
+ always @(*)
+ assert(fs_rd_outstanding[M] < { 1'b1, {(F_LGDEPTH-1){1'b0}} });
+
+ always @(*)
+ if (M_AXI_AWVALID[M])
+ assert(((M_AXI_AWADDR[M*AW +: AW]
+ ^ SLAVE_ADDR[M*AW +: AW])
+ & SLAVE_MASK[M*AW +: AW]) == 0);
+
+ always @(*)
+ if (M_AXI_ARVALID[M])
+ assert(((M_AXI_ARADDR[M*AW +: AW]
+ ^ SLAVE_ADDR[M*AW +: AW])
+ & SLAVE_MASK[M*AW +: AW]) == 0);
+ // }}}
+ end endgenerate
+
+ generate for(N=0; N<NM; N=N+1)
+ begin : CORRELATE_OUTSTANDING
+ // {{{
+ always @(*)
+ if (S_AXI_ARESETN && (swgrant[N] && (swindex[N] < NS)))
+ begin
+ assert((fm_awr_outstanding[N]
+ - (S_AXI_AWREADY[N] ? 0:1)
+ -((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+ - (S_AXI_BVALID[N] ? 1:0))
+ == (fs_awr_outstanding[swindex[N]]
+ + (m_axi_awvalid[swindex[N]] ? 1:0)
+ + (m_axi_bready[swindex[N]] ? 0:1)));
+
+ assert((fm_wr_outstanding[N]
+ - (S_AXI_WREADY[N] ? 0:1)
+ - (S_AXI_BVALID[N] ? 1:0))
+ == (fs_wr_outstanding[swindex[N]]
+ + (m_axi_wvalid[swindex[N]] ? 1:0)
+ + (m_axi_bready[swindex[N]] ? 0:1)));
+
+ end else if (S_AXI_ARESETN && (!swgrant[N] || (swindex[N]==NS)))
+ begin
+ if (!swgrant[N])
+ assert(fm_awr_outstanding[N] ==
+ (S_AXI_AWREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+ +(S_AXI_BVALID[N] ? 1:0));
+ else
+ assert(fm_awr_outstanding[N] >=
+ (S_AXI_AWREADY[N] ? 0:1)
+ +((OPT_BUFFER_DECODER && dcd_awvalid[N]) ? 1:0)
+ +(S_AXI_BVALID[N] ? 1:0));
+
+ assert(fm_wr_outstanding[N] ==
+ (S_AXI_WREADY[N] ? 0:1)
+ +(S_AXI_BVALID[N] ? 1:0));
+ end
+
+ always @(*)
+ if (srgrant[N] && (srindex[N] < NS))
+ begin
+ assert((fm_rd_outstanding[N]//17
+ - (S_AXI_ARREADY[N] ? 0:1)//1
+ -((OPT_BUFFER_DECODER && dcd_arvalid[N]) ? 1:0)
+ - (S_AXI_RVALID[N] ? 1:0))//0
+ == (fs_rd_outstanding[srindex[N]]//16
+ + (m_axi_arvalid[srindex[N]] ? 1:0)//0
+ + (m_axi_rready[srindex[N]] ? 0:1)));//0
+ end
+ // }}}
+ end endgenerate
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ // Can every master reach every slave?
+ // Can things transition without dropping the request line(s)?
+ generate for(N=0; N<NM; N=N+1)
+ begin : COVER_CONNECTIVITY_FROM_MASTER
+ reg [3:0] cvr_w_returns, cvr_r_returns;
+ reg err_wr_return, err_rd_return;
+ reg [NS-1:0] cvr_w_every, cvr_r_every;
+ reg cvr_was_wevery, cvr_was_revery,
+ cvr_whsreturn, cvr_rhsreturn;
+
+ // cvr_w_returns is a speed check: Can we return one write
+ // acknowledgement per clock cycle?
+ initial cvr_w_returns = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_w_returns = 0;
+ else begin
+ cvr_w_returns <= { cvr_w_returns[2:0], 1'b0 };
+ if (S_AXI_BVALID[N] && S_AXI_BREADY[N] && !wgrant[N][NS])
+ cvr_w_returns[0] <= 1'b1;
+ end
+
+ initial cvr_whsreturn = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_whsreturn <= 0;
+ else
+ cvr_whsreturn <= cvr_whsreturn || (&cvr_w_returns);
+
+ // w_every is a connectivity test: Can we get a return from
+ // every slave?
+ initial cvr_w_every = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_w_every <= 0;
+ else if (!S_AXI_AWVALID[N])
+ cvr_w_every <= 0;
+ else begin
+ if (S_AXI_BVALID[N] && S_AXI_BREADY[N] && !wgrant[N][NS])
+ cvr_w_every[swindex[N]] <= 1'b1;
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_BVALID[N])
+ assert($stable(swindex[N]));
+
+ initial cvr_was_wevery = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_was_wevery <= 0;
+ else
+ cvr_was_wevery <= cvr_was_wevery || (&cvr_w_every);
+
+ // err_wr_return is a test to make certain we can return a
+ // bus error on the write channel.
+ initial err_wr_return = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ err_wr_return = 0;
+ else if (wgrant[N][NS] && S_AXI_BVALID[N]
+ && (S_AXI_BRESP[2*N+:2]==INTERCONNECT_ERROR))
+ err_wr_return = 1;
+
+`ifndef VERILATOR
+ always @(*)
+ cover(!swgrant[N] && cvr_whsreturn);
+ always @(*)
+ cover(!swgrant[N] && cvr_was_wevery);
+
+ always @(*)
+ cover(S_AXI_ARESETN && wrequest[N][NS]);
+ always @(*)
+ cover(S_AXI_ARESETN && wrequest[N][NS] && slave_awaccepts[N]);
+ always @(*)
+ cover(err_wr_return);
+ always @(*)
+ cover(!swgrant[N] && err_wr_return);
+`endif
+
+ always @(*)
+ if (S_AXI_BVALID[N])
+ assert(swgrant[N]);
+
+ // cvr_r_returns is a speed check: Can we return one read
+ // acknowledgment per clock cycle?
+ initial cvr_r_returns = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_r_returns = 0;
+ else begin
+ cvr_r_returns <= { cvr_r_returns[2:0], 1'b0 };
+ if (S_AXI_RVALID[N] && S_AXI_RREADY[N])
+ cvr_r_returns[0] <= 1'b1;
+ end
+
+ initial cvr_rhsreturn = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_rhsreturn <= 0;
+ else
+ cvr_rhsreturn <= cvr_rhsreturn || (&cvr_r_returns);
+
+
+ // r_every is a connectivity test: Can we get a read return from
+ // every slave?
+ initial cvr_r_every = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_r_every = 0;
+ else if (!S_AXI_ARVALID[N])
+ cvr_r_every = 0;
+ else begin
+ if (S_AXI_RVALID[N] && S_AXI_RREADY[N])
+ cvr_r_every[srindex[N]] <= 1'b1;
+ end
+
+ // cvr_was_revery is a return to idle check following the
+ // connectivity test. Since the connectivity test is cleared
+ // if there's ever a drop in the valid line, we need a separate
+ // wire to check that this master can return to idle again.
+ initial cvr_was_revery = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_was_revery <= 0;
+ else
+ cvr_was_revery <= cvr_was_revery || (&cvr_r_every);
+
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_RVALID[N])
+ assert($stable(srindex[N]));
+
+ initial err_rd_return = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ err_rd_return = 0;
+ else if (rgrant[N][NS] && S_AXI_RVALID[N]
+ && (S_AXI_RRESP[2*N+:2]==INTERCONNECT_ERROR))
+ err_rd_return = 1;
+
+`ifndef VERILATOR
+ always @(*)
+ cover(!srgrant[N] && cvr_rhsreturn); // @26
+ always @(*)
+ cover(!srgrant[N] && cvr_was_revery); // @26
+
+ always @(*)
+ cover(S_AXI_ARVALID[N] && rrequest[N][NS]);
+ always @(*)
+ cover(rgrant[N][NS]);
+ always @(*)
+ cover(err_rd_return);
+ always @(*)
+ cover(!srgrant[N] && err_rd_return); //@!
+`endif
+
+ always @(*)
+ if (S_AXI_BVALID[N] && wgrant[N][NS])
+ assert(S_AXI_BRESP[2*N+:2]==INTERCONNECT_ERROR);
+ always @(*)
+ if (S_AXI_RVALID[N] && rgrant[N][NS])
+ assert(S_AXI_RRESP[2*N+:2]==INTERCONNECT_ERROR);
+ end endgenerate
+
+ reg cvr_multi_write_hit, cvr_multi_read_hit;
+
+ initial cvr_multi_write_hit = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_multi_write_hit <= 0;
+ else if (fm_awr_outstanding[0] > 2 && !wgrant[0][NS])
+ cvr_multi_write_hit <= 1;
+
+ initial cvr_multi_read_hit = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ cvr_multi_read_hit <= 0;
+ else if (fm_rd_outstanding[0] > 2 && !rgrant[0][NS])
+ cvr_multi_read_hit <= 1;
+
+ always @(*)
+ cover(cvr_multi_write_hit);
+
+ always @(*)
+ cover(cvr_multi_read_hit);
+
+ always @(*)
+ cover(S_AXI_ARESETN && cvr_multi_write_hit & mwgrant == 0 && M_AXI_BVALID == 0);
+
+ always @(*)
+ cover(S_AXI_ARESETN && cvr_multi_read_hit & mrgrant == 0 && M_AXI_RVALID == 0);
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Negation check
+ // {{{
+ // Pick a particular value. Assume the value doesn't show up on the
+ // input. Prove it doesn't show up on the output. This will check for
+ // ...
+ // 1. Stuck bits on the output channel
+ // 2. Cross-talk between channels
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ (* anyconst *) reg [LGNM-1:0] f_const_source;
+ (* anyconst *) reg [AW-1:0] f_const_addr;
+ (* anyconst *) reg [AW-1:0] f_const_addr_n;
+ (* anyconst *) reg [DW-1:0] f_const_data_n;
+ (* anyconst *) reg [DW/8-1:0] f_const_strb_n;
+ (* anyconst *) reg [3-1:0] f_const_prot_n;
+ (* anyconst *) reg [2-1:0] f_const_resp_n;
+ reg [LGNS-1:0] f_const_slave;
+
+ always @(*)
+ assume(f_const_source < NM);
+ always @(*)
+ begin
+ f_const_slave = NS;
+ for(iM=0; iM<NS; iM=iM+1)
+ begin
+ if (((f_const_addr ^ SLAVE_ADDR[iM*AW+:AW])
+ &SLAVE_MASK[iM*AW+:AW])==0)
+ f_const_slave = iM;
+ end
+
+ assume(f_const_slave < NS);
+ end
+
+ reg [AW-1:0] f_awaddr;
+ reg [AW-1:0] f_araddr;
+ always @(*)
+ f_awaddr = S_AXI_AWADDR[f_const_source * AW +: AW];
+ always @(*)
+ f_araddr = S_AXI_ARADDR[f_const_source * AW +: AW];
+
+ // The assumption check: assume our negated values are not found on
+ // the inputs
+ always @(*)
+ begin
+ if (S_AXI_AWVALID[f_const_source])
+ begin
+ assume(f_awaddr != f_const_addr_n);
+ assume(S_AXI_AWPROT[f_const_source*3+:3] != f_const_prot_n);
+ end
+ if (m_wvalid)
+ begin
+ assume(m_wdata[f_const_source] != f_const_data_n);
+ assume(m_wstrb[f_const_source] != f_const_strb_n);
+ end
+ if (S_AXI_ARVALID[f_const_source])
+ begin
+ assume(f_araddr != f_const_addr_n);
+ assume(S_AXI_ARPROT[f_const_source*3+:3] != f_const_prot_n);
+ end
+
+ if (M_AXI_BVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+ begin
+ assume(m_axi_bresp[f_const_slave] != f_const_resp_n);
+ end
+
+ if (M_AXI_RVALID[f_const_slave] && rgrant[f_const_source][f_const_slave])
+ begin
+ assume(m_axi_rdata[f_const_slave] != f_const_data_n);
+ assume(m_axi_rresp[f_const_slave] != f_const_resp_n);
+ end
+ end
+
+ // Proof check: Prove these values are not found on our outputs
+ always @(*)
+ begin
+ if (skd_awvalid[f_const_source])
+ begin
+ assert(skd_awaddr[f_const_source] != f_const_addr_n);
+ assert(skd_awprot[f_const_source] != f_const_prot_n);
+ end
+ if (dcd_awvalid[f_const_source])
+ begin
+ assert(m_awaddr[f_const_source] != f_const_addr_n);
+ assert(m_awprot[f_const_source] != f_const_prot_n);
+ end
+ if (M_AXI_AWVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+ begin
+ assert(M_AXI_AWADDR[f_const_slave*AW+:AW] != f_const_addr_n);
+ assert(M_AXI_AWPROT[f_const_slave*3+:3] != f_const_prot_n);
+ end
+ if (M_AXI_WVALID[f_const_slave] && wgrant[f_const_source][f_const_slave])
+ begin
+ assert(M_AXI_WDATA[f_const_slave*DW+:DW] != f_const_data_n);
+ assert(M_AXI_WSTRB[f_const_slave*(DW/8)+:(DW/8)] != f_const_strb_n);
+ end
+ if (skd_arvalid[f_const_source])
+ begin
+ assert(skd_araddr[f_const_source] != f_const_addr_n);
+ assert(skd_arprot[f_const_source] != f_const_prot_n);
+ end
+ if (dcd_arvalid[f_const_source])
+ begin
+ assert(m_araddr[f_const_source] != f_const_addr_n);
+ assert(m_arprot[f_const_source] != f_const_prot_n);
+ end
+ if (M_AXI_ARVALID[f_const_slave] && rgrant[f_const_source][f_const_slave])
+ begin
+ assert(M_AXI_ARADDR[f_const_slave*AW+:AW] != f_const_addr_n);
+ assert(M_AXI_ARPROT[f_const_slave*3+:3] != f_const_prot_n);
+ end
+ //
+ if (r_bvalid[f_const_source] && wgrant[f_const_source][f_const_slave])
+ assert(r_bresp[f_const_source] != f_const_resp_n);
+ if (S_AXI_BVALID[f_const_source] && wgrant[f_const_source][f_const_slave])
+ assert(S_AXI_BRESP[f_const_source*2+:2] != f_const_resp_n);
+ if (r_rvalid[f_const_source] && rgrant[f_const_source][f_const_slave])
+ begin
+ assert(r_rresp[f_const_source] != f_const_resp_n);
+ assert(r_rdata[f_const_source] != f_const_data_n);
+ end
+ if (S_AXI_RVALID[f_const_source] && rgrant[f_const_source][f_const_slave])
+ begin
+ assert(S_AXI_RRESP[f_const_source*2+:2]!=f_const_resp_n);
+ assert(S_AXI_RDATA[f_const_source*DW+:DW]!=f_const_data_n);
+ end
+ end
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // (Careless) constraining assumptions
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ generate for(N=0; N<NM; N=N+1)
+ begin
+
+ end endgenerate
+ // }}}
+`endif
+// }}}
+endmodule
+`ifndef YOSYS
+`default_nettype wire
+`endif