//////////////////////////////////////////////////////////////////////////////// // // Filename: axi3reorder.v // {{{ // Project: WB2AXIPSP: bus bridges and other odds and ends // // Purpose: One of the challenges of working with AXI3 are the (potentially) // out of order writes. This modules is designed to re-order write // beats back into the proper order given by the AW* channel. Once done, // write beats will always be contiguous--only changing ID's after WLAST. // Indeed, once done, the WID field can be properly removed and ignored. // it's left within for forms sake, but isn't required. // // Algorithms: // The design currently contains one of three reordering algorithms. // // MTHD_NONE Is a basic pass-through. This would be appropriate // for AXI3 streams that are known to be in order already. // // MTHD_SHIFT_REGISTER Uses a shift-register based "FIFO". (Not block // RAM) All write data goes into this FIFO. Items // are read from this FIFO out of order as required for // the given ID. When any item is read from the middle, // the shift register back around the item read. // // This is a compromise implementation that uses less // logic than the PER/ID FIFOS, while still allowing some // amount of reordering to take place. // // MTHD_PERID_FIFOS Uses an explicit FIFO for each ID. Data come // into the core and go directly into the FIFO's. // Data are read out of the FIFOs in write-address order // until WLAST, where the write address may (potentially) // change. // // For a small number of IDs, this solution should be // *complete*, and lacking nothing. (Unless you fill the // write data FIFO's while needing data from another ID ..) // // Implementation notes: // This module is intended to be used side by side with other AW* channel // processing, and following an (external) AW* skidbuffer. For this // reason, it doesn't use an AW skid buffer, nor does it output AW* // information. External AWREADY handling should therefore be: // // master_awskid_read = reorder_awready && any_other_awready; // // going into a skid buffer, with the proper AWREADY being the upstream // skidbuffer's AWREADY output. // // Expected performance: // One beat per clock, all methods. // // Status: // This module passes both a Verilator lint check and a 15-20 step formal // bounded model check. // // 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 axi3reorder #( // {{{ parameter C_AXI_ID_WIDTH = 4, parameter C_AXI_DATA_WIDTH = 32, parameter LGAWFIFO = 3, // # packets we can handle parameter LGWFIFO = 4, // Full size of an AXI burst parameter OPT_METHOD = 0, parameter [0:0] OPT_LOWPOWER = 0, parameter [0:0] OPT_LOW_LATENCY = 0, parameter NUM_FIFOS = (1< 0)&&(sr_advance[gk-1])) sr_advance[gk] = 1; if ((!M_AXI_WVALID || M_AXI_WREADY) && cid_valid && current_id == sr_id[gk]) sr_advance[gk] = 1; if (!sr_valid[gk]) sr_advance[gk] = 0; end // }}} // sw_write // {{{ // Do we write new data into this station? always @(*) begin sr_write[gk] = S_AXI3_WVALID && S_AXI3_WREADY; if (sr_valid[gk] && (!sr_advance[gk] ||(gk < NSREG-1 && sr_valid[gk+1]))) sr_write[gk] = 0; if (gk > 0 && (!sr_valid[gk-1] || (sr_advance[gk-1] && !sr_valid[gk]))) sr_write[gk] = 0; end // }}} // sr_valid // {{{ initial sr_valid[gk] = 0; always @(posedge S_AXI_ACLK) if (!S_AXI_ARESETN) sr_valid[gk] <= 0; else if (sr_write[gk]) sr_valid[gk] <= 1; else if (sr_advance[gk] && gk 0); generate if (OPT_LOWPOWER) begin : F_LOWPOWER_CHECK always @(*) if (!S_AXI3_AWVALID) assume(S_AXI3_AWID == 0); always @(*) if (!S_AXI3_WVALID) begin assume(S_AXI3_WID == 0); assume(S_AXI3_WDATA == 0); assume(S_AXI3_WSTRB == 0); assume(S_AXI3_WLAST == 0); end always @(*) if (!M_AXI_WVALID) begin assert(M_AXI_WID == 0); assert(M_AXI_WDATA == 0); assert(M_AXI_WSTRB == 0); assert(M_AXI_WLAST == 0); end end endgenerate `endif // }}} endmodule