//////////////////////////////////////////////////////////////////////////////// // // Filename: axi2axilite.v // {{{ // Project: WB2AXIPSP: bus bridges and other odds and ends // // Purpose: Convert from AXI to AXI-lite with no performance loss. // // Performance: The goal of this converter is to convert from AXI to AXI-lite // while still maintaining the one-clock per transaction speed // of AXI. It currently achieves this goal. The design needs very little // configuration to be useful, but you might wish to resize the FIFOs // within depending upon the length of your slave's data path. The current // FIFO length, LGFIFO=4, is sufficient to maintain full speed. If the // slave, however, can maintain full speed but requires a longer // processing cycle, then you may need longer FIFOs. // // The AXI specification does require an additional 2 clocks per // transaction when using this core, so your latency will go up. // // Related: There's a related axidouble.v core in the same repository as // well. That can be used to convert the AXI protocol to something // simpler (even simpler than AXI-lite), but it can also do so for multiple // downstream slaves at the same time. // // 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 axi2axilite #( // {{{ parameter integer C_AXI_ID_WIDTH = 2, parameter integer C_AXI_DATA_WIDTH = 32, parameter integer C_AXI_ADDR_WIDTH = 6, parameter [0:0] OPT_WRITES = 1, parameter [0:0] OPT_READS = 1, parameter [0:0] OPT_LOWPOWER = 0, // Log (based two) of the maximum number of outstanding AXI // (not AXI-lite) transactions. If you multiply 2^LGFIFO * 256, // you'll get the maximum number of outstanding AXI-lite // transactions parameter LGFIFO = 4 // }}} ) ( // {{{ input wire S_AXI_ACLK, input wire S_AXI_ARESETN, // AXI4 slave interface // {{{ // Write address channel // {{{ input wire S_AXI_AWVALID, output wire S_AXI_AWREADY, input wire [C_AXI_ID_WIDTH-1:0] S_AXI_AWID, input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, input wire [7:0] S_AXI_AWLEN, input wire [2:0] S_AXI_AWSIZE, input wire [1:0] S_AXI_AWBURST, input wire S_AXI_AWLOCK, input wire [3:0] S_AXI_AWCACHE, input wire [2:0] S_AXI_AWPROT, input wire [3:0] S_AXI_AWQOS, // }}} // Write data channel // {{{ 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, input wire S_AXI_WLAST, // }}} // Write return channel // {{{ output wire S_AXI_BVALID, input wire S_AXI_BREADY, output wire [C_AXI_ID_WIDTH-1:0] S_AXI_BID, output wire [1:0] S_AXI_BRESP, // }}} // Read address channel // {{{ input wire S_AXI_ARVALID, output wire S_AXI_ARREADY, input wire [C_AXI_ID_WIDTH-1:0] S_AXI_ARID, input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR, input wire [7:0] S_AXI_ARLEN, input wire [2:0] S_AXI_ARSIZE, input wire [1:0] S_AXI_ARBURST, input wire S_AXI_ARLOCK, input wire [3:0] S_AXI_ARCACHE, input wire [2:0] S_AXI_ARPROT, input wire [3:0] S_AXI_ARQOS, // }}} // Read data channel // {{{ output wire S_AXI_RVALID, input wire S_AXI_RREADY, output wire [C_AXI_ID_WIDTH-1:0] S_AXI_RID, output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, output wire [1:0] S_AXI_RRESP, output wire S_AXI_RLAST, // }}} // }}} // AXI-lite master interface // {{{ // AXI-lite Write interface // {{{ output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, output wire [2 : 0] M_AXI_AWPROT, output wire M_AXI_AWVALID, input wire M_AXI_AWREADY, 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_WVALID, input wire M_AXI_WREADY, input wire [1 : 0] M_AXI_BRESP, input wire M_AXI_BVALID, output wire M_AXI_BREADY, // }}} // AXI-lite read interface // {{{ output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, output wire [2:0] M_AXI_ARPROT, output wire M_AXI_ARVALID, input wire M_AXI_ARREADY, // input wire M_AXI_RVALID, output wire M_AXI_RREADY, input wire [C_AXI_DATA_WIDTH-1 : 0] M_AXI_RDATA, input wire [1 : 0] M_AXI_RRESP // }}} // }}} // }}} ); // Local parameters, register, and net declarations // {{{ localparam [1:0] SLVERR = 2'b10; // localparam [1:0] OKAY = 2'b00, // EXOKAY = 2'b01, // DECERR = 2'b10; localparam AW = C_AXI_ADDR_WIDTH; localparam DW = C_AXI_DATA_WIDTH; localparam IW = C_AXI_ID_WIDTH; // }}} // Register declarations // {{{ // // Write registers reg m_axi_awvalid, s_axi_wready; reg [C_AXI_ADDR_WIDTH-1:0] axi_awaddr; reg [7:0] axi_awlen, axi_blen; reg [1:0] axi_awburst; reg [2:0] axi_awsize; wire [C_AXI_ADDR_WIDTH-1:0] next_write_addr; wire [4:0] wfifo_count; wire wfifo_full; wire wfifo_empty; wire [7:0] wfifo_bcount; wire [IW-1:0] wfifo_bid; reg [8:0] bcounts; reg [C_AXI_ID_WIDTH-1:0] axi_bid, bid; reg [1:0] axi_bresp; reg s_axi_bvalid; wire read_from_wrfifo; // // Read register reg m_axi_arvalid; wire [4:0] rfifo_count; wire rfifo_full; wire rfifo_empty; wire [7:0] rfifo_rcount; reg s_axi_rvalid; reg [1:0] s_axi_rresp; reg [8:0] rcounts; reg [C_AXI_ADDR_WIDTH-1:0] axi_araddr; reg [7:0] axi_arlen, axi_rlen; reg [1:0] axi_arburst; reg [2:0] axi_arsize; wire [C_AXI_ADDR_WIDTH-1:0] next_read_addr; reg [C_AXI_ID_WIDTH-1:0] s_axi_rid; wire [C_AXI_ID_WIDTH-1:0] rfifo_rid; reg [C_AXI_DATA_WIDTH-1:0] s_axi_rdata; reg s_axi_rlast; reg [IW-1:0] rid; wire read_from_rdfifo; // // S_AXI_AW* skid buffer wire skids_awvalid, skids_awready; wire [IW-1:0] skids_awid; wire [AW-1:0] skids_awaddr; wire [7:0] skids_awlen; wire [2:0] skids_awsize; wire [1:0] skids_awburst; // // S_AXI_W* skid buffer wire skids_wvalid, skids_wready, skids_wlast; wire [DW-1:0] skids_wdata; wire [DW/8-1:0] skids_wstrb; // // S_AXI_B* skid buffer isn't needed // // M_AXI_AW* skid buffer isn't needed // // M_AXI_W* skid buffer wire skidm_wvalid, skidm_wready; wire [DW-1:0] skidm_wdata; wire [DW/8-1:0] skidm_wstrb; // // M_AXI_B* skid buffer wire skidm_bvalid, skidm_bready; wire [1:0] skidm_bresp; // // // // S_AXI_AR* skid buffer wire skids_arvalid, skids_arready; wire [IW-1:0] skids_arid; wire [AW-1:0] skids_araddr; wire [7:0] skids_arlen; wire [2:0] skids_arsize; wire [1:0] skids_arburst; // // S_AXI_R* skid buffer isn't needed // // M_AXI_AR* skid buffer isn't needed // M_AXI_R* skid buffer wire skidm_rvalid, skidm_rready; wire [DW-1:0] skidm_rdata; wire [1:0] skidm_rresp; // }}} //////////////////////////////////////////////////////////////////////// // // Write logic // {{{ //////////////////////////////////////////////////////////////////////// // // generate if (OPT_WRITES) begin : IMPLEMENT_WRITES // {{{ // The write address channel's skid buffer // {{{ skidbuffer #( // {{{ .DW(IW+AW+8+3+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0) // }}} ) awskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, S_AXI_AWVALID, S_AXI_AWREADY, { S_AXI_AWID, S_AXI_AWADDR, S_AXI_AWLEN, S_AXI_AWSIZE, S_AXI_AWBURST }, skids_awvalid, skids_awready, { skids_awid, skids_awaddr, skids_awlen, skids_awsize, skids_awburst } // }}} ); // }}} // // The write data channel's skid buffer (S_AXI_W*) // {{{ skidbuffer #( // {{{ .DW(DW+DW/8+1), .OPT_LOWPOWER(0), .OPT_OUTREG(0) // }}} ) wskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, S_AXI_WVALID, S_AXI_WREADY, { S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST }, skids_wvalid, skids_wready, { skids_wdata, skids_wstrb, skids_wlast } // }}} ); // }}} // // The downstream AXI-lite write data (M_AXI_W*) skid buffer // {{{ skidbuffer #( // {{{ .DW(DW+DW/8), .OPT_LOWPOWER(0), .OPT_OUTREG(1) // }}} ) mwskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, skidm_wvalid, skidm_wready, { skidm_wdata, skidm_wstrb }, M_AXI_WVALID,M_AXI_WREADY,{ M_AXI_WDATA, M_AXI_WSTRB } // }}} ); // }}} // // The downstream AXI-lite response (M_AXI_B*) skid buffer // {{{ skidbuffer #( // {{{ .DW(2), .OPT_LOWPOWER(0), .OPT_OUTREG(0) // }}} ) bskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, M_AXI_BVALID, M_AXI_BREADY, { M_AXI_BRESP }, skidm_bvalid, skidm_bready, { skidm_bresp } // }}} ); // }}} // m_axi_awvalid // {{{ initial m_axi_awvalid = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) m_axi_awvalid <= 0; else if (skids_awvalid & skids_awready) m_axi_awvalid <= 1; else if (M_AXI_AWREADY && axi_awlen == 0) m_axi_awvalid <= 0; assign M_AXI_AWVALID = m_axi_awvalid; // }}} // skids_awready // {{{ assign skids_awready = (!M_AXI_AWVALID || ((axi_awlen == 0)&&M_AXI_AWREADY)) && !wfifo_full &&(!s_axi_wready || (skids_wvalid && skids_wlast && skids_wready)); // }}} // Address processing // {{{ always @(posedge S_AXI_ACLK) if (skids_awvalid && skids_awready) begin axi_awaddr <= skids_awaddr; axi_blen <= skids_awlen; axi_awburst<= skids_awburst; axi_awsize <= skids_awsize; end else if (M_AXI_AWVALID && M_AXI_AWREADY) axi_awaddr <= next_write_addr; // }}} // axi_awlen // {{{ initial axi_awlen = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_awlen <= 0; else if (skids_awvalid && skids_awready) axi_awlen <= skids_awlen; else if (M_AXI_AWVALID && M_AXI_AWREADY && axi_awlen > 0) axi_awlen <= axi_awlen - 1; // }}} // axi_addr // {{{ axi_addr #( // {{{ .AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH) // }}} ) calcwraddr( // {{{ axi_awaddr, axi_awsize, axi_awburst, axi_blen, next_write_addr // }}} ); // }}} // s_axi_wready // {{{ // We really don't need to do anything special to the write // channel. initial s_axi_wready = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) s_axi_wready <= 0; else if (skids_awvalid && skids_awready) s_axi_wready <= 1; else if (skids_wvalid && skids_wready && skids_wlast) s_axi_wready <= 0; // }}} // skidm*, and read_from_wrfifo // {{{ assign skidm_wdata = skids_wdata; assign skidm_wstrb = skids_wstrb; assign skidm_wvalid = skids_wvalid && s_axi_wready; assign skids_wready = s_axi_wready && skidm_wready; assign read_from_wrfifo = (bcounts <= 1)&&(!wfifo_empty) &&(skidm_bvalid && skidm_bready); // }}} // BFIFO // {{{ sfifo #( .BW(C_AXI_ID_WIDTH+8), .LGFLEN(LGFIFO) ) bidlnfifo( S_AXI_ACLK, !S_AXI_ARESETN, skids_awvalid && skids_awready, { skids_awid, skids_awlen }, wfifo_full, wfifo_count, read_from_wrfifo, { wfifo_bid, wfifo_bcount }, wfifo_empty); // }}} // bcounts // {{{ // Return counts initial bcounts = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) bcounts <= 0; else if (read_from_wrfifo) begin bcounts <= wfifo_bcount + bcounts; end else if (skidm_bvalid && skidm_bready) bcounts <= bcounts - 1; // }}} // bid // {{{ always @(posedge S_AXI_ACLK) if (read_from_wrfifo) bid <= wfifo_bid; always @(posedge S_AXI_ACLK) if (!S_AXI_BVALID || S_AXI_BREADY) axi_bid <= (read_from_wrfifo && bcounts==0) ? wfifo_bid : bid; // }}} // s_axi_bvalid // {{{ initial s_axi_bvalid = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) s_axi_bvalid <= 0; else if (skidm_bvalid && skidm_bready) s_axi_bvalid <= (bcounts == 1) ||((bcounts == 0) && (!wfifo_empty) && (wfifo_bcount == 0)); else if (S_AXI_BREADY) s_axi_bvalid <= 0; // }}} // axi_bresp // {{{ initial axi_bresp = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_bresp <= 0; else if (S_AXI_BVALID && S_AXI_BREADY) begin if (skidm_bvalid && skidm_bready) axi_bresp <= skidm_bresp; else axi_bresp <= 0; end else if (skidm_bvalid && skidm_bready) begin // Let SLVERR take priority over DECERR casez({ S_AXI_BRESP, skidm_bresp }) 4'b??0?: axi_bresp <= S_AXI_BRESP; 4'b0?1?: axi_bresp <= skidm_bresp; 4'b1?10: axi_bresp <= SLVERR; 4'b1011: axi_bresp <= SLVERR; 4'b1111: axi_bresp <= skidm_bresp; endcase end // /}}} // M_AXI_AW* // {{{ assign M_AXI_AWVALID= m_axi_awvalid; assign M_AXI_AWADDR = axi_awaddr; assign M_AXI_AWPROT = 0; // }}} // skidm_bready, S_AXI_B* // {{{ assign skidm_bready = ((bcounts > 0)||(!wfifo_empty))&&(!S_AXI_BVALID | S_AXI_BREADY); assign S_AXI_BID = axi_bid; assign S_AXI_BRESP = axi_bresp; assign S_AXI_BVALID = s_axi_bvalid; // }}} // }}} end else begin : NO_WRITE_SUPPORT // {{{ assign S_AXI_AWREADY = 0; assign S_AXI_WREADY = 0; assign S_AXI_BID = 0; assign S_AXI_BRESP = 2'b11; assign S_AXI_BVALID = 0; assign S_AXI_BID = 0; // assign M_AXI_AWVALID = 0; assign M_AXI_AWADDR = 0; assign M_AXI_AWPROT = 0; // assign M_AXI_WVALID = 0; assign M_AXI_WDATA = 0; assign M_AXI_WSTRB = 0; // assign M_AXI_BREADY = 0; // // S_AXI_AW* skid buffer assign skids_awvalid = 0; assign skids_awready = 0; assign skids_awid = 0; assign skids_awaddr = 0; assign skids_awlen = 0; assign skids_awsize = 0; assign skids_awburst = 0; // // S_AXI_W* skid buffer assign skids_wvalid = S_AXI_WVALID; assign skids_wready = S_AXI_WREADY; assign skids_wdata = S_AXI_WDATA; assign skids_wstrb = S_AXI_WSTRB; assign skids_wlast = S_AXI_WLAST; // // S_AXI_B* skid buffer isn't needed // // M_AXI_AW* skid buffer isn't needed // // M_AXI_W* skid buffer assign skidm_wvalid = M_AXI_WVALID; assign skidm_wready = M_AXI_WREADY; assign skidm_wdata = M_AXI_WDATA; assign skidm_wstrb = M_AXI_WSTRB; // // M_AXI_B* skid buffer assign skidm_bvalid = M_AXI_BVALID; assign skidm_bready = M_AXI_BREADY; assign skidm_bresp = M_AXI_BRESP; // // always @(*) begin s_axi_wready = 0; axi_awlen = 0; bcounts = 0; bid = 0; axi_bresp = 0; axi_bid = 0; end assign wfifo_full = 0; assign wfifo_empty = 1; assign wfifo_count = 0; assign read_from_wrfifo = 0; // Make Verilator happy // {{{ // Verilator lint_off UNUSED wire unused_write_signals; assign unused_write_signals = &{ 1'b0, M_AXI_AWREADY, M_AXI_WREADY, S_AXI_BREADY }; // Verilator lint_on UNUSED // }}} // }}} end endgenerate // }}} //////////////////////////////////////////////////////////////////////// // // Read logic // {{{ //////////////////////////////////////////////////////////////////////// // // generate if (OPT_READS) begin : IMPLEMENT_READS // {{{ // S_AXI_AR* skid buffer // {{{ skidbuffer #( // {{{ .DW(IW+AW+8+3+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0) // }}} ) arskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, S_AXI_ARVALID, S_AXI_ARREADY, { S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN, S_AXI_ARSIZE, S_AXI_ARBURST }, skids_arvalid, skids_arready, { skids_arid, skids_araddr, skids_arlen, skids_arsize, skids_arburst } // }}} ); // }}} // M_AXI_R* skid buffer // {{{ skidbuffer #( // {{{ .DW(DW+2), .OPT_LOWPOWER(0), .OPT_OUTREG(0) // }}} ) rskid( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, M_AXI_RVALID, M_AXI_RREADY,{ M_AXI_RDATA, M_AXI_RRESP }, skidm_rvalid,skidm_rready,{ skidm_rdata, skidm_rresp } // }}} ); // }}} // m_axi_arvalid // {{{ initial m_axi_arvalid = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) m_axi_arvalid <= 0; else if (skids_arvalid && skids_arready) m_axi_arvalid <= 1; else if (M_AXI_ARREADY && axi_arlen == 0) m_axi_arvalid <= 0; // }}} // Read address processing // {{{ always @(posedge S_AXI_ACLK) if (skids_arvalid && skids_arready) begin axi_araddr <= skids_araddr; axi_arburst <= skids_arburst; axi_arsize <= skids_arsize; axi_rlen <= skids_arlen; end else if (M_AXI_ARREADY) begin axi_araddr <= next_read_addr; if (OPT_LOWPOWER && axi_arlen == 0) axi_araddr <= 0; end axi_addr #( // {{{ .AW(C_AXI_ADDR_WIDTH), .DW(C_AXI_DATA_WIDTH) // }}} ) calcrdaddr( // {{{ axi_araddr, axi_arsize, axi_arburst, axi_rlen, next_read_addr // }}} ); // }}} // axi_arlen, Read length processing // {{{ initial axi_arlen = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_arlen <= 0; else if (skids_arvalid && skids_arready) axi_arlen <= skids_arlen; else if (M_AXI_ARVALID && M_AXI_ARREADY && axi_arlen > 0) axi_arlen <= axi_arlen - 1; // }}} assign skids_arready = (!M_AXI_ARVALID || ((axi_arlen == 0) && M_AXI_ARREADY)) && !rfifo_full; assign read_from_rdfifo = skidm_rvalid && skidm_rready && (rcounts <= 1) && !rfifo_empty; // Read ID FIFO // {{{ sfifo #( // {{{ .BW(C_AXI_ID_WIDTH+8), .LGFLEN(LGFIFO) // }}} ) ridlnfifo( // {{{ S_AXI_ACLK, !S_AXI_ARESETN, skids_arvalid && skids_arready, { skids_arid, skids_arlen }, rfifo_full, rfifo_count, read_from_rdfifo, { rfifo_rid, rfifo_rcount }, rfifo_empty // }}} ); // }}} assign skidm_rready = (!S_AXI_RVALID || S_AXI_RREADY); // s_axi_rvalid // {{{ initial s_axi_rvalid = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) s_axi_rvalid <= 0; else if (skidm_rvalid && skidm_rready) s_axi_rvalid <= 1; else if (S_AXI_RREADY) s_axi_rvalid <= 0; // }}} // s_axi_rresp, s_axi_rdata // {{{ always @(posedge S_AXI_ACLK) if (skidm_rvalid && skidm_rready) begin s_axi_rresp <= skidm_rresp; s_axi_rdata <= skidm_rdata; end else if (S_AXI_RREADY) begin s_axi_rresp <= 0; s_axi_rdata <= 0; end // }}} // rcounts, Return counts // {{{ initial rcounts = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) rcounts <= 0; else if (read_from_rdfifo) rcounts <= rfifo_rcount + rcounts; else if (skidm_rvalid && skidm_rready) rcounts <= rcounts - 1; // }}} // rid // {{{ initial rid = 0; always @(posedge S_AXI_ACLK) if (read_from_rdfifo) rid <= rfifo_rid; // }}} // s_axi_rlast // {{{ always @(posedge S_AXI_ACLK) if (!S_AXI_RVALID || S_AXI_RREADY) begin // if (rcounts == 1) s_axi_rlast <= 1; else if (read_from_rdfifo) s_axi_rlast <= (rfifo_rcount == 0); else s_axi_rlast <= 0; if (rcounts == 1) s_axi_rlast <= 1; end // }}} // s_axi_rid // {{{ initial s_axi_rid = 0; always @(posedge S_AXI_ACLK) if ((S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST) ||(!S_AXI_RVALID && rcounts == 0)) s_axi_rid <= (read_from_rdfifo)&&(rcounts == 0)?rfifo_rid : rid; // }}} // M_AXI_AR* // {{{ assign M_AXI_ARVALID= m_axi_arvalid; assign M_AXI_ARADDR = axi_araddr; assign M_AXI_ARPROT = 0; // }}} // S_AXI_R* // {{{ assign S_AXI_RVALID = s_axi_rvalid; assign S_AXI_RDATA = s_axi_rdata; assign S_AXI_RRESP = s_axi_rresp; assign S_AXI_RLAST = s_axi_rlast; assign S_AXI_RID = s_axi_rid; // }}} // }}} end else begin : NO_READ_SUPPORT // if (!OPT_READS) // {{{ assign M_AXI_ARVALID= 0; assign M_AXI_ARADDR = 0; assign M_AXI_ARPROT = 0; assign M_AXI_RREADY = 0; // assign S_AXI_ARREADY= 0; assign S_AXI_RVALID = 0; assign S_AXI_RDATA = 0; assign S_AXI_RRESP = 0; assign S_AXI_RLAST = 0; assign S_AXI_RID = 0; // assign skids_arvalid = S_AXI_ARVALID; assign skids_arready = S_AXI_ARREADY; assign skids_arid = S_AXI_ARID; assign skids_araddr = S_AXI_ARADDR; assign skids_arlen = S_AXI_ARLEN; assign skids_arsize = S_AXI_ARSIZE; assign skids_arburst = S_AXI_ARBURST; // assign skidm_rvalid = M_AXI_RVALID; assign skidm_rready = M_AXI_RREADY; assign skidm_rdata = M_AXI_RDATA; assign skidm_rresp = M_AXI_RRESP; // // always @(*) begin axi_arlen = 0; rcounts = 0; rid = 0; end assign rfifo_empty = 1; assign rfifo_full = 0; assign rfifo_count = 0; // Make Verilator happy // {{{ // Verilator lint_off UNUSED wire unused_read_signals; assign unused_read_signals = &{ 1'b0, M_AXI_ARREADY, S_AXI_RREADY }; // Verilator lint_on UNUSED // }}} // }}} end endgenerate // }}} // Make Verilator happy // {{{ // Verilator lint_off UNUSED wire [35-1:0] unused; assign unused = { S_AXI_AWLOCK, S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS, skids_wlast, wfifo_count, S_AXI_ARLOCK, S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS, rfifo_count }; // Verilator lint_on UNUSED // }}} //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // Formal properties // {{{ // The following are a subset of the formal properties used to verify this core //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// `ifdef FORMAL localparam F_LGDEPTH = LGFIFO+1+8; // // ... // //////////////////////////////////////////////////////////////////////// // // AXI channel properties // {{{ //////////////////////////////////////////////////////////////////////// // // faxi_slave #(.C_AXI_ID_WIDTH(IW), .C_AXI_DATA_WIDTH(DW), .C_AXI_ADDR_WIDTH(AW), // ) faxi(.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN), // Write address .i_axi_awready(skids_awready), .i_axi_awid( skids_awid), .i_axi_awaddr( skids_awaddr), .i_axi_awlen( skids_awlen), .i_axi_awsize( skids_awsize), .i_axi_awburst(skids_awburst), .i_axi_awlock( 0), .i_axi_awcache(0), .i_axi_awprot( 0), .i_axi_awqos( 0), .i_axi_awvalid(skids_awvalid), // Write data .i_axi_wready( skids_wready), .i_axi_wdata( skids_wdata), .i_axi_wstrb( skids_wstrb), .i_axi_wlast( skids_wlast), .i_axi_wvalid( skids_wvalid), // Write return response .i_axi_bid( S_AXI_BID), .i_axi_bresp( S_AXI_BRESP), .i_axi_bvalid( S_AXI_BVALID), .i_axi_bready( S_AXI_BREADY), // Read address .i_axi_arready(skids_arready), .i_axi_arid( skids_arid), .i_axi_araddr( skids_araddr), .i_axi_arlen( skids_arlen), .i_axi_arsize( skids_arsize), .i_axi_arburst(skids_arburst), .i_axi_arlock( 0), .i_axi_arcache(0), .i_axi_arprot( 0), .i_axi_arqos( 0), .i_axi_arvalid(skids_arvalid), // Read response .i_axi_rid( S_AXI_RID), .i_axi_rresp( S_AXI_RRESP), .i_axi_rvalid( S_AXI_RVALID), .i_axi_rdata( S_AXI_RDATA), .i_axi_rlast( S_AXI_RLAST), .i_axi_rready( S_AXI_RREADY), // // Formal property data .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), // // ... ); // }}} //////////////////////////////////////////////////////////////////////// // // AXI-lite properties // {{{ //////////////////////////////////////////////////////////////////////// // // faxil_master #(.C_AXI_DATA_WIDTH(DW), .C_AXI_ADDR_WIDTH(AW), .F_OPT_NO_RESET(1), .F_AXI_MAXWAIT(5), .F_AXI_MAXDELAY(4), .F_AXI_MAXRSTALL(0), .F_OPT_WRITE_ONLY(OPT_WRITES && !OPT_READS), .F_OPT_READ_ONLY(!OPT_WRITES && OPT_READS), .F_LGDEPTH(F_AXIL_LGDEPTH)) faxil(.i_clk(S_AXI_ACLK), .i_axi_reset_n(S_AXI_ARESETN), // Write address channel .i_axi_awvalid(M_AXI_AWVALID), .i_axi_awready(M_AXI_AWREADY), .i_axi_awaddr( M_AXI_AWADDR), .i_axi_awprot( M_AXI_AWPROT), // Write data .i_axi_wready( skidm_wready), .i_axi_wdata( skidm_wdata), .i_axi_wstrb( skidm_wstrb), .i_axi_wvalid( skidm_wvalid), // Write response .i_axi_bresp( skidm_bresp), .i_axi_bvalid( skidm_bvalid), .i_axi_bready( skidm_bready), // Read address .i_axi_arvalid(M_AXI_ARVALID), .i_axi_arready(M_AXI_ARREADY), .i_axi_araddr( M_AXI_ARADDR), .i_axi_arprot( M_AXI_ARPROT), // Read data return .i_axi_rvalid( skidm_rvalid), .i_axi_rready( skidm_rready), .i_axi_rdata( skidm_rdata), .i_axi_rresp( skidm_rresp), // // Formal check variables .f_axi_rd_outstanding(faxil_rd_outstanding), .f_axi_wr_outstanding(faxil_wr_outstanding), .f_axi_awr_outstanding(faxil_awr_outstanding)); // }}} //////////////////////////////////////////////////////////////////////// // // Assume that the two write channels stay within an appropriate // distance of each other. This is to make certain that the property // file features are not violated, although not necessary true for // actual operation // always @(*) assert(s_axi_wready == (OPT_WRITES && faxi_wr_pending > 0)); //////////////////////////////////////////////////////////////////////// // // Write induction properties // {{{ //////////////////////////////////////////////////////////////////////// // // These are extra properties necessary to pass write induction // always @(*) if ((bcounts == 0)&&(!read_from_wrfifo)) assert(!skidm_bvalid || !skidm_bready); always @(*) if (axi_awlen > 0) begin assert(m_axi_awvalid); if (axi_awlen > 1) begin assert(!skids_awready); end else if (wfifo_full) begin assert(!skids_awready); end else if (M_AXI_AWVALID && !M_AXI_AWREADY) assert(!skids_awready); end always @(*) assert(axi_bresp != EXOKAY); reg [F_LGDEPTH-1:0] f_wfifo_bursts, f_wfifo_bursts_minus_one, f_wfifo_within, f_wfiid_bursts, f_wfiid_bursts_minus_one; reg [IW-1:0] f_awid; always @(posedge S_AXI_ACLK) if (skids_awvalid && skids_awready) f_awid = skids_awid; // }}} //////////////////////////////////////////////////////////////////////// // // Read induction properties // {{{ //////////////////////////////////////////////////////////////////////// // // always @(*) if (!S_AXI_RVALID && rcounts > 0) assert(rid == S_AXI_RID); always @(*) if (S_AXI_RVALID && !S_AXI_RLAST) assert(rid == S_AXI_RID); always @(*) if ((rcounts == 0)&&(!read_from_rdfifo)) assert(!skidm_rvalid || !skidm_rready); always @(*) if (axi_arlen > 0) begin assert(m_axi_arvalid); assert(!skids_arready); end // // ... // // }}} //////////////////////////////////////////////////////////////////////// // // Select only write or only read operation // {{{ //////////////////////////////////////////////////////////////////////// // // generate if (!OPT_WRITES) begin always @(*) begin assume(!skids_awvalid); assume(!skids_wvalid); assert(M_AXI_AWVALID == 0); assert(faxil_awr_outstanding == 0); assert(faxil_wr_outstanding == 0); assert(!skidm_bvalid); assert(!S_AXI_BVALID); end end endgenerate generate if (!OPT_READS) begin always @(*) begin assume(!S_AXI_ARVALID); assert(M_AXI_ARVALID == 0); assert(faxil_rd_outstanding == 0); end end endgenerate // }}} //////////////////////////////////////////////////////////////////////// // // Cover statements, to show performance // {{{ //////////////////////////////////////////////////////////////////////// // // generate if (OPT_WRITES) begin // {{{ reg [3:0] cvr_write_count, cvr_write_count_simple; initial cvr_write_count = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) cvr_write_count_simple <= 0; else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 0) cvr_write_count_simple <= cvr_write_count_simple + 1; initial cvr_write_count = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) cvr_write_count <= 0; else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN > 2) cvr_write_count <= cvr_write_count + 1; always @(*) cover(cvr_write_count_simple > 6 && /* ... */ !S_AXI_BVALID); always @(*) cover(cvr_write_count > 2 && /* ... */ !S_AXI_BVALID); // }}} end endgenerate generate if (OPT_READS) begin // {{{ reg [3:0] cvr_read_count, cvr_read_count_simple; initial cvr_read_count_simple = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) cvr_read_count_simple <= 0; else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 0) cvr_read_count_simple <= cvr_read_count_simple + 1; initial cvr_read_count = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) cvr_read_count <= 0; else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN > 2) cvr_read_count <= cvr_read_count + 1; always @(*) cover(cvr_read_count_simple > 6 && /* ... */ !S_AXI_RVALID); always @(*) cover(cvr_read_count > 2 && /* ... */ !S_AXI_RVALID); // }}} end endgenerate // }}} //////////////////////////////////////////////////////////////////////// // // ... // {{{ //////////////////////////////////////////////////////////////////////// // // }}} `undef BMC_ASSERT `endif // }}} endmodule