summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axilite2axi.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axilite2axi.v')
-rw-r--r--rtl/wb2axip/axilite2axi.v374
1 files changed, 374 insertions, 0 deletions
diff --git a/rtl/wb2axip/axilite2axi.v b/rtl/wb2axip/axilite2axi.v
new file mode 100644
index 0000000..8b8adf3
--- /dev/null
+++ b/rtl/wb2axip/axilite2axi.v
@@ -0,0 +1,374 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axilite2axi.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose:
+//
+// 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 axilite2axi #(
+ // {{{
+ parameter C_AXI_ID_WIDTH = 4,
+ C_AXI_ADDR_WIDTH= 32,
+ C_AXI_DATA_WIDTH= 32,
+ parameter [C_AXI_ID_WIDTH-1:0] C_AXI_WRITE_ID = 0,
+ C_AXI_READ_ID = 0
+ // }}}
+ ) (
+ // {{{
+ input wire ACLK,
+ input wire ARESETN,
+ // Slave AXI interface
+ // {{{
+ // Slave write signals
+ 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,
+ // Slave write data signals
+ 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,
+ // Slave return write response
+ output wire S_AXI_BVALID,
+ input wire S_AXI_BREADY,
+ output wire [2-1:0] S_AXI_BRESP,
+ // Slave read signals
+ input wire S_AXI_ARVALID,
+ output wire S_AXI_ARREADY,
+ input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR,
+ input wire [3-1:0] S_AXI_ARPROT,
+ // Slave read data signals
+ output wire S_AXI_RVALID,
+ input wire S_AXI_RREADY,
+ output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA,
+ output wire [2-1:0] S_AXI_RRESP,
+ // }}}
+ // Master AXI interface
+ // {{{
+ // Master interface write address
+ output wire M_AXI_AWVALID,
+ input wire M_AXI_AWREADY,
+ output wire [C_AXI_ID_WIDTH-1:0] M_AXI_AWID,
+ output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR,
+ output wire [8-1:0] M_AXI_AWLEN,
+ output wire [3-1:0] M_AXI_AWSIZE,
+ output wire [2-1:0] M_AXI_AWBURST,
+ output wire M_AXI_AWLOCK,
+ output wire [4-1:0] M_AXI_AWCACHE,
+ output wire [3-1:0] M_AXI_AWPROT,
+ output wire [4-1:0] M_AXI_AWQOS,
+ // Master write data
+ output wire M_AXI_WVALID,
+ input wire M_AXI_WREADY,
+ output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA,
+ output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB,
+ output wire M_AXI_WLAST,
+ // Master write response
+ input wire M_AXI_BVALID,
+ output wire M_AXI_BREADY,
+ input wire [C_AXI_ID_WIDTH-1:0] M_AXI_BID,
+ input wire [1:0] M_AXI_BRESP,
+ // Master interface read address
+ output wire M_AXI_ARVALID,
+ input wire M_AXI_ARREADY,
+ output wire [C_AXI_ID_WIDTH-1:0] M_AXI_ARID,
+ output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR,
+ output wire [8-1:0] M_AXI_ARLEN,
+ output wire [3-1:0] M_AXI_ARSIZE,
+ output wire [2-1:0] M_AXI_ARBURST,
+ output wire M_AXI_ARLOCK,
+ output wire [4-1:0] M_AXI_ARCACHE,
+ output wire [3-1:0] M_AXI_ARPROT,
+ output wire [4-1:0] M_AXI_ARQOS,
+ // Master interface read data return
+ input wire M_AXI_RVALID,
+ output wire M_AXI_RREADY,
+ input wire [C_AXI_ID_WIDTH-1:0] M_AXI_RID,
+ input wire [C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA,
+ input wire M_AXI_RLAST,
+ input wire [2-1:0] M_AXI_RRESP
+ // }}}
+ // }}}
+ );
+
+ localparam ADDRLSB = $clog2(C_AXI_DATA_WIDTH)-3;
+ assign M_AXI_AWID = C_AXI_WRITE_ID;
+ assign M_AXI_AWADDR = S_AXI_AWADDR;
+ assign M_AXI_AWLEN = 0;
+ assign M_AXI_AWSIZE = ADDRLSB[2:0];
+ assign M_AXI_AWBURST = 0;
+ assign M_AXI_AWLOCK = 0;
+ assign M_AXI_AWCACHE = 4'b0011; // As recommended by Xilinx UG1037
+ assign M_AXI_AWPROT = S_AXI_AWPROT;
+ assign M_AXI_AWQOS = 0;
+ assign M_AXI_AWVALID = S_AXI_AWVALID;
+ assign S_AXI_AWREADY = M_AXI_AWREADY;
+ // Master write data
+ assign M_AXI_WDATA = S_AXI_WDATA;
+ assign M_AXI_WLAST = 1;
+ assign M_AXI_WSTRB = S_AXI_WSTRB;
+ assign M_AXI_WVALID = S_AXI_WVALID;
+ assign S_AXI_WREADY = M_AXI_WREADY;
+ // Master write response
+ assign S_AXI_BRESP = M_AXI_BRESP;
+ assign S_AXI_BVALID = M_AXI_BVALID;
+ assign M_AXI_BREADY = S_AXI_BREADY;
+ //
+ //
+ assign M_AXI_ARID = C_AXI_READ_ID;
+ assign M_AXI_ARADDR = S_AXI_ARADDR;
+ assign M_AXI_ARLEN = 0;
+ assign M_AXI_ARSIZE = ADDRLSB[2:0];
+ assign M_AXI_ARBURST = 0;
+ assign M_AXI_ARLOCK = 0;
+ assign M_AXI_ARCACHE = 4'b0011; // As recommended by Xilinx UG1037
+ assign M_AXI_ARPROT = S_AXI_ARPROT;
+ assign M_AXI_ARQOS = 0;
+ assign M_AXI_ARVALID = S_AXI_ARVALID;
+ assign S_AXI_ARREADY = M_AXI_ARREADY;
+ //
+ assign S_AXI_RDATA = M_AXI_RDATA;
+ assign S_AXI_RRESP = M_AXI_RRESP;
+ assign S_AXI_RVALID = M_AXI_RVALID;
+ assign M_AXI_RREADY = S_AXI_RREADY;
+
+ // Make Verilator happy
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, ACLK, ARESETN, M_AXI_RLAST, M_AXI_RID, M_AXI_BID };
+ // Verilator lint_on UNUSED
+
+`ifdef FORMAL
+ //
+ // The following are some of the properties used to verify this design
+ //
+
+ localparam F_LGDEPTH = 10;
+
+ wire [F_LGDEPTH-1:0] faxil_awr_outstanding,
+ faxil_wr_outstanding, faxil_rd_outstanding;
+
+ faxil_slave #(
+ .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .F_LGDEPTH(10),
+ .F_AXI_MAXRSTALL(4),
+ .F_AXI_MAXWAIT(9),
+ .F_AXI_MAXDELAY(0)
+ ) faxil(.i_clk(ACLK), .i_axi_reset_n(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_awr_outstanding(faxil_awr_outstanding),
+ .f_axi_wr_outstanding(faxil_wr_outstanding),
+ .f_axi_rd_outstanding(faxil_rd_outstanding));
+
+ //
+ // ...
+ //
+
+ faxi_master #(
+ .C_AXI_ID_WIDTH(C_AXI_ID_WIDTH),
+ .C_AXI_ADDR_WIDTH(C_AXI_ADDR_WIDTH),
+ .C_AXI_DATA_WIDTH(C_AXI_DATA_WIDTH),
+ .OPT_MAXBURST(0),
+ .OPT_EXCLUSIVE(1'b0),
+ .OPT_NARROW_BURST(1'b0),
+ .F_OPT_NO_RESET(1'b1),
+ .F_LGDEPTH(10),
+ .F_AXI_MAXSTALL(4),
+ .F_AXI_MAXRSTALL(0),
+ .F_AXI_MAXDELAY(4)
+ ) faxi(.i_clk(ACLK), .i_axi_reset_n(ARESETN),
+ //
+ .i_axi_awready(M_AXI_AWREADY),
+ .i_axi_awid( M_AXI_AWID),
+ .i_axi_awaddr( M_AXI_AWADDR),
+ .i_axi_awlen( M_AXI_AWLEN),
+ .i_axi_awsize( M_AXI_AWSIZE),
+ .i_axi_awburst(M_AXI_AWBURST),
+ .i_axi_awlock( M_AXI_AWLOCK),
+ .i_axi_awcache(M_AXI_AWCACHE),
+ .i_axi_awprot( M_AXI_AWPROT),
+ .i_axi_awqos( M_AXI_AWQOS),
+ .i_axi_awvalid(M_AXI_AWVALID),
+ //
+ .i_axi_wready(M_AXI_WREADY),
+ .i_axi_wdata( M_AXI_WDATA),
+ .i_axi_wstrb( M_AXI_WSTRB),
+ .i_axi_wlast( M_AXI_WLAST),
+ .i_axi_wvalid(M_AXI_WVALID),
+ //
+ .i_axi_bready(M_AXI_BREADY),
+ .i_axi_bid( M_AXI_BID),
+ .i_axi_bresp( M_AXI_BRESP),
+ .i_axi_bvalid(M_AXI_BVALID),
+ //
+ .i_axi_arready(M_AXI_ARREADY),
+ .i_axi_arid( M_AXI_ARID),
+ .i_axi_araddr( M_AXI_ARADDR),
+ .i_axi_arlen( M_AXI_ARLEN),
+ .i_axi_arsize( M_AXI_ARSIZE),
+ .i_axi_arburst(M_AXI_ARBURST),
+ .i_axi_arlock( M_AXI_ARLOCK),
+ .i_axi_arcache(M_AXI_ARCACHE),
+ .i_axi_arprot( M_AXI_ARPROT),
+ .i_axi_arqos( M_AXI_ARQOS),
+ .i_axi_arvalid(M_AXI_ARVALID),
+ //
+ .i_axi_rid( M_AXI_RID),
+ .i_axi_rdata( M_AXI_RDATA),
+ .i_axi_rready(M_AXI_RREADY),
+ .i_axi_rresp( M_AXI_RRESP),
+ .i_axi_rvalid(M_AXI_RVALID),
+ //
+ .f_axi_awr_nbursts(faxi_awr_nbursts),
+ .f_axi_wr_pending(faxi_wr_pending),
+ .f_axi_rd_nbursts(faxi_rd_nbursts),
+ .f_axi_rd_outstanding(faxi_rd_outstanding)
+ //
+ // ...
+ //
+ );
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Induction rule checks
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // First rule: the AXI solver isn't permitted to have any more write
+ // bursts outstanding than the AXI-lite interface has.
+ always @(*)
+ assert(faxi_awr_nbursts == faxil_awr_outstanding);
+
+ //
+ // Second: Since our bursts are limited to one value each, and since
+ // we can't send address bursts ahead of their data counterparts,
+ // (AXI property limitation) faxi_wr_pending can only ever be one or
+ // zero, and the counters must match
+ always @(*)
+ begin
+ //
+ // ...
+ //
+
+ if (faxil_awr_outstanding != 0)
+ begin
+ assert((faxil_awr_outstanding == faxil_wr_outstanding)
+ ||(faxil_awr_outstanding-1 == faxil_wr_outstanding));
+ end
+
+ if (faxil_awr_outstanding == 0)
+ assert(faxil_wr_outstanding == 0);
+ end
+
+ //
+ // ...
+ //
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Known "bugs"
+ //
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // These are really more limitations in the AXI properties than
+ // bugs in the code, but they need to be documented here.
+ //
+ generate if (C_AXI_DATA_WIDTH > 8)
+ begin
+ // The AXI-lite property checker doesn't validate WSTRB
+ // values like it should. If we don't force the AWADDR
+ // LSBs to zero, the solver will pick an invalid WSTRB.
+ //
+ always @(*)
+ assume(S_AXI_AWADDR[$clog2(C_AXI_DATA_WIDTH)-3:0] == 0);
+ always @(*)
+ assert(faxi_wr_addr[$clog2(C_AXI_DATA_WIDTH)-3:0] == 0);
+ end endgenerate
+
+ //
+ // The AXI solver can't handle write transactions without either a
+ // concurrent or proceeding write address burst. Here we make that
+ // plain. It's not likely to cause any problems, but still worth
+ // noting.
+ always @(*)
+ if (faxil_awr_outstanding == faxil_wr_outstanding)
+ assume(S_AXI_AWVALID || !S_AXI_WVALID);
+ else if (faxil_awr_outstanding > faxil_wr_outstanding)
+ assume(!S_AXI_AWVALID);
+
+ //
+ // We need to make certain that our counters never overflow. This is
+ // an assertion within the property checkers, so we need an appropriate
+ // matching assumption here. In practice, F_LGDEPTH could be set
+ // so arbitrarily large that this assumption would never get hit,
+ // but the solver doesn't know that.
+ always @(*)
+ if (faxil_rd_outstanding >= {{(F_LGDEPTH-1){1'b1}}, 1'b0 })
+ assume(!S_AXI_ARVALID);
+
+ always @(*)
+ if (faxil_awr_outstanding >= {{(F_LGDEPTH-1){1'b1}}, 1'b0 })
+ assume(!S_AXI_AWVALID);
+
+`endif
+endmodule
+`ifndef YOSYS
+`default_nettype wire
+`endif