//////////////////////////////////////////////////////////////////////////////// // // 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, /*local*/parameter SDW = C_S_AXIL_DATA_WIDTH, /*local*/parameter MDW = C_M_AXIL_DATA_WIDTH, /*local*/parameter 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< MDW) $stop; // }}} endmodule