//////////////////////////////////////////////////////////////////////////////// // // Filename: axi2axi3.v // {{{ // Project: WB2AXIPSP: bus bridges and other odds and ends // // Purpose: Bridge from an AXI4 slave to an AXI3 master // // The goal here is to not lose bus resolution, capacity or capability, // while bridging from AXI4 to AXI3. The biggest problem with such // a bridge is that we'll need to break large requests (AxLEN>15) up // into smaller packets. After that, everything should work as normal // with only minor modifications for AxCACHE. // // Opportunity: // The cost of this core is very much determined by the number of ID's // supported. It should be possible, with little extra cost or effort, // to reduce the ID space herein. This should be a topic for future // exploration. // // Status: // This core is an unverified first draft. It has past neither formal // nor simulation testing. Therefore, it is almost certain to have bugs // within it. Use it at your own risk. // // 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 axi2axi3 #( // {{{ parameter C_AXI_ID_WIDTH = 1, parameter C_AXI_ADDR_WIDTH = 32, parameter C_AXI_DATA_WIDTH = 32 // }}} ) ( // {{{ input wire S_AXI_ACLK, input wire S_AXI_ARESETN, // // The AXI4 incoming/slave interface input reg S_AXI_AWVALID, output wire S_AXI_AWREADY, input reg [C_AXI_ID_WIDTH-1:0] S_AXI_AWID, input reg [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, input reg [7:0] S_AXI_AWLEN, input reg [2:0] S_AXI_AWSIZE, input reg [1:0] S_AXI_AWBURST, input reg S_AXI_AWLOCK, input reg [3:0] S_AXI_AWCACHE, input reg [2:0] S_AXI_AWPROT, input reg [3:0] S_AXI_AWQOS, // // 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, // // 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, // // 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, // 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 S_AXI_RLAST, output wire [1:0] S_AXI_RRESP, // // // The AXI3 Master (outgoing) interface 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 [3:0] M_AXI_AWLEN, output wire [2:0] M_AXI_AWSIZE, output wire [1:0] M_AXI_AWBURST, output wire [1:0] M_AXI_AWLOCK, output wire [3:0] M_AXI_AWCACHE, output wire [2:0] M_AXI_AWPROT, output wire [3:0] M_AXI_AWQOS, // // output wire M_AXI_WVALID, input wire M_AXI_WREADY, output wire [C_AXI_ID_WIDTH-1:0] M_AXI_WID, 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, // // 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, // // 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 [3:0] M_AXI_ARLEN, output wire [2:0] M_AXI_ARSIZE, output wire [1:0] M_AXI_ARBURST, output wire [1:0] M_AXI_ARLOCK, output wire [3:0] M_AXI_ARCACHE, output wire [2:0] M_AXI_ARPROT, output wire [3:0] M_AXI_ARQOS, // 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 [1:0] M_AXI_RRESP // }}} ); // localparam ADDRLSB= $clog2(C_AXI_DATA_WIDTH)-3; localparam [0:0] OPT_LOWPOWER = 1'b0; localparam LGWFIFO = 4; localparam NID = (1< 0) awskd_ready = 0; if (M_AXI_AWVALID && M_AXI_AWREADY) awskd_ready = 0; if (|wfifo_fill[LGWFIFO:LGWFIFO-1]) awskd_ready = 0; end initial axi_awvalid = 1'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_awvalid <= 0; else if (awskd_valid || r_awlen > 0) axi_awvalid <= 1; else if (M_AXI_AWREADY) axi_awvalid <= 0; initial r_awlen = 0; initial axi_awlen = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) begin r_awlen <= 0; axi_awlen <= 0; end else if (!M_AXI_AWVALID || M_AXI_AWREADY) begin if (r_awlen > 15) begin axi_awlen <= 4'd15; r_awlen <= r_awlen - 8'd16; end else if (r_awlen > 0) begin axi_awlen[3:0] <= r_awlen[3:0] - 1; r_awlen <= 0; end else if (awskd_valid) begin if (awskd_len > 15) begin r_awlen <= awskd_len + 1'b1 - 8'd16; axi_awlen <= 4'd15; end else begin r_awlen <= 0; axi_awlen <= awskd_len[3:0]; end end else begin r_awlen <= 0; axi_awlen <= 0; end end always @(posedge S_AXI_ACLK) if (awskd_valid && awskd_ready) axi_awaddr <= awskd_addr; else if (M_AXI_AWVALID && M_AXI_AWREADY) begin // Verilator lint_off WIDTH axi_awaddr <= axi_awaddr + ((M_AXI_AWLEN + 1) << M_AXI_AWSIZE); // Verilator lint_on WIDTH case(M_AXI_AWSIZE) 3'b000: begin end 3'b001: axi_awaddr[ 0] <= 0; 3'b010: axi_awaddr[1:0] <= 0; 3'b011: axi_awaddr[2:0] <= 0; 3'b100: axi_awaddr[3:0] <= 0; 3'b101: axi_awaddr[4:0] <= 0; 3'b110: axi_awaddr[5:0] <= 0; 3'b111: axi_awaddr[6:0] <= 0; endcase end initial M_AXI_AWSIZE = ADDRLSB[2:0]; always @(posedge S_AXI_ACLK) begin if (awskd_valid && awskd_ready) begin axi_awid <= awskd_id; axi_awsize <= awskd_size; axi_awburst <= awskd_burst; axi_awlock[0]<=awskd_lock; axi_awcache <= awskd_cache; axi_awprot <= awskd_prot; axi_awqos <= awskd_qos; end if (C_AXI_DATA_WIDTH < 16) axi_awsize <= 3'b000; else if (C_AXI_DATA_WIDTH < 32) axi_awsize[2:1] <= 2'b00; else if (C_AXI_DATA_WIDTH < 128) axi_awsize[2] <= 1'b0; axi_awlock[1] <= 1'b0; end assign M_AXI_AWVALID = axi_awvalid; assign M_AXI_AWID = axi_awid; assign M_AXI_AWADDR = axi_awaddr; assign M_AXI_AWLEN = axi_awlen; assign M_AXI_AWSIZE = axi_awsize; assign M_AXI_AWBURST = axi_awburst; assign M_AXI_AWLOCK = axi_awlock; assign M_AXI_AWCACHE = axi_awcache; assign M_AXI_AWPROT = axi_awprot; assign M_AXI_AWQOS = axi_awqos; // }}} //////////////////////////////////////////////////////////////////////// // // Write data channel // {{{ //////////////////////////////////////////////////////////////////////// // // wire wskd_valid; reg wskd_ready, write_idle; wire [C_AXI_DATA_WIDTH-1:0] wskd_data; wire [C_AXI_DATA_WIDTH/8-1:0] wskd_strb; wire wskd_last; reg [4:0] r_wlen; wire [C_AXI_ID_WIDTH-1:0] wfifo_id, raw_wfifo_id; wire [3:0] wfifo_wlen, raw_wfifo_wlen; reg next_wlast, r_wlast; wire raw_wfifo_last; wire wfifo_empty, wfifo_full; wire [LGWFIFO:0] wfifo_fill; reg axi_wvalid; reg [C_AXI_DATA_WIDTH-1:0] axi_wdata; reg [C_AXI_DATA_WIDTH/8-1:0] axi_wstrb; reg [C_AXI_ID_WIDTH-1:0] axi_wid; reg axi_wlast; skidbuffer #( .DW(C_AXI_DATA_WIDTH + (C_AXI_DATA_WIDTH/8) + 1), .OPT_OUTREG(1'b0) ) wskid ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), .i_valid(S_AXI_WVALID), .o_ready(S_AXI_WREADY), .i_data({ S_AXI_WDATA, S_AXI_WSTRB, S_AXI_WLAST }), .o_valid(wskd_valid), .i_ready(wskd_ready), .o_data({ wskd_data, wskd_strb, wskd_last }) ); always @(*) wskd_ready = !M_AXI_WVALID || M_AXI_WREADY; initial axi_wvalid = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_wvalid <= 0; else if (wskd_valid) axi_wvalid <= 1; else if (M_AXI_WREADY) axi_wvalid <= 0; initial write_idle = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) write_idle <= 1; else if (M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST && !wskd_valid) write_idle <= 1; else if (wskd_valid && wskd_ready) write_idle <= 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN && OPT_LOWPOWER) begin axi_wdata <= 0; axi_wstrb <= 0; end else if (!M_AXI_WVALID || M_AXI_WREADY) begin axi_wdata <= wskd_data; axi_wstrb <= wskd_strb; if (OPT_LOWPOWER && !wskd_valid) begin axi_wdata <= 0; axi_wstrb <= 0; end end always @(*) begin if (r_awlen[7:4] != 0) next_wlen = 4'd15; else if (r_awlen[3:0] != 0) next_wlen = r_awlen[3:0]; else if (awskd_len[7:4] != 0) next_wlen = 4'd15; else next_wlen = awskd_len[3:0]; if (r_awlen != 0) next_wlast = (r_awlen[7:4] == 0); else next_wlast = (awskd_len[7:4] == 0); end sfifo #(.BW(C_AXI_ID_WIDTH+4+1), .LGFLEN(LGWFIFO)) wfifo(S_AXI_ACLK, !S_AXI_ARESETN, (!M_AXI_AWVALID || M_AXI_AWREADY)&&(awskd_valid||(r_awlen > 0)) && !write_idle, // The length of the next burst { ((r_awlen != 0) ? M_AXI_AWID : awskd_id), next_wlen, next_wlast }, wfifo_full, wfifo_fill, // (!M_AXI_WVALID || M_AXI_WREADY), { raw_wfifo_id, raw_wfifo_wlen, raw_wfifo_last }, wfifo_empty); assign wfifo_id = (wfifo_empty) ? awskd_id : raw_wfifo_id; assign wfifo_wlen = (wfifo_empty) ? next_wlen : raw_wfifo_wlen; initial r_wlen = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN && OPT_LOWPOWER) r_wlen <= 0; else if (!M_AXI_WVALID || M_AXI_WREADY) begin if (r_wlen > 1) r_wlen <= r_wlen - 1; else if (!wfifo_empty) r_wlen <= raw_wfifo_wlen + 1; else if (awskd_valid && awskd_ready) r_wlen <= next_wlen + 1; end initial r_wlast = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN && OPT_LOWPOWER) r_wlast <= 0; else if (!M_AXI_WVALID || M_AXI_WREADY) begin if (r_wlen > 0) r_wlast <= (r_wlen <= 1); else r_wlast <= raw_wfifo_last; end always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN && OPT_LOWPOWER) begin axi_wid <= 0; axi_wlast <= 0; end else if (!M_AXI_WVALID || M_AXI_WREADY) begin axi_wid <= wfifo_id; axi_wlast <= r_wlast; if (OPT_LOWPOWER && !wskd_valid) begin axi_wid <= 0; axi_wlast <= 0; end end assign M_AXI_WVALID = axi_wvalid; assign M_AXI_WDATA = axi_wdata; assign M_AXI_WSTRB = axi_wstrb; assign M_AXI_WID = axi_wid; assign M_AXI_WLAST = axi_wlast; // }}} //////////////////////////////////////////////////////////////////////// // // Write return channel // {{{ //////////////////////////////////////////////////////////////////////// // // wire bskd_valid; reg bskd_ready; wire [C_AXI_ID_WIDTH-1:0] bskd_id; wire [1:0] bskd_resp; reg [1:0] bburst_err [0:NID-1]; reg [NID-1:0] wbfifo_valid; reg [NID-1:0] wbfifo_last; reg axi_bvalid; reg [C_AXI_ID_WIDTH-1:0] axi_bid; reg [1:0] axi_bresp; skidbuffer #(.DW(C_AXI_ID_WIDTH + 2), .OPT_OUTREG(1'b0) ) bskid ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), .i_valid(M_AXI_BVALID), .o_ready(M_AXI_BREADY), .i_data({ M_AXI_BID, M_AXI_BRESP }), .o_valid(bskd_valid), .i_ready(bskd_ready), .o_data({ bskd_id, bskd_resp }) ); generate for(ID=0; ID < NID; ID = ID + 1) begin : WRITE_BURST_TRACKING wire wbfifo_empty, wbfifo_full; wire [LGFIFO:0] wbfifo_fill; initial wbfifo_valid[ID] = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) wbfifo_valid[ID] <= 0; else if (!wbfifo_valid[ID] && !wbfifo_empty) wbfifo_valid[ID] <= 1; else if (bskd_valid && bskd_ready && bskd_id==ID) wbfifo_valid[ID] <= !wbfifo_empty; sfifo #(.BW(1), .LGFLEN(LGFIFO)) wbfifo(S_AXI_ACLK, !S_AXI_ARESETN, (M_AXI_WVALID && M_AXI_WREADY && M_AXI_WLAST) && (M_AXI_WID == ID), (r_wlen == 0) ? 1'b1 : 1'b0, wbfifo_full, wbfifo_fill, // (!wbfifo_valid[ID] || (M_AXI_BVALID && M_AXI_BREADY && M_AXI_BID == ID)), wbfifo_last[ID], wbfifo_empty ); // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0, wbfifo_full, wbfifo_fill }; // Verilator lint_on UNUSED end endgenerate always @(*) bskd_ready = (!S_AXI_BVALID || S_AXI_BREADY); initial axi_bvalid = 1'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_bvalid <= 1'b0; else if (bskd_valid && bskd_ready) axi_bvalid <= wbfifo_last[bskd_id]; else if (M_AXI_BREADY) axi_bvalid <= 1'b0; generate for(ID=0; ID < NID; ID = ID + 1) begin : WRITE_ERR_BY_ID initial bburst_err[ID] = 2'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) bburst_err[ID] <= 2'b0; else if (S_AXI_BVALID && S_AXI_BREADY && S_AXI_BID == ID && wbfifo_last[ID]) bburst_err[ID] <= 2'b0; else if (bskd_valid && bskd_id == ID) bburst_err[ID] <= bburst_err[ID] | bskd_resp; end endgenerate initial axi_bid = 0; initial axi_bresp = 0; always @(posedge S_AXI_ACLK) if (OPT_LOWPOWER && !S_AXI_ARESETN) begin axi_bid <= 0; axi_bresp <= 0; end else if (!S_AXI_BVALID || S_AXI_BREADY) begin axi_bid <= bskd_id; axi_bresp <= bskd_resp | bburst_err[bskd_id]; if (OPT_LOWPOWER && !bskd_valid) begin axi_bid <= 0; axi_bresp <= 0; end end assign S_AXI_BVALID = axi_bvalid; assign S_AXI_BID = axi_bid; assign S_AXI_BRESP = axi_bresp; // }}} // }}} //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // READ SIDE // {{{ //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////// // // Read address channel // {{{ //////////////////////////////////////////////////////////////////////// // // reg [7:0] r_arlen; wire arskd_valid; reg arskd_ready; wire [C_AXI_ID_WIDTH-1:0] arskd_id; wire [C_AXI_ADDR_WIDTH-1:0] arskd_addr; wire [7:0] arskd_len; wire [2:0] arskd_size; wire [1:0] arskd_burst; wire arskd_lock; wire [3:0] arskd_cache; wire [2:0] arskd_prot; wire [3:0] arskd_qos; reg axi_arvalid; reg [C_AXI_ID_WIDTH-1:0] axi_arid; reg [C_AXI_ADDR_WIDTH-1:0] axi_araddr; reg [3:0] axi_arlen; reg [2:0] axi_arsize; reg [1:0] axi_arburst; reg [1:0] axi_arlock; reg [3:0] axi_arcache; reg [2:0] axi_arprot; reg [3:0] axi_arqos; skidbuffer #( .DW(C_AXI_ADDR_WIDTH + C_AXI_ID_WIDTH + 8 + 3 + 2 + 1+4+3+4), .OPT_OUTREG(1'b0) ) arskid ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), .i_valid(S_AXI_ARVALID), .o_ready(S_AXI_ARREADY), .i_data({ S_AXI_ARID, S_AXI_ARADDR, S_AXI_ARLEN, S_AXI_ARSIZE, S_AXI_ARBURST, S_AXI_ARLOCK, S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS }), .o_valid(arskd_valid), .i_ready(arskd_ready), .o_data({ arskd_id, arskd_addr, arskd_len, arskd_size, arskd_burst, arskd_lock, arskd_cache, arskd_prot, arskd_qos }) ); always @(*) begin arskd_ready = 1; if (r_arlen > 0) arskd_ready = 0; if (M_AXI_ARVALID && M_AXI_ARREADY) arskd_ready = 0; end initial axi_arvalid = 1'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_arvalid <= 1'b0; else if (r_arlen > 0) axi_arvalid <= 1'b1; else if (arskd_ready) axi_arvalid <= 1'b1; else if (M_AXI_ARREADY) axi_arvalid <= 1'b0; initial r_arlen = 0; initial M_AXI_ARLEN = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) begin r_arlen <= 0; axi_arlen <= 0; end else if (!M_AXI_ARVALID || M_AXI_ARREADY) begin if (r_arlen[7:4] != 0) begin axi_arlen <= 4'd15; r_arlen <= r_arlen - 16; end else if (r_arlen[3:0] != 0) begin axi_arlen <= r_arlen[3:0] - 1; r_arlen <= 0; end else if (arskd_valid) begin if (arskd_len[7:4] != 0) begin r_arlen <= arskd_len + 1 - 16; axi_arlen <= 4'd15; end else begin r_arlen <= 0; axi_arlen <= arskd_len[3:0]; end end else begin r_arlen <= 0; axi_arlen <= 0; end end always @(posedge S_AXI_ACLK) if (arskd_valid && arskd_ready) axi_araddr <= arskd_addr; else if (M_AXI_ARVALID && M_AXI_ARREADY) begin // Verilator lint_off WIDTH axi_araddr <= axi_araddr + ((M_AXI_ARLEN + 1) << M_AXI_ARSIZE); // Verilator lint_on WIDTH case(M_AXI_AWSIZE) 3'b000: begin end 3'b001: axi_araddr[ 0] <= 0; 3'b010: axi_araddr[1:0] <= 0; 3'b011: axi_araddr[2:0] <= 0; 3'b100: axi_araddr[3:0] <= 0; 3'b101: axi_araddr[4:0] <= 0; 3'b110: axi_araddr[5:0] <= 0; 3'b111: axi_araddr[6:0] <= 0; endcase end initial axi_arsize = ADDRLSB[2:0]; always @(posedge S_AXI_ACLK) begin if (arskd_valid && arskd_ready) begin axi_arid <= arskd_id; axi_arsize <= arskd_size; axi_arburst <= arskd_burst; axi_arlock[0] <= arskd_lock; axi_arcache <= arskd_cache; axi_arprot <= arskd_prot; axi_arqos <= arskd_qos; end // Propagate constants, to help the optimizer out out a touch axi_arlock[1] <= 1'b0; if (C_AXI_DATA_WIDTH < 16) axi_arsize <= 3'b000; else if (C_AXI_DATA_WIDTH < 32) axi_arsize[2:1] <= 2'b00; else if (C_AXI_DATA_WIDTH < 128) axi_arsize[2] <= 1'b0; end generate for(ID=0; ID < NID; ID = ID + 1) begin : READ_BURST_TRACKING wire rbfifo_empty, rbfifo_full; wire [LGFIFO:0] rbfifo_fill; initial rbfifo_valid[ID] = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) rbfifo_valid[ID] <= 0; else if (!rbfifo_valid[ID] && !rbfifo_empty) rbfifo_valid[ID] <= 1; else if (rskd_valid && rskd_ready && rskd_last && rskd_id==ID) rbfifo_valid[ID] <= !rbfifo_empty; sfifo #(.BW(1), .LGFLEN(LGFIFO)) rbfifo(S_AXI_ACLK, !S_AXI_ARESETN, (!M_AXI_ARVALID || M_AXI_ARREADY) && (((r_arlen>0)&&(M_AXI_ARID==ID)) || (arskd_valid && arskd_id == ID)), ((arskd_valid && arskd_ready && arskd_len <= 15) ||(r_arlen <= 15)) ? 1'b1 : 1'b0, rbfifo_full, rbfifo_fill, // (!rbfifo_valid[ID] || (M_AXI_RVALID && M_AXI_RREADY && M_AXI_RID == ID && M_AXI_RLAST)), rid_last[ID], rbfifo_empty ); // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0, rbfifo_full, rbfifo_fill }; // Verilator lint_on UNUSED end endgenerate assign M_AXI_ARVALID= axi_arvalid; assign M_AXI_ARID = axi_arid; assign M_AXI_ARADDR = axi_araddr; assign M_AXI_ARLEN = axi_arlen; assign M_AXI_ARSIZE = axi_arsize; assign M_AXI_ARBURST= axi_arburst; assign M_AXI_ARLOCK = axi_arlock; assign M_AXI_ARCACHE= axi_arcache; assign M_AXI_ARPROT = axi_arprot; assign M_AXI_ARQOS = axi_arqos; // }}} //////////////////////////////////////////////////////////////////////// // // Read data channel // {{{ //////////////////////////////////////////////////////////////////////// // // wire rskd_valid; reg rskd_ready; wire [C_AXI_ID_WIDTH-1:0] rskd_id; wire [C_AXI_DATA_WIDTH-1:0] rskd_data; wire rskd_last; wire [1:0] rskd_resp; reg [1:0] rburst_err [0:NID-1]; reg [NID-1:0] rbfifo_valid; reg [NID-1:0] rid_last; reg axi_rvalid; reg [C_AXI_ID_WIDTH-1:0] axi_rid; reg [C_AXI_DATA_WIDTH-1:0] axi_rdata; reg axi_rlast; reg [1:0] axi_rresp; skidbuffer #( .DW(C_AXI_DATA_WIDTH + C_AXI_ID_WIDTH + 3), .OPT_OUTREG(1'b0) ) rskid ( .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), .i_valid(M_AXI_RVALID), .o_ready(M_AXI_RREADY), .i_data({ M_AXI_RID, M_AXI_RDATA, M_AXI_RLAST, M_AXI_RRESP }), .o_valid(rskd_valid), .i_ready(rskd_ready), .o_data({ rskd_id, rskd_data, rskd_last, rskd_resp }) ); always @(*) rskd_ready = !S_AXI_RVALID || S_AXI_RREADY; initial axi_rvalid = 1'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) axi_rvalid <= 1'b0; else if (rskd_valid && rskd_ready) axi_rvalid <= 1'b1; else if (S_AXI_RREADY) axi_rvalid <= 1'b0; generate for(ID=0; ID < NID; ID = ID + 1) begin : READ_ERR_BY_ID initial rburst_err[ID] = 2'b0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) rburst_err[ID] <= 2'b0; else if (S_AXI_RVALID && S_AXI_RREADY && S_AXI_RLAST && S_AXI_RID == ID) rburst_err[ID] <= 2'b0; else if (rskd_valid && rskd_id == ID) rburst_err[ID] <= rburst_err[ID] | rskd_resp; end endgenerate always @(posedge S_AXI_ACLK) if (!S_AXI_RVALID || S_AXI_RREADY) begin axi_rid <= rskd_id; axi_rdata <= rskd_data; axi_rresp <= rskd_resp | rburst_err[rskd_id]; axi_rlast <= rid_last[rskd_id] && rskd_last; end assign S_AXI_RVALID= axi_rvalid; assign S_AXI_RID = axi_rid; assign S_AXI_RDATA = axi_rdata; assign S_AXI_RRESP = axi_rresp; assign S_AXI_RLAST = axi_rlast; // }}} // }}} // Make Verilator happy // {{{ // Verilator lint_off UNUSED wire unused; assign unused = &{ 1'b0, wfifo_fill[LGWFIFO-2:0], wskd_last, wfifo_wlen, wfifo_full }; // Verilator lint_on UNUSED // }}} //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// // // Formal property section // //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// `ifdef FORMAL // // This design has not been formally verified. // `endif endmodule