| //////////////////////////////////////////////////////////////////////////////// |
| // |
| // 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, 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. |
| parameter C_AXI_ADDR_WIDTH = 4, |
| localparam C_AXI_DATA_WIDTH = 32, |
| parameter [0:0] OPT_SKIDBUFFER = 1'b0, |
| parameter [0:0] OPT_LOWPOWER = 0, |
| localparam ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3 |
| // }}} |
| ) ( |
| // {{{ |
| 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)); |
| |
| 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)); |
| |
| 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(C_AXI_ADDR_WIDTH-ADDRLSB)) |
| 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); |
| |
| // 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_awcache(4'h0), |
| .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_arcache(4'h0), |
| .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 |