diff options
Diffstat (limited to 'rtl/wb2axip/axildouble.v')
| -rw-r--r-- | rtl/wb2axip/axildouble.v | 734 |
1 files changed, 734 insertions, 0 deletions
diff --git a/rtl/wb2axip/axildouble.v b/rtl/wb2axip/axildouble.v new file mode 100644 index 0000000..ddaedb6 --- /dev/null +++ b/rtl/wb2axip/axildouble.v @@ -0,0 +1,734 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: axildouble.v +// {{{ +// Project: WB2AXIPSP: bus bridges and other odds and ends +// +// Purpose: Create a special slave which can be used to reduce crossbar +// logic for multiple simplified slaves. This is a companion +// core to the similar axilsingle core, but allowing the slave to +// decode the clock between multiple possible addresses. +// +// To use this, the slave must follow specific (simplified AXI) rules: +// +// Write interface +// 1. The slave must guarantee that AWREADY == WREADY = 1 +// (This core doesn't have AWREADY or WREADY inputs) +// 2. The slave must also guarantee that BVALID == $past(AWVALID) +// (This core internally generates BVALID) +// 3. The controller will guarantee that AWVALID == WVALID +// (You can connect AWVALID to WVALID when connecting to your core) +// 4. The controller will also guarantee that BREADY = 1 +// (This core doesn't have a BVALID input) +// +// Read interface +// 1. The slave must guarantee that ARREADY == 1 +// (This core doesn't have an ARREADY input) +// 2. The slave must also guarantee that RVALID == $past(ARVALID) +// (This core doesn't have an RVALID input, trusting the slave +// instead) +// 3. The controller will guarantee that RREADY = 1 +// (This core doesn't have an RREADY output) +// +// +// Why? This simplifies slave logic. Slaves may interact with the bus +// using only the logic below: +// +// always @(posedge S_AXI_ACLK) +// if (AWVALID) case(AWADDR) +// R1: slvreg_1 <= WDATA; +// R2: slvreg_2 <= WDATA; +// R3: slvreg_3 <= WDATA; +// R4: slvreg_4 <= WDATA; +// endcase +// +// always @(*) +// BRESP = 2'b00; +// +// always @(posedge S_AXI_ACLK) +// if (ARVALID) +// case(ARADDR) +// R1: RDATA <= slvreg_1; +// R2: RDATA <= slvreg_2; +// R3: RDATA <= slvreg_3; +// R4: RDATA <= slvreg_4; +// endcase +// +// always @(*) +// RRESP = 2'b00; +// +// This core will then keep track of the more complex bus logic, +// simplifying both slaves and connection logic. Slaves with the more +// complicated (and proper/accurate) logic, that follow the rules above, +// should have no problems with this additional logic. +// +// Performance: +// +// This core can sustain one read/write per clock as long as the upstream +// AXI master keeps S_AXI_[BR]READY high. If S_AXI_[BR]READY ever drops, +// there's some flexibility provided by the return FIFO, so the master +// might not notice a drop in throughput until the FIFO fills. +// +// The more practical performance measure is the latency of this core. +// That I've measured at four clocks. +// +// 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 +// `ifdef VERILATOR +// `define FORMAL +// `endif +// }}} +module axildouble #( + // {{{ + parameter integer C_AXI_DATA_WIDTH = 32, + parameter integer C_AXI_ADDR_WIDTH = 32, + // + // NS is the number of slave interfaces + parameter NS = 8, + // + // + parameter [NS*C_AXI_ADDR_WIDTH-1:0] SLAVE_ADDR = { + { 3'b111, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b110, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b101, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b100, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b011, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b010, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 4'b0001,{(C_AXI_ADDR_WIDTH-4){1'b0}} }, + { 4'b0000,{(C_AXI_ADDR_WIDTH-4){1'b0}} } }, + // + // + parameter [NS*C_AXI_ADDR_WIDTH-1:0] SLAVE_MASK = + (NS <= 1) ? 0 + : { {(NS-2){ 3'b111,{(C_AXI_ADDR_WIDTH-3){1'b0}} }}, + {(2){ 4'b1111,{(C_AXI_ADDR_WIDTH-4){1'b0}} }} + }, + // + // + // LGFLEN specifies the log (based two) of the number of + // transactions that may need to be held outstanding internally. + // If you really want high throughput, and if you expect any + // back pressure at all, then increase LGFLEN. Otherwise the + // default value of 3 (FIFO size = 8) should be sufficient + // to maintain full loading + parameter LGFLEN=3, + // + // 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 = 0 + // }}} + ) ( + // {{{ + input wire S_AXI_ACLK, + input wire S_AXI_ARESETN, + // + input wire S_AXI_AWVALID, + output wire S_AXI_AWREADY, + input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, + input wire [3-1:0] S_AXI_AWPROT, + // + input wire S_AXI_WVALID, + output wire S_AXI_WREADY, + input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA, + input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB, + // + output wire [2-1:0] S_AXI_BRESP, + output wire S_AXI_BVALID, + input wire S_AXI_BREADY, + // + input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR, + input wire [3-1:0] S_AXI_ARPROT, + input wire S_AXI_ARVALID, + output wire S_AXI_ARREADY, + // + output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, + output wire [2-1:0] S_AXI_RRESP, + output wire S_AXI_RVALID, + input wire S_AXI_RREADY, + // + // + // + output wire [NS-1:0] M_AXI_AWVALID, + output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, + output wire [3-1:0] M_AXI_AWPROT, + // + output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA, + output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB, + // + input wire [NS*2-1:0] M_AXI_BRESP, + // + output wire [NS-1:0] M_AXI_ARVALID, + output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, + output wire [3-1:0] M_AXI_ARPROT, + // + input wire [NS*C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA, + input wire [NS*2-1:0] M_AXI_RRESP + // }}} + ); + + // + // AW, and DW, are short-hand abbreviations used locally. + localparam AW = C_AXI_ADDR_WIDTH; + localparam DW = C_AXI_DATA_WIDTH; + localparam LGNS = $clog2(NS); + // + localparam INTERCONNECT_ERROR = 2'b11; + + //////////////////////////////////////////////////////////////////////// + // + // Write logic: + // + //////////////////////////////////////////////////////////////////////// + // + // + wire awskid_valid, bffull, bempty, write_awskidready, + dcd_awvalid; + reg write_bvalid, write_response; + reg bfull, write_wready, write_no_index; + wire [NS:0] wdecode; + wire [AW-1:0] awskid_addr; + wire [AW-1:0] m_awaddr; + reg [LGNS-1:0] write_windex, write_bindex; + wire [3-1:0] awskid_prot, m_axi_awprot; + wire [LGFLEN:0] bfill; + reg [LGFLEN:0] write_count; + reg [1:0] write_resp; + integer k; + + skidbuffer #(.OPT_LOWPOWER(OPT_LOWPOWER), .OPT_OUTREG(0), + .DW(AW+3)) + awskid( .i_clk(S_AXI_ACLK), + .i_reset(!S_AXI_ARESETN), + .i_valid(S_AXI_AWVALID), + .o_ready(S_AXI_AWREADY), + .i_data({ S_AXI_AWPROT, S_AXI_AWADDR }), + .o_valid(awskid_valid), .i_ready(write_awskidready), + .o_data({ awskid_prot, awskid_addr })); + + wire awskd_stall; + + addrdecode #(.AW(AW), .DW(3), .NS(NS), + .SLAVE_ADDR(SLAVE_ADDR), + .SLAVE_MASK(SLAVE_MASK), + .OPT_REGISTERED(1'b1)) + wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), + .i_valid(awskid_valid && write_awskidready), .o_stall(awskd_stall), + .i_addr(awskid_addr), + .i_data(awskid_prot), + .o_valid(dcd_awvalid), .i_stall(!S_AXI_WVALID), + .o_decode(wdecode), .o_addr(m_awaddr), + .o_data(m_axi_awprot)); + + always @(*) + write_wready = dcd_awvalid; + assign S_AXI_WREADY = write_wready; + assign M_AXI_AWVALID = (S_AXI_WVALID) ? wdecode[NS-1:0] : 0; + assign M_AXI_AWADDR = m_awaddr; + assign M_AXI_AWPROT = m_axi_awprot; + assign M_AXI_WDATA = S_AXI_WDATA; + assign M_AXI_WSTRB = S_AXI_WSTRB; + assign write_awskidready = (S_AXI_WVALID || !S_AXI_WREADY) && !bfull; + + always @(*) + begin + write_windex = 0; + for(k=0; k<NS; k=k+1) + if (wdecode[k]) + write_windex = write_windex | k[LGNS-1:0]; + end + + always @(posedge S_AXI_ACLK) + begin + write_bindex <= write_windex; + write_no_index <= wdecode[NS]; + end + + initial { write_response, write_bvalid } = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + { write_response, write_bvalid } <= 0; + else + { write_response, write_bvalid } + <= { write_bvalid, (S_AXI_WVALID && S_AXI_WREADY) }; + + always @(posedge S_AXI_ACLK) + if (write_no_index) + write_resp <= INTERCONNECT_ERROR; + else + write_resp <= M_AXI_BRESP[2*write_bindex +: 2]; + + initial write_count = 0; + initial bfull = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + begin + write_count <= 0; + bfull <= 0; + end else case({ (awskid_valid && write_awskidready), + (S_AXI_BVALID & S_AXI_BREADY) }) + 2'b01: begin + write_count <= write_count - 1; + bfull <= 1'b0; + end + 2'b10: begin + write_count <= write_count + 1; + bfull <= (&write_count[LGFLEN-1:0]); + end + default: begin end + endcase + +`ifdef FORMAL + always @(*) + assert(write_count <= { 1'b1, {(LGFLEN){1'b0}} }); + always @(*) + assert(bfull == (write_count == { 1'b1, {(LGFLEN){1'b0}} })); +`endif + + sfifo #(.BW(2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN)) + bfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), + .i_wr(write_response), .i_data(write_resp), .o_full(bffull), + .o_fill(bfill), + .i_rd(S_AXI_BVALID && S_AXI_BREADY), .o_data(S_AXI_BRESP), + .o_empty(bempty)); + +`ifdef FORMAL + always @(*) + assert(write_count == bfill + + (write_response ? 1:0) + + (write_bvalid ? 1:0) + + (write_wready ? 1:0)); + +`ifdef VERIFIC + always @(*) + if (bfifo.f_first_in_fifo) + assert(bfifo.f_first_data != 2'b01); + always @(*) + if (bfifo.f_second_in_fifo) + assert(bfifo.f_second_data != 2'b01); + always @(*) + if (!bempty && (!bfifo.f_first_in_fifo + || bfifo.rd_addr != bfifo.f_first_addr) + &&(!bfifo.f_second_in_fifo + || bfifo.rd_addr != bfifo.f_second_addr)) + assume(S_AXI_BRESP != 2'b01); +`else + always @(*) + if (!bempty) + assume(S_AXI_BRESP != 2'b01); +`endif +`endif + + assign S_AXI_BVALID = !bempty; + +`ifdef FORMAL + always @(*) + assert(!bffull || !write_bvalid); +`endif + + //////////////////////////////////////////////////////////////////////// + // + // Read logic + // + //////////////////////////////////////////////////////////////////////// + // + // + wire rempty, rdfull; + wire [LGFLEN:0] rfill; + reg [LGNS-1:0] read_index, last_read_index; + reg [1:0] read_resp; + reg [DW-1:0] read_rdata; + wire read_rwait, arskd_stall; + reg read_rvalid, read_result, read_no_index; + wire [AW-1:0] m_araddr; + wire [3-1:0] m_axi_arprot; + wire [NS:0] rdecode; + + addrdecode #(.AW(AW), .DW(3), .NS(NS), + .SLAVE_ADDR(SLAVE_ADDR), + .SLAVE_MASK(SLAVE_MASK), + .OPT_REGISTERED(1'b1)) + rdaddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), + .i_valid(S_AXI_ARVALID && S_AXI_ARREADY), .o_stall(arskd_stall), + .i_addr(S_AXI_ARADDR), .i_data(S_AXI_ARPROT), + .o_valid(read_rwait), .i_stall(1'b0), + .o_decode(rdecode), .o_addr(m_araddr), + .o_data(m_axi_arprot)); + + assign M_AXI_ARVALID = rdecode[NS-1:0]; + assign M_AXI_ARADDR = m_araddr; + assign M_AXI_ARPROT = m_axi_arprot; + + initial { read_result, read_rvalid } = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + { read_result, read_rvalid } <= 2'b00; + else + { read_result, read_rvalid } <= { read_rvalid, read_rwait }; + + always @(*) + begin + read_index = 0; + + for(k=0; k<NS; k=k+1) + if (rdecode[k]) + read_index = read_index | k[LGNS-1:0]; + end + + always @(posedge S_AXI_ACLK) + last_read_index <= read_index; + + always @(posedge S_AXI_ACLK) + read_no_index <= rdecode[NS]; + + always @(posedge S_AXI_ACLK) + read_rdata <= M_AXI_RDATA[DW*last_read_index +: DW]; + + always @(posedge S_AXI_ACLK) + if (read_no_index) + read_resp <= INTERCONNECT_ERROR; + else + read_resp <= M_AXI_RRESP[2*last_read_index +: 2]; + + reg read_full; + reg [LGFLEN:0] read_count; + + initial { read_count, read_full } = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + { read_count, read_full } <= 0; + else case({ S_AXI_ARVALID & S_AXI_ARREADY, S_AXI_RVALID & S_AXI_RREADY}) + 2'b10: begin + read_count <= read_count + 1; + read_full <= &read_count[LGFLEN-1:0]; + end + 2'b01: begin + read_count <= read_count - 1; + read_full <= 1'b0; + end + default: begin end + endcase + +`ifdef FORMAL + always @(*) + assert(read_count <= { 1'b1, {(LGFLEN){1'b0}} }); + always @(*) + assert(read_full == (read_count == { 1'b1, {(LGFLEN){1'b0}} })); +`endif + assign S_AXI_ARREADY = !read_full; + + sfifo #(.BW(DW+2), .OPT_ASYNC_READ(0), .LGFLEN(LGFLEN)) + rfifo ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), + .i_wr(read_result), .i_data({ read_rdata, read_resp }), + .o_full(rdfull), .o_fill(rfill), + .i_rd(S_AXI_RVALID && S_AXI_RREADY), + .o_data({ S_AXI_RDATA, S_AXI_RRESP }),.o_empty(rempty)); + +`ifdef FORMAL + always @(*) + assert(read_count == rfill + read_result + read_rvalid + read_rwait); +`ifdef VERIFIC + always @(*) + if (rfifo.f_first_in_fifo) + assert(rfifo.f_first_data[1:0] != 2'b01); + always @(*) + if (rfifo.f_second_in_fifo) + assert(rfifo.f_second_data[1:0] != 2'b01); + always @(*) + if (!rempty && (!rfifo.f_first_in_fifo + || rfifo.rd_addr != rfifo.f_first_addr) + &&(!rfifo.f_second_in_fifo + || rfifo.rd_addr != rfifo.f_second_addr)) + assume(S_AXI_RRESP != 2'b01); +`else + always @(*) + if (!rempty) + assume(S_AXI_RRESP != 2'b01); +`endif +`endif + + assign S_AXI_RVALID = !rempty; + + // verilator lint_off UNUSED + wire unused; + assign unused = &{ 1'b0, + bffull, rdfull, bfill, rfill, + awskd_stall, arskd_stall }; + // verilator lint_on UNUSED +`ifdef FORMAL + localparam F_LGDEPTH = LGFLEN+1; + reg f_past_valid; + reg [F_LGDEPTH-1:0] count_awr_outstanding, count_wr_outstanding, + count_rd_outstanding; + + + wire [(F_LGDEPTH-1):0] f_axi_awr_outstanding, + f_axi_wr_outstanding, + f_axi_rd_outstanding; + + wire [1:0] fm_axi_awr_outstanding [0:NS-1]; + wire [1:0] fm_axi_wr_outstanding [0:NS-1]; + wire [1:0] fm_axi_rd_outstanding [0:NS-1]; + + reg [NS-1:0] m_axi_rvalid, m_axi_bvalid; + + faxil_slave #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), + .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), + // .F_OPT_NO_READS(1'b0), + // .F_OPT_NO_WRITES(1'b0), + .F_OPT_XILINX(1), + .F_LGDEPTH(F_LGDEPTH)) + properties ( + .i_clk(S_AXI_ACLK), + .i_axi_reset_n(S_AXI_ARESETN), + // + .i_axi_awvalid(S_AXI_AWVALID), + .i_axi_awready(S_AXI_AWREADY), + .i_axi_awaddr(S_AXI_AWADDR), + .i_axi_awprot(S_AXI_AWPROT), + // + .i_axi_wvalid(S_AXI_WVALID), + .i_axi_wready(S_AXI_WREADY), + .i_axi_wdata(S_AXI_WDATA), + .i_axi_wstrb(S_AXI_WSTRB), + // + .i_axi_bvalid(S_AXI_BVALID), + .i_axi_bready(S_AXI_BREADY), + .i_axi_bresp(S_AXI_BRESP), + // + .i_axi_arvalid(S_AXI_ARVALID), + .i_axi_arready(S_AXI_ARREADY), + .i_axi_araddr(S_AXI_ARADDR), + .i_axi_arprot(S_AXI_ARPROT), + // + .i_axi_rvalid(S_AXI_RVALID), + .i_axi_rready(S_AXI_RREADY), + .i_axi_rdata(S_AXI_RDATA), + .i_axi_rresp(S_AXI_RRESP), + // + .f_axi_rd_outstanding(f_axi_rd_outstanding), + .f_axi_wr_outstanding(f_axi_wr_outstanding), + .f_axi_awr_outstanding(f_axi_awr_outstanding)); + + initial f_past_valid = 1'b0; + always @(posedge S_AXI_ACLK) + f_past_valid <= 1'b1; + + genvar M; + generate for(M=0; M<NS; M=M+1) + begin : CONSTRAIN_SLAVE_INTERACTIONS + + faxil_master #(// .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), + .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), + .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), + // .F_OPT_NO_READS(1'b0), + // .F_OPT_NO_WRITES(1'b0), + .F_OPT_NO_RESET(1'b1), + .F_LGDEPTH(2)) + properties ( + .i_clk(S_AXI_ACLK), + .i_axi_reset_n(S_AXI_ARESETN), + // + .i_axi_awvalid(M_AXI_AWVALID[M]), + .i_axi_awready(1'b1), + .i_axi_awaddr(M_AXI_AWADDR), + .i_axi_awprot(M_AXI_AWPROT), + // + .i_axi_wvalid(M_AXI_AWVALID[M]), + .i_axi_wready(1'b1), + .i_axi_wdata(M_AXI_WDATA[C_AXI_DATA_WIDTH-1:0]), + .i_axi_wstrb(M_AXI_WSTRB[C_AXI_DATA_WIDTH/8-1:0]), + // + .i_axi_bvalid(m_axi_bvalid[M]), + .i_axi_bready(1'b1), + .i_axi_bresp(M_AXI_BRESP[2*M +: 2]), + // + .i_axi_arvalid(M_AXI_ARVALID[M]), + .i_axi_arready(1'b1), + .i_axi_araddr(M_AXI_ARADDR), + .i_axi_arprot(M_AXI_ARPROT), + // + .i_axi_rdata(M_AXI_RDATA[M*C_AXI_DATA_WIDTH +: C_AXI_DATA_WIDTH]), + .i_axi_rresp(M_AXI_RRESP[2*M +: 2]), + .i_axi_rvalid(m_axi_rvalid[M]), + .i_axi_rready(1'b1), + // + .f_axi_rd_outstanding(fm_axi_rd_outstanding[M]), + .f_axi_wr_outstanding(fm_axi_wr_outstanding[M]), + .f_axi_awr_outstanding(fm_axi_awr_outstanding[M])); + + initial m_axi_bvalid <= 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + m_axi_bvalid[M] <= 1'b0; + else + m_axi_bvalid[M] <= M_AXI_AWVALID[M]; + + initial m_axi_rvalid[M] <= 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + m_axi_rvalid[M] <= 1'b0; + else + m_axi_rvalid[M] <= M_AXI_ARVALID[M]; + + always @(*) + assert(fm_axi_awr_outstanding[M] == fm_axi_wr_outstanding[M]); + + always @(*) + assert(fm_axi_wr_outstanding[M]== (m_axi_bvalid[M] ? 1:0)); + + always @(*) + assert(fm_axi_rd_outstanding[M]== (m_axi_rvalid[M] ? 1:0)); + end endgenerate + + //////////////////////////////////////////////////////////////////////// + // + // Properties necessary to pass induction + // + //////////////////////////////////////////////////////////////////////// + // + // + always @(*) + assert(S_AXI_WREADY == (wdecode != 0)); +`ifdef VERIFIC + always @(*) + assert($onehot0(M_AXI_AWVALID)); + + always @(*) + assert($onehot0(m_axi_bvalid)); + + always @(*) + assert($onehot0(m_axi_rvalid)); +`endif + always @(*) + begin + count_awr_outstanding = 0; + if (!S_AXI_AWREADY) + count_awr_outstanding = count_awr_outstanding + 1; + if (write_wready) + count_awr_outstanding = count_awr_outstanding + 1; + if (write_bvalid) + count_awr_outstanding = count_awr_outstanding + 1; + if (write_response) + count_awr_outstanding = count_awr_outstanding + 1; + count_awr_outstanding = count_awr_outstanding + bfill; + end + + always @(*) + if (S_AXI_ARESETN) + assert(f_axi_awr_outstanding == count_awr_outstanding); + + always @(*) + begin + count_wr_outstanding = 0; + if (write_bvalid) + count_wr_outstanding = count_wr_outstanding + 1; + if (write_response) + count_wr_outstanding = count_wr_outstanding + 1; + count_wr_outstanding = count_wr_outstanding + bfill; + end + + always @(*) + if (S_AXI_ARESETN) + assert(f_axi_wr_outstanding == count_wr_outstanding); + + // + // + // + always @(*) + begin + count_rd_outstanding = 0; + if (read_rwait) + count_rd_outstanding = count_rd_outstanding + 1; + if (read_rvalid) + count_rd_outstanding = count_rd_outstanding + 1; + if (read_result) + count_rd_outstanding = count_rd_outstanding + 1; + count_rd_outstanding = count_rd_outstanding + rfill; + end + + always @(*) + if (S_AXI_ARESETN) + assert(f_axi_rd_outstanding == count_rd_outstanding); + + + //////////////////////////////////////////////////////////////////////// + // + // Cover properties + // + //////////////////////////////////////////////////////////////////////// + // + // + reg [3:0] cvr_arvalids, cvr_awvalids, cvr_reads, cvr_writes; + + initial cvr_awvalids = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + cvr_awvalids <= 0; + else if (S_AXI_AWVALID && S_AXI_AWREADY && !(&cvr_awvalids)) + cvr_awvalids <= cvr_awvalids + 1; + + initial cvr_arvalids = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + cvr_arvalids <= 0; + else if (S_AXI_ARVALID && S_AXI_ARREADY && !(&cvr_arvalids)) + cvr_arvalids <= cvr_arvalids + 1; + + initial cvr_writes = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + cvr_writes <= 0; + else if (S_AXI_BVALID && S_AXI_BREADY && !(&cvr_writes)) + cvr_writes <= cvr_writes + 1; + + initial cvr_reads = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + cvr_reads <= 0; + else if (S_AXI_RVALID && S_AXI_RREADY && !(&cvr_arvalids)) + cvr_reads <= cvr_reads + 1; + + always @(*) + cover(cvr_awvalids > 4); + + always @(*) + cover(cvr_arvalids > 4); + + always @(*) + cover(cvr_reads > 4); + + always @(*) + cover(cvr_writes > 4); + + always @(*) + cover((cvr_writes > 4) && (cvr_reads > 4)); +`endif +endmodule +// `ifndef YOSYS +// `default_nettype wire +// `endif |
