summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axilempty.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axilempty.v')
-rw-r--r--rtl/wb2axip/axilempty.v371
1 files changed, 371 insertions, 0 deletions
diff --git a/rtl/wb2axip/axilempty.v b/rtl/wb2axip/axilempty.v
new file mode 100644
index 0000000..f429d69
--- /dev/null
+++ b/rtl/wb2axip/axilempty.v
@@ -0,0 +1,371 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// 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