summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/axilupsz.v
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/wb2axip/axilupsz.v')
-rw-r--r--rtl/wb2axip/axilupsz.v603
1 files changed, 603 insertions, 0 deletions
diff --git a/rtl/wb2axip/axilupsz.v b/rtl/wb2axip/axilupsz.v
new file mode 100644
index 0000000..29dc41d
--- /dev/null
+++ b/rtl/wb2axip/axilupsz.v
@@ -0,0 +1,603 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: axilupsz.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: Converts AXI4-lite traffic of one data width to a similar
+// AXI4-lite interface with a larger data path.
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2021-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 axilupsz #(
+ // {{{
+ parameter C_S_AXIL_DATA_WIDTH = 32,
+ parameter C_M_AXIL_DATA_WIDTH = 64,
+ parameter C_AXIL_ADDR_WIDTH = 32,
+ parameter LGFIFO = 5,
+ parameter [0:0] OPT_LOWPOWER = 1,
+ localparam SDW = C_S_AXIL_DATA_WIDTH,
+ localparam MDW = C_M_AXIL_DATA_WIDTH,
+ localparam AW = C_AXIL_ADDR_WIDTH
+ // }}}
+ ) (
+ // {{{
+ input wire S_AXI_ACLK,
+ S_AXI_ARESETN,
+ // The slave interface
+ // {{{
+ input wire S_AXIL_AWVALID,
+ output wire S_AXIL_AWREADY,
+ input wire [AW-1:0] S_AXIL_AWADDR,
+ input wire [2:0] S_AXIL_AWPROT,
+ //
+ input wire S_AXIL_WVALID,
+ output wire S_AXIL_WREADY,
+ input wire [SDW-1:0] S_AXIL_WDATA,
+ input wire [SDW/8-1:0] S_AXIL_WSTRB,
+ //
+ output wire S_AXIL_BVALID,
+ input wire S_AXIL_BREADY,
+ output wire [1:0] S_AXIL_BRESP,
+ //
+ input wire S_AXIL_ARVALID,
+ output wire S_AXIL_ARREADY,
+ input wire [AW-1:0] S_AXIL_ARADDR,
+ input wire [2:0] S_AXIL_ARPROT,
+ //
+ output wire S_AXIL_RVALID,
+ input wire S_AXIL_RREADY,
+ output wire [SDW-1:0] S_AXIL_RDATA,
+ output wire [1:0] S_AXIL_RRESP,
+ // }}}
+ // The master interface
+ // {{{
+ output wire M_AXIL_AWVALID,
+ input wire M_AXIL_AWREADY,
+ output wire [AW-1:0] M_AXIL_AWADDR,
+ output wire [2:0] M_AXIL_AWPROT,
+ //
+ output wire M_AXIL_WVALID,
+ input wire M_AXIL_WREADY,
+ output wire [MDW-1:0] M_AXIL_WDATA,
+ output wire [MDW/8-1:0] M_AXIL_WSTRB,
+ //
+ input wire M_AXIL_BVALID,
+ output wire M_AXIL_BREADY,
+ input wire [1:0] M_AXIL_BRESP,
+ //
+ output wire M_AXIL_ARVALID,
+ input wire M_AXIL_ARREADY,
+ output wire [AW-1:0] M_AXIL_ARADDR,
+ output wire [2:0] M_AXIL_ARPROT,
+ //
+ input wire M_AXIL_RVALID,
+ output wire M_AXIL_RREADY,
+ input wire [MDW-1:0] M_AXIL_RDATA,
+ input wire [1:0] M_AXIL_RRESP
+ // }}}
+ // }}}
+ );
+
+ localparam MLSB = $clog2(C_M_AXIL_DATA_WIDTH/8);
+ localparam SLSB = $clog2(C_S_AXIL_DATA_WIDTH/8);
+ localparam RPTS = MDW/SDW;
+
+ generate if (SDW == MDW)
+ begin : NO_CHANGE
+ // {{{
+ assign M_AXIL_AWVALID = S_AXIL_AWVALID;
+ assign S_AXIL_AWREADY = M_AXIL_AWREADY;
+ assign M_AXIL_AWADDR = S_AXIL_AWADDR;
+ assign M_AXIL_AWPROT = S_AXIL_AWPROT;
+
+ assign M_AXIL_WVALID = S_AXIL_WVALID;
+ assign S_AXIL_WREADY = M_AXIL_WREADY;
+ assign M_AXIL_WDATA = S_AXIL_WDATA;
+ assign M_AXIL_WSTRB = S_AXIL_WSTRB;
+
+ assign S_AXIL_BVALID = M_AXIL_BVALID;
+ assign M_AXIL_BREADY = S_AXIL_BREADY;
+ assign S_AXIL_BRESP = M_AXIL_BRESP;
+
+ assign M_AXIL_ARVALID = S_AXIL_ARVALID;
+ assign S_AXIL_ARREADY = M_AXIL_ARREADY;
+ assign M_AXIL_ARADDR = S_AXIL_ARADDR;
+ assign M_AXIL_ARPROT = S_AXIL_ARPROT;
+
+ assign S_AXIL_RVALID = M_AXIL_RVALID;
+ assign M_AXIL_RREADY = S_AXIL_RREADY;
+ assign S_AXIL_RDATA = M_AXIL_RDATA;
+ assign S_AXIL_RRESP = M_AXIL_RRESP;
+ // }}}
+ end else begin : UPSIZE_BUS_DATA_WIDTH
+ // {{{
+ // Signal declarations
+ // {{{
+ wire awskd_valid, wskd_valid, wskd_ready;
+ wire [AW-1:0] awskd_addr;
+ wire [2:0] awskd_prot;
+
+ wire [SDW-1:0] wskd_data;
+ wire [SDW/8-1:0] wskd_strb;
+
+ reg awvalid, wvalid;
+ reg [AW-1:0] awaddr;
+ reg [2:0] awprot;
+ reg [MDW-1:0] wdata;
+ reg [MDW/8-1:0] wstrb;
+
+ reg rvalid;
+ reg [SDW-1:0] rdata;
+ reg [1:0] rresp;
+ wire rfifo_full, rfifo_empty;
+ wire [LGFIFO:0] rfifo_fill;
+ wire [MLSB-SLSB-1:0] rfifo_data;
+ wire [MDW-1:0] shift_rdata;
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // Write channel(s)
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // AW* skid bufer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_OUTREG(0),
+ .DW(AW+3)
+ // }}}
+ ) awskd (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIL_AWVALID), .o_ready(S_AXIL_AWREADY),
+ .i_data({ S_AXIL_AWADDR, S_AXIL_AWPROT }),
+ .o_valid(awskd_valid), .i_ready(wskd_ready),
+ .o_data({ awskd_addr, awskd_prot })
+ // }}}
+ );
+ // }}}
+
+ skidbuffer #(
+ // {{{
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_OUTREG(0),
+ .DW(SDW+SDW/8)
+ // }}}
+ ) wskd (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXIL_WVALID), .o_ready(S_AXIL_WREADY),
+ .i_data({ S_AXIL_WDATA, S_AXIL_WSTRB }),
+ .o_valid(wskd_valid), .i_ready(wskd_ready),
+ .o_data({ wskd_data, wskd_strb })
+ // }}}
+ );
+
+ // wskd_ready
+ // {{{
+ // We *need* to synchronize the two channels here. We need the
+ // address informatiuon to know how to set the W* channel
+ // downstream
+ assign wskd_ready = (awskd_valid && wskd_valid)
+ && (!M_AXIL_AWVALID || M_AXIL_AWREADY)
+ && (!M_AXIL_WVALID || M_AXIL_WREADY);
+ // }}}
+
+ // awvalid
+ // {{{
+ initial awvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ awvalid <= 0;
+ else if (!M_AXIL_AWVALID || M_AXIL_AWREADY)
+ awvalid <= wskd_ready;
+ // }}}
+
+ // awaddr, awprot
+ // {{{
+ initial { awaddr, awprot } = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ { awaddr, awprot } <= 0;
+ else if (!M_AXIL_AWVALID || M_AXIL_AWREADY)
+ begin
+ { awaddr, awprot } <= 0;
+ if (awskd_valid || !OPT_LOWPOWER)
+ {awaddr, awprot } <= { awskd_addr, awskd_prot };
+ end
+ // }}}
+
+ // wvalid
+ // {{{
+ initial wvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ wvalid <= 0;
+ else if (!M_AXIL_WVALID || M_AXIL_WREADY)
+ wvalid <= wskd_ready;
+ // }}}
+
+ // wdata, wstrb
+ // {{{
+ initial { wdata, wstrb } = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN && OPT_LOWPOWER)
+ { wdata, wstrb } <= 0;
+ else if (!M_AXIL_WVALID || M_AXIL_WREADY)
+ begin
+ // Default values
+ wstrb <= 0;
+ wdata <= {(RPTS){ wskd_data }};
+
+ // Verilator lint_off WIDTH
+ if (OPT_LOWPOWER)
+ begin
+ wdata <= 0;
+ wdata <= (wskd_data)
+ << (awskd_addr[MLSB-1:SLSB] * SDW);
+ end
+
+ if (!OPT_LOWPOWER || wskd_valid)
+ wstrb <= (wskd_strb)
+ << (awskd_addr[MLSB-1:SLSB] * SDW);
+ // Verilator lint_on WIDTH
+ end
+ // }}}
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // Read channel
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+ wire rskd_valid, rskd_ready;
+ wire [MDW-1:0] rskd_data;
+ wire [1:0] rskd_resp;
+
+ // Read LSB address FIFO
+ // {{{
+ sfifo #(
+ // {{{
+ .BW(MLSB-SLSB),
+ .LGFLEN(LGFIFO)
+ // }}}
+ ) rfifo (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_wr(S_AXIL_ARVALID && S_AXIL_ARREADY),
+ .i_data(M_AXIL_ARADDR[MLSB-1:SLSB]),
+ .o_full(rfifo_full), .o_fill(rfifo_fill),
+ .i_rd(M_AXIL_RVALID && M_AXIL_RREADY),
+ .o_data(rfifo_data),
+ .o_empty(rfifo_empty)
+ // }}}
+ );
+ // }}}
+
+ // Read return skid buffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_OUTREG(0),
+ .DW(MDW+2)
+ // }}}
+ ) rskd (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(M_AXIL_RVALID), .o_ready(M_AXIL_RREADY),
+ .i_data({ M_AXIL_RDATA, M_AXIL_RRESP }),
+ .o_valid(rskd_valid), .i_ready(rskd_ready),
+ .o_data({ rskd_data, rskd_resp })
+ // }}}
+ );
+
+ assign rskd_ready = !S_AXIL_RVALID || S_AXIL_RREADY;
+ // }}}
+
+ assign shift_rdata = rskd_data
+ >> ({ {(MDW-(MLSB-SLSB)){1'b0}}, rfifo_data} * SDW);
+
+
+ // rvalid
+ // {{{
+ initial rvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ rvalid <= 0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ rvalid <= rskd_valid;
+ // }}}
+
+ // rresp
+ // {{{
+ initial rresp = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ rresp <= 0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ begin
+ rresp <= rskd_resp;
+ if (OPT_LOWPOWER && !rskd_valid)
+ rresp <= 0;
+ end
+ // }}}
+
+ // rdata
+ // {{{
+ initial rdata = 0;
+ always @(posedge S_AXI_ACLK)
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ rdata <= 0;
+ else if (!S_AXIL_RVALID || S_AXIL_RREADY)
+ begin
+ rdata <= shift_rdata[SDW-1:0];
+
+ if (OPT_LOWPOWER && !rskd_valid)
+ rdata <= 0;
+ end
+`ifdef FORMAL
+ // Low power check
+ // {{{
+ always @(*)
+ if (S_AXI_ARESETN && OPT_LOWPOWER && !S_AXIL_RVALID)
+ begin
+ assert(rdata == 0);
+ assert(rresp == 0);
+ end
+ // }}}
+`endif
+ // }}}
+
+ // }}}
+
+ // M_* values, S_B*
+ // {{{
+ assign M_AXIL_AWVALID = awvalid;
+ assign M_AXIL_AWADDR = awaddr;
+ assign M_AXIL_AWPROT = awprot;
+ assign M_AXIL_WVALID = wvalid;
+ assign M_AXIL_WDATA = wdata;
+ assign M_AXIL_WSTRB = wstrb;
+
+ assign M_AXIL_ARVALID = S_AXIL_ARVALID && !rfifo_full;
+ assign S_AXIL_ARREADY = M_AXIL_ARREADY && !rfifo_full;
+ assign M_AXIL_ARADDR = S_AXIL_ARADDR;
+ assign M_AXIL_ARPROT = S_AXIL_ARPROT;
+
+ assign S_AXIL_RVALID = rvalid;
+ assign S_AXIL_RDATA = rdata;
+ assign S_AXIL_RRESP = rresp;
+
+ assign S_AXIL_BVALID = M_AXIL_BVALID;
+ assign M_AXIL_BREADY = S_AXIL_BREADY;
+ assign S_AXIL_BRESP = M_AXIL_BRESP;
+ // }}}
+
+ // Make Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, shift_rdata[MDW-1:SDW],
+ rfifo_empty, rfifo_fill };
+ // Verilator lint_on UNUSED
+ // }}}
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ // Formal properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ localparam F_LGDEPTH = LGFIFO+2;
+ wire [F_LGDEPTH-1:0] fslv_rd_outstanding,
+ fmst_rd_outstanding,
+ fslv_wr_outstanding,
+ fmst_wr_outstanding,
+ fslv_awr_outstanding,
+ fmst_awr_outstanding;
+ ////////////////////////////////////////////////////////////////
+ //
+ // Interface properties
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ faxil_slave #(
+ // {{{
+ .C_AXI_DATA_WIDTH(SDW),
+ .C_AXI_ADDR_WIDTH(AW),
+ .F_OPT_COVER_BURST(4),
+ .F_LGDEPTH(F_LGDEPTH),
+ .F_AXI_MAXWAIT(8),
+ .F_AXI_MAXRSTALL(3),
+ .F_AXI_MAXDELAY(16)
+ // }}}
+ ) axil_slave (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(S_AXIL_AWVALID),
+ .i_axi_awready(S_AXIL_AWREADY),
+ .i_axi_awaddr( S_AXIL_AWADDR),
+ .i_axi_awprot( S_AXIL_AWPROT),
+ //
+ .i_axi_wvalid(S_AXIL_WVALID),
+ .i_axi_wready(S_AXIL_WREADY),
+ .i_axi_wdata( S_AXIL_WDATA),
+ .i_axi_wstrb( S_AXIL_WSTRB),
+ //
+ .i_axi_bvalid(S_AXIL_BVALID),
+ .i_axi_bready(S_AXIL_BREADY),
+ .i_axi_bresp( S_AXIL_BRESP),
+ //
+ .i_axi_arvalid(S_AXIL_ARVALID),
+ .i_axi_arready(S_AXIL_ARREADY),
+ .i_axi_araddr( S_AXIL_ARADDR),
+ .i_axi_arprot( S_AXIL_ARPROT),
+ //
+ .i_axi_rvalid(S_AXIL_RVALID),
+ .i_axi_rready(S_AXIL_RREADY),
+ .i_axi_rdata( S_AXIL_RDATA),
+ .i_axi_rresp( S_AXIL_RRESP),
+ //
+ .f_axi_rd_outstanding(fslv_rd_outstanding),
+ .f_axi_wr_outstanding(fslv_wr_outstanding),
+ .f_axi_awr_outstanding(fslv_awr_outstanding)
+ // }}}
+ );
+
+ faxil_master #(
+ // {{{
+ .C_AXI_DATA_WIDTH(MDW),
+ .C_AXI_ADDR_WIDTH(AW),
+ .F_OPT_COVER_BURST(1),
+ .F_LGDEPTH(F_LGDEPTH),
+ .F_OPT_NO_RESET(1),
+ .F_AXI_MAXWAIT(5),
+ .F_AXI_MAXRSTALL(3),
+ .F_AXI_MAXDELAY(5)
+ // }}}
+ ) axil_master (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ .i_axi_awvalid(M_AXIL_AWVALID),
+ .i_axi_awready(M_AXIL_AWREADY),
+ .i_axi_awaddr( M_AXIL_AWADDR),
+ .i_axi_awprot( M_AXIL_AWPROT),
+ //
+ .i_axi_wvalid(M_AXIL_WVALID),
+ .i_axi_wready(M_AXIL_WREADY),
+ .i_axi_wdata( M_AXIL_WDATA),
+ .i_axi_wstrb( M_AXIL_WSTRB),
+ //
+ .i_axi_bvalid(M_AXIL_BVALID),
+ .i_axi_bready(M_AXIL_BREADY),
+ .i_axi_bresp( M_AXIL_BRESP),
+ //
+ .i_axi_arvalid(M_AXIL_ARVALID),
+ .i_axi_arready(M_AXIL_ARREADY),
+ .i_axi_araddr( M_AXIL_ARADDR),
+ .i_axi_arprot( M_AXIL_ARPROT),
+ //
+ .i_axi_rvalid(M_AXIL_RVALID),
+ .i_axi_rready(M_AXIL_RREADY),
+ .i_axi_rdata( M_AXIL_RDATA),
+ .i_axi_rresp( M_AXIL_RRESP),
+ //
+ .f_axi_rd_outstanding(fmst_rd_outstanding),
+ .f_axi_wr_outstanding(fmst_wr_outstanding),
+ .f_axi_awr_outstanding(fmst_awr_outstanding)
+ // }}}
+ );
+
+ // Correlate slave and master write outstanding counters
+ // {{{
+ always @(*)
+ begin
+ assume(fslv_awr_outstanding <= (1<<LGFIFO));
+ assume(fslv_wr_outstanding <= (1<<LGFIFO));
+
+ assert(fslv_awr_outstanding + (S_AXIL_WREADY ? 0:1)
+ == fslv_wr_outstanding +(S_AXIL_AWREADY ? 0:1));
+
+ assert(fmst_awr_outstanding + (M_AXIL_AWVALID ? 1:0)
+ == fmst_wr_outstanding + (M_AXIL_WVALID ? 1:0));
+
+ assert(fslv_awr_outstanding == fmst_awr_outstanding
+ +(M_AXIL_AWVALID ? 1:0)+(S_AXIL_AWREADY ? 0:1));
+ assert(fslv_wr_outstanding == fmst_wr_outstanding
+ +(M_AXIL_WVALID ? 1:0) + (S_AXIL_WREADY ? 0:1));
+ end
+ // }}}
+
+ // Correlate the slave and master read outstanding counters
+ // w/ FIFO fill
+ // {{{
+ always @(*)
+ begin
+ assert(fslv_rd_outstanding == fmst_rd_outstanding
+ +(S_AXIL_RVALID ? 1:0) + (M_AXIL_RREADY ? 0:1));
+ assert(rfifo_fill == fmst_rd_outstanding);
+
+ if (M_AXIL_RVALID)
+ assert(!rfifo_empty);
+ end
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // Contract checks
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // Not implemented yet
+
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // Cover checks
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // (Currently) captured by the interface properties
+ // }}}
+ ////////////////////////////////////////////////////////////////
+ //
+ // "Careless" assumptions
+ // {{{
+ ////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // None
+
+ // }}}
+`endif
+ // }}}
+ end endgenerate
+
+ // Parameter checking
+ // {{{
+ initial if (SDW > MDW) $stop;
+ // }}}
+endmodule