//////////////////////////////////////////////////////////////////////////////// // // Filename: axilempty.v // {{{ // Project: WB2AXIPSP: bus bridges and other odds and ends // // Purpose: Modifies the simple AXI-lite interface to be an empty shell // // This is useful for a bus with masters but no slaves. When used, // the interconnect can connect those masters to this slave to know // that requests will still be properly handled--and get proper error // returns. // // Creator: Dan Gisselquist, Ph.D. // Gisselquist Technology, LLC // //////////////////////////////////////////////////////////////////////////////// // }}} // Copyright (C) 2020-2024, Gisselquist Technology, LLC // {{{ // // This file is part of the WB2AXIP project. // // The WB2AXIP project contains free software and gateware, licensed under the // Apache License, Version 2.0 (the "License"). You may not use this project, // or this file, except in compliance with the License. You may obtain a copy // of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. // //////////////////////////////////////////////////////////////////////////////// // `default_nettype none // }}} module axilempty #( // {{{ // // Size of the AXI-lite bus. These are fixed, since 1) AXI-lite // is fixed at a width of 32-bits by Xilinx def'n, and 2) since // we only ever have 4 configuration words. // Verilator lint_off UNUSED parameter C_AXI_ADDR_WIDTH = 4, // Verilator lint_on UNUSED localparam C_AXI_DATA_WIDTH = 32, parameter [0:0] OPT_SKIDBUFFER = 1'b0, 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 S_AXI_WVALID, output wire S_AXI_WREADY, // output wire S_AXI_BVALID, input wire S_AXI_BREADY, output wire [1:0] S_AXI_BRESP, // input wire S_AXI_ARVALID, output wire S_AXI_ARREADY, // output wire S_AXI_RVALID, input wire S_AXI_RREADY, output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, output wire [1:0] S_AXI_RRESP // }}} ); //////////////////////////////////////////////////////////////////////// // // Register/wire signal declarations // //////////////////////////////////////////////////////////////////////// // // {{{ wire i_reset = !S_AXI_ARESETN; wire axil_write_ready; // reg axil_bvalid; // wire axil_read_ready; reg axil_read_valid; //////////////////////////////////////////////////////////////////////// // // AXI-lite signaling // //////////////////////////////////////////////////////////////////////// // // {{{ // // Write signaling // // {{{ generate if (OPT_SKIDBUFFER) begin : SKIDBUFFER_WRITE wire awskd_valid, wskd_valid, awskd_unused, wskd_unused; skidbuffer #(.OPT_OUTREG(0), .OPT_LOWPOWER(OPT_LOWPOWER), .DW(1)) axilawskid(// .i_clk(S_AXI_ACLK), .i_reset(i_reset), .i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY), .i_data(1'b0), .o_valid(awskd_valid), .i_ready(axil_write_ready), .o_data(awskd_unused)); `ifdef FORMAL always @(*) if (awskd_valid) assert(awskd_unused == 0); `endif skidbuffer #(.OPT_OUTREG(0), .OPT_LOWPOWER(OPT_LOWPOWER), .DW(1)) axilwskid(// .i_clk(S_AXI_ACLK), .i_reset(i_reset), .i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY), .i_data({ 1'b0 }), .o_valid(wskd_valid), .i_ready(axil_write_ready), .o_data(wskd_unused)); `ifdef FORMAL always @(*) if (wskd_valid) assert(wskd_unused == 0); `endif assign axil_write_ready = awskd_valid && wskd_valid && (!S_AXI_BVALID || S_AXI_BREADY); // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0, awskd_unused, wskd_unused }; // Verilator lint_on UNUSED end else begin : SIMPLE_WRITES reg axil_awready; initial axil_awready = 1'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axil_awready <= 1'b0; else axil_awready <= !axil_awready && (S_AXI_AWVALID && S_AXI_WVALID) && (!S_AXI_BVALID || S_AXI_BREADY); assign S_AXI_AWREADY = axil_awready; assign S_AXI_WREADY = axil_awready; assign axil_write_ready = axil_awready; end endgenerate initial axil_bvalid = 0; always @(posedge S_AXI_ACLK) if (i_reset) axil_bvalid <= 0; else if (axil_write_ready) axil_bvalid <= 1; else if (S_AXI_BREADY) axil_bvalid <= 0; assign S_AXI_BVALID = axil_bvalid; assign S_AXI_BRESP = 2'b11; // }}} // // Read signaling // // {{{ generate if (OPT_SKIDBUFFER) begin : SKIDBUFFER_READ wire arskd_valid, arskd_unused; skidbuffer #(.OPT_OUTREG(0), .OPT_LOWPOWER(OPT_LOWPOWER), .DW(1)) axilarskid(// .i_clk(S_AXI_ACLK), .i_reset(i_reset), .i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY), .i_data( 1'b0 ), .o_valid(arskd_valid), .i_ready(axil_read_ready), .o_data(arskd_unused)); assign axil_read_ready = arskd_valid && (!axil_read_valid || S_AXI_RREADY); `ifdef FORMAL always @(*) if (arskd_valid) assert(arskd_unused == 0); `endif // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0, arskd_unused }; // Verilator lint_on UNUSED end else begin : SIMPLE_READS reg axil_arready; always @(*) axil_arready = !S_AXI_RVALID; assign S_AXI_ARREADY = axil_arready; assign axil_read_ready = (S_AXI_ARVALID && S_AXI_ARREADY); end endgenerate initial axil_read_valid = 1'b0; always @(posedge S_AXI_ACLK) if (i_reset) axil_read_valid <= 1'b0; else if (axil_read_ready) axil_read_valid <= 1'b1; else if (S_AXI_RREADY) axil_read_valid <= 1'b0; assign S_AXI_RVALID = axil_read_valid; assign S_AXI_RDATA = 0; assign S_AXI_RRESP = 2'b11; // }}} // }}} //////////////////////////////////////////////////////////////////////// // // AXI-lite register logic // //////////////////////////////////////////////////////////////////////// // // {{{ // }}} // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0 }; // Verilator lint_on UNUSED // }}} `ifdef FORMAL //////////////////////////////////////////////////////////////////////// // // Formal properties used in verfiying this core // //////////////////////////////////////////////////////////////////////// // // {{{ reg f_past_valid; initial f_past_valid = 0; always @(posedge S_AXI_ACLK) f_past_valid <= 1; //////////////////////////////////////////////////////////////////////// // // The AXI-lite control interface // //////////////////////////////////////////////////////////////////////// // // {{{ localparam F_AXIL_LGDEPTH = 4; wire [F_AXIL_LGDEPTH-1:0] faxil_rd_outstanding, faxil_wr_outstanding, faxil_awr_outstanding; faxil_slave #( // {{{ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH), .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH), .F_LGDEPTH(F_AXIL_LGDEPTH), .F_AXI_MAXWAIT(2), .F_AXI_MAXDELAY(2), .F_AXI_MAXRSTALL(3), .F_OPT_COVER_BURST(0) // }}} ) faxil( // {{{ .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({(C_AXI_ADDR_WIDTH){1'b0}}), .i_axi_awprot( 3'h0), // .i_axi_wvalid(S_AXI_WVALID), .i_axi_wready(S_AXI_WREADY), .i_axi_wdata( {(C_AXI_DATA_WIDTH){1'b0}}), .i_axi_wstrb( {(C_AXI_DATA_WIDTH/8){1'b0}}), // .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( {(C_AXI_ADDR_WIDTH){1'b0}}), .i_axi_arprot( 3'h0), // .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(faxil_rd_outstanding), .f_axi_wr_outstanding(faxil_wr_outstanding), .f_axi_awr_outstanding(faxil_awr_outstanding) // }}} ); always @(*) if (OPT_SKIDBUFFER) begin assert(faxil_awr_outstanding== (S_AXI_BVALID ? 1:0) +(S_AXI_AWREADY ? 0:1)); assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0) +(S_AXI_WREADY ? 0:1)); assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0) +(S_AXI_ARREADY ? 0:1)); end else begin assert(faxil_wr_outstanding == (S_AXI_BVALID ? 1:0)); assert(faxil_awr_outstanding == faxil_wr_outstanding); assert(faxil_rd_outstanding == (S_AXI_RVALID ? 1:0)); end // // Check that our low-power only logic works by verifying that anytime // S_AXI_RVALID is inactive, then the outgoing data is also zero. // always @(*) assert(S_AXI_RDATA == 0); always @(*) assert(S_AXI_RRESP == 2'b11); always @(*) assert(S_AXI_BRESP == 2'b11); // }}} //////////////////////////////////////////////////////////////////////// // // Cover checks // //////////////////////////////////////////////////////////////////////// // // {{{ // While there are already cover properties in the formal property // set above, you'll probably still want to cover something // application specific here // }}} // }}} `endif endmodule