// ----------------------------------------------------------------------
// Copyright (c) 2015, The Regents of the University of California All
// rights reserved.
// 
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
// 
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
// 
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
// 
//     * Neither the name of The Regents of the University of California
//       nor the names of its contributors may be used to endorse or
//       promote products derived from this software without specific
//       prior written permission.
// 
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL REGENTS OF THE
// UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
// TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
// DAMAGE.
// ----------------------------------------------------------------------
`include "trellis.vh"
`include "riffa.vh"
`timescale 1ns/1ns
module riffa
    #(
      parameter C_PCI_DATA_WIDTH = 128,
      parameter C_NUM_CHNL = 12,
      parameter C_MAX_READ_REQ_BYTES = 512, // Max size of read requests (in bytes)
      parameter C_TAG_WIDTH = 5, // Number of outstanding requests 
      parameter C_VENDOR = "ALTERA",
      parameter C_FPGA_NAME = "FPGA",
      parameter C_DEPTH_PACKETS = 10
      )
    (
     input                                      CLK,
     input                                      RST_IN,
     output                                     RST_OUT,
    
     // Interface: RXC Engine
     input [C_PCI_DATA_WIDTH-1:0]               RXC_DATA,
     input                                      RXC_DATA_VALID,
     input [(C_PCI_DATA_WIDTH/32)-1:0]          RXC_DATA_WORD_ENABLE,
     input                                      RXC_DATA_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    RXC_DATA_START_OFFSET,
     input                                      RXC_DATA_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    RXC_DATA_END_OFFSET,

     input [`SIG_LBE_W-1:0]                     RXC_META_LDWBE,
     input [`SIG_FBE_W-1:0]                     RXC_META_FDWBE,
     input [`SIG_TAG_W-1:0]                     RXC_META_TAG,
     input [`SIG_LOWADDR_W-1:0]                 RXC_META_ADDR,
     input [`SIG_TYPE_W-1:0]                    RXC_META_TYPE,
     input [`SIG_LEN_W-1:0]                     RXC_META_LENGTH,
     input [`SIG_BYTECNT_W-1:0]                 RXC_META_BYTES_REMAINING,
     input [`SIG_CPLID_W-1:0]                   RXC_META_COMPLETER_ID,
     input                                      RXC_META_EP,

     // Interface: RXR Engine
     input [C_PCI_DATA_WIDTH-1:0]               RXR_DATA,
     input                                      RXR_DATA_VALID,
     input [(C_PCI_DATA_WIDTH/32)-1:0]          RXR_DATA_WORD_ENABLE,
     input                                      RXR_DATA_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    RXR_DATA_START_OFFSET,
     input                                      RXR_DATA_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    RXR_DATA_END_OFFSET,
    
     input [`SIG_FBE_W-1:0]                     RXR_META_FDWBE,
     input [`SIG_LBE_W-1:0]                     RXR_META_LDWBE,
     input [`SIG_TC_W-1:0]                      RXR_META_TC,
     input [`SIG_ATTR_W-1:0]                    RXR_META_ATTR,
     input [`SIG_TAG_W-1:0]                     RXR_META_TAG,
     input [`SIG_TYPE_W-1:0]                    RXR_META_TYPE,
     input [`SIG_ADDR_W-1:0]                    RXR_META_ADDR,
     input [`SIG_BARDECODE_W-1:0]               RXR_META_BAR_DECODED,
     input [`SIG_REQID_W-1:0]                   RXR_META_REQUESTER_ID,
     input [`SIG_LEN_W-1:0]                     RXR_META_LENGTH,
     input                                      RXR_META_EP,
    
     // Interface: TXC Engine
     output [C_PCI_DATA_WIDTH-1:0]              TXC_DATA,
     output                                     TXC_DATA_VALID,
     output                                     TXC_DATA_START_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0]   TXC_DATA_START_OFFSET,
     output                                     TXC_DATA_END_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0]   TXC_DATA_END_OFFSET,
     input                                      TXC_DATA_READY,

     output                                     TXC_META_VALID,
     output [`SIG_FBE_W-1:0]                    TXC_META_FDWBE,
     output [`SIG_LBE_W-1:0]                    TXC_META_LDWBE,
     output [`SIG_LOWADDR_W-1:0]                TXC_META_ADDR,
     output [`SIG_TYPE_W-1:0]                   TXC_META_TYPE,
     output [`SIG_LEN_W-1:0]                    TXC_META_LENGTH,
     output [`SIG_BYTECNT_W-1:0]                TXC_META_BYTE_COUNT,
     output [`SIG_TAG_W-1:0]                    TXC_META_TAG,
     output [`SIG_REQID_W-1:0]                  TXC_META_REQUESTER_ID,
     output [`SIG_TC_W-1:0]                     TXC_META_TC,
     output [`SIG_ATTR_W-1:0]                   TXC_META_ATTR,
     output                                     TXC_META_EP,
     input                                      TXC_META_READY,
     input                                      TXC_SENT,

     // Interface: TXR Engine
     output                                     TXR_DATA_VALID,
     output [C_PCI_DATA_WIDTH-1:0]              TXR_DATA,
     output                                     TXR_DATA_START_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0]   TXR_DATA_START_OFFSET,
     output                                     TXR_DATA_END_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0]   TXR_DATA_END_OFFSET,
     input                                      TXR_DATA_READY,

     output                                     TXR_META_VALID,
     output [`SIG_FBE_W-1:0]                    TXR_META_FDWBE, 
     output [`SIG_LBE_W-1:0]                    TXR_META_LDWBE,
     output [`SIG_ADDR_W-1:0]                   TXR_META_ADDR,
     output [`SIG_LEN_W-1:0]                    TXR_META_LENGTH,
     output [`SIG_TAG_W-1:0]                    TXR_META_TAG,
     output [`SIG_TC_W-1:0]                     TXR_META_TC,
     output [`SIG_ATTR_W-1:0]                   TXR_META_ATTR,
     output [`SIG_TYPE_W-1:0]                   TXR_META_TYPE,
     output                                     TXR_META_EP,
     input                                      TXR_META_READY,
     input                                      TXR_SENT,

     // Interface: Configuration 
     input [`SIG_CPLID_W-1:0]                   CONFIG_COMPLETER_ID,
     input                                      CONFIG_BUS_MASTER_ENABLE, 
     input [`SIG_LINKWIDTH_W-1:0]               CONFIG_LINK_WIDTH,
     input [`SIG_LINKRATE_W-1:0]                CONFIG_LINK_RATE,
     input [`SIG_MAXREAD_W-1:0]                 CONFIG_MAX_READ_REQUEST_SIZE, 
     input [`SIG_MAXPAYLOAD_W-1:0]              CONFIG_MAX_PAYLOAD_SIZE,
     input [`SIG_FC_CPLD_W-1:0]                 CONFIG_MAX_CPL_DATA, // Receive credit limit for data
     input [`SIG_FC_CPLH_W-1:0]                 CONFIG_MAX_CPL_HDR, // Receive credit limit for headers
     input                                      CONFIG_INTERRUPT_MSIENABLE,
     input                                      CONFIG_CPL_BOUNDARY_SEL,
     // Interrupt Request
     input                                      INTR_MSI_RDY, // High when interrupt is able to be sent
     output                                     INTR_MSI_REQUEST, // High to request interrupt, when both INTR_MSI_RDY and INTR_MSI_RE

     input [C_NUM_CHNL-1:0]                     CHNL_RX_CLK, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX, 
     input [C_NUM_CHNL-1:0]                     CHNL_RX_ACK, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX_LAST, 
     output [(C_NUM_CHNL*32)-1:0]               CHNL_RX_LEN, 
     output [(C_NUM_CHNL*31)-1:0]               CHNL_RX_OFF, 
     output [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0] CHNL_RX_DATA, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX_DATA_VALID, 
     input [C_NUM_CHNL-1:0]                     CHNL_RX_DATA_REN,
    
     input [C_NUM_CHNL-1:0]                     CHNL_TX_CLK, 
     input [C_NUM_CHNL-1:0]                     CHNL_TX, 
     output [C_NUM_CHNL-1:0]                    CHNL_TX_ACK,
     input [C_NUM_CHNL-1:0]                     CHNL_TX_LAST, 
     input [(C_NUM_CHNL*32)-1:0]                CHNL_TX_LEN, 
     input [(C_NUM_CHNL*31)-1:0]                CHNL_TX_OFF, 
     input [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]  CHNL_TX_DATA, 
     input [C_NUM_CHNL-1:0]                     CHNL_TX_DATA_VALID, 
     output [C_NUM_CHNL-1:0]                    CHNL_TX_DATA_REN

     );
    localparam C_MAX_READ_REQ = clog2s(C_MAX_READ_REQ_BYTES)-7;    // Max read: 000=128B; 001=256B; 010=512B; 011=1024B; 100=2048B; 101=4096B
    localparam C_NUM_CHNL_WIDTH = clog2s(C_NUM_CHNL);
    localparam C_PCI_DATA_WORD_WIDTH = clog2s((C_PCI_DATA_WIDTH/32)+1);
    localparam C_NUM_VECTORS = 2;
    localparam C_VECTOR_WIDTH = 32;

    // Interface: Reorder Buffer Output
    wire [(C_NUM_CHNL*C_PCI_DATA_WORD_WIDTH)-1:0] wRxEngMainDataEn; // Start offset and end offset
    wire [C_PCI_DATA_WIDTH-1:0]                   wRxEngData;
    wire [C_NUM_CHNL-1:0]                         wRxEngMainDone;
    wire [C_NUM_CHNL-1:0]                         wRxEngMainErr;

    // Interface: Reorder Buffer to SG RX engines    
    wire [(C_NUM_CHNL*C_PCI_DATA_WORD_WIDTH)-1:0] wRxEngSgRxDataEn;
    wire [C_NUM_CHNL-1:0]                         wRxEngSgRxDone;
    wire [C_NUM_CHNL-1:0]                         wRxEngSgRxErr;
    
    // Interface: Reorder Buffer to SG TX engines    
    wire [(C_NUM_CHNL*C_PCI_DATA_WORD_WIDTH)-1:0] wRxEngSgTxDataEn;
    wire [C_NUM_CHNL-1:0]                         wRxEngSgTxDone;
    wire [C_NUM_CHNL-1:0]                         wRxEngSgTxErr;

    // Interface: Channel TX Write
    wire [C_NUM_CHNL-1:0]                         wTxEngWrReq;
    wire [(C_NUM_CHNL*`SIG_ADDR_W)-1:0]           wTxEngWrAddr;
    wire [(C_NUM_CHNL*`SIG_LEN_W)-1:0]            wTxEngWrLen;
    wire [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]      wTxEngWrData;
    wire [C_NUM_CHNL-1:0]                         wTxEngWrDataRen;
    wire [C_NUM_CHNL-1:0]                         wTxEngWrAck; 
    wire [C_NUM_CHNL-1:0]                         wTxEngWrSent;

    // Interface: Channel TX Read
    wire [C_NUM_CHNL-1:0]                         wTxEngRdReq;
    wire [(C_NUM_CHNL*2)-1:0]                     wTxEngRdSgChnl;
    wire [(C_NUM_CHNL*`SIG_ADDR_W)-1:0]           wTxEngRdAddr;
    wire [(C_NUM_CHNL*`SIG_LEN_W)-1:0]            wTxEngRdLen;
    wire [C_NUM_CHNL-1:0]                         wTxEngRdAck;

    // Interface: Channel Interrupts
    wire [C_NUM_CHNL-1:0]                         wChnlSgRxBufRecvd;
    wire [C_NUM_CHNL-1:0]                         wChnlRxDone;
    wire [C_NUM_CHNL-1:0]                         wChnlTxRequest;
    wire [C_NUM_CHNL-1:0]                         wChnlTxDone;
    wire [C_NUM_CHNL-1:0]                         wChnlSgTxBufRecvd;

    wire                                          wInternalTagValid;
    wire [5:0]                                    wInternalTag;
    wire                                          wExternalTagValid;
    wire [C_TAG_WIDTH-1:0]                        wExternalTag;

    // Interface: Channel - PIO Read
    wire [C_NUM_CHNL-1:0]                         wChnlTxLenReady;
    wire [(`SIG_TXRLEN_W*C_NUM_CHNL)-1:0]         wChnlTxReqLen;
    wire [C_NUM_CHNL-1:0]                         wChnlTxOfflastReady;
    wire [(`SIG_OFFLAST_W*C_NUM_CHNL)-1:0]        wChnlTxOfflast;
    wire                                          wCoreSettingsReady;
    wire [`SIG_CORESETTINGS_W-1:0]                wCoreSettings;
    wire [C_NUM_VECTORS-1:0]                      wIntrVectorReady;
    wire [C_NUM_VECTORS*C_VECTOR_WIDTH-1:0]       wIntrVector;
    wire [C_NUM_CHNL-1:0]                         wChnlTxDoneReady;
    wire [(`SIG_TXDONELEN_W*C_NUM_CHNL)-1:0]      wChnlTxDoneLen;
    wire [C_NUM_CHNL-1:0]                         wChnlRxDoneReady;
    wire [(`SIG_RXDONELEN_W*C_NUM_CHNL)-1:0]      wChnlRxDoneLen;
    wire                                          wChnlNameReady;

    // Interface: Channel - PIO Write
    wire [31:0]                                   wChnlReqData; 
    wire [C_NUM_CHNL-1:0]                         wChnlSgRxLenValid;
    wire [C_NUM_CHNL-1:0]                         wChnlSgRxAddrLoValid;
    wire [C_NUM_CHNL-1:0]                         wChnlSgRxAddrHiValid;
    wire [C_NUM_CHNL-1:0]                         wChnlSgTxLenValid;
    wire [C_NUM_CHNL-1:0]                         wChnlSgTxAddrLoValid;
    wire [C_NUM_CHNL-1:0]                         wChnlSgTxAddrHiValid;
    wire [C_NUM_CHNL-1:0]                         wChnlRxLenValid;
    wire [C_NUM_CHNL-1:0]                         wChnlRxOfflastValid;

    wire                                          wRxBufSpaceAvail;
    wire                                          wTxEngRdReqSent;
    wire                                          wRxEngRdComplete;

    reg [4:0]                                     rWideRst;
    reg                                           rRst;

    genvar                                        i;

    assign wRxEngRdComplete = RXC_DATA_END_FLAG & RXC_DATA_VALID & 
                              (RXC_META_LENGTH >= RXC_META_BYTES_REMAINING[`SIG_BYTECNT_W-1:2]);// TODO: Retime (if possible)

    assign wCoreSettings = {9'd0, C_PCI_DATA_WIDTH[8:5], CONFIG_MAX_PAYLOAD_SIZE, CONFIG_MAX_READ_REQUEST_SIZE, CONFIG_LINK_RATE[1:0], CONFIG_LINK_WIDTH, CONFIG_BUS_MASTER_ENABLE, C_NUM_CHNL[3:0]};
    
    assign RST_OUT = rRst;
    always @ (posedge CLK) begin
        rRst <= #1 rWideRst[4]; 
        if (RST_IN | (wCoreSettingsReady /*& wRxEngReqRdDone*/)) // TODO: 
            rWideRst <= #1 5'b11111;
        else 
            rWideRst <= (rWideRst<<1);
    end

    reorder_queue 
        #( 
           .C_PCI_DATA_WIDTH(C_PCI_DATA_WIDTH),
           .C_NUM_CHNL(C_NUM_CHNL),
           .C_MAX_READ_REQ_BYTES(C_MAX_READ_REQ_BYTES),
           .C_TAG_WIDTH(C_TAG_WIDTH)
           ) 
    reorderQueue 
        (
         .RST                           (rRst),
         .VALID                         (RXC_DATA_VALID),
         .DATA_START_FLAG               (RXC_DATA_START_FLAG),
         .DATA_START_OFFSET             (RXC_DATA_START_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .DATA_END_FLAG                 (RXC_DATA_END_FLAG),
         .DATA_END_OFFSET               (RXC_DATA_END_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .DATA                          (RXC_DATA),
         .DATA_EN                       (RXC_DATA_WORD_ENABLE),
         .DONE                          (wRxEngRdComplete),
         .ERR                           (RXC_META_EP),
         .TAG                           (RXC_META_TAG[C_TAG_WIDTH-1:0]), 
         .INT_TAG                       (wInternalTag),
         .INT_TAG_VALID                 (wInternalTagValid),
         .EXT_TAG                       (wExternalTag),
         .EXT_TAG_VALID                 (wExternalTagValid),
         .ENG_DATA                      (wRxEngData), 
         .MAIN_DATA_EN                  (wRxEngMainDataEn),
         .MAIN_DONE                     (wRxEngMainDone),
         .MAIN_ERR                      (wRxEngMainErr),
         .SG_RX_DATA_EN                 (wRxEngSgRxDataEn),
         .SG_RX_DONE                    (wRxEngSgRxDone),
         .SG_RX_ERR                     (wRxEngSgRxErr),
         .SG_TX_DATA_EN                 (wRxEngSgTxDataEn), 
         .SG_TX_DONE                    (wRxEngSgTxDone), 
         .SG_TX_ERR                     (wRxEngSgTxErr),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK));

    registers
        #(// Parameters
          .C_PIPELINE_OUTPUT            (1),
          .C_PIPELINE_INPUT             (1),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_NUM_CHNL                   (C_NUM_CHNL),
          .C_MAX_READ_REQ_BYTES         (C_MAX_READ_REQ_BYTES),
          .C_VENDOR                     (C_VENDOR),
          .C_NUM_VECTORS                (C_NUM_VECTORS),
          .C_VECTOR_WIDTH               (C_VECTOR_WIDTH),
          .C_FPGA_NAME                  (C_FPGA_NAME))
    reg_inst
        (// Outputs
         // Write Interfaces
         .CHNL_REQ_DATA                 (wChnlReqData[31:0]),
         .CHNL_SGRX_LEN_VALID           (wChnlSgRxLenValid),
         .CHNL_SGRX_ADDRLO_VALID        (wChnlSgRxAddrLoValid),
         .CHNL_SGRX_ADDRHI_VALID        (wChnlSgRxAddrHiValid),
         .CHNL_SGTX_LEN_VALID           (wChnlSgTxLenValid),
         .CHNL_SGTX_ADDRLO_VALID        (wChnlSgTxAddrLoValid),
         .CHNL_SGTX_ADDRHI_VALID        (wChnlSgTxAddrHiValid),
         .CHNL_RX_LEN_VALID             (wChnlRxLenValid),
         .CHNL_RX_OFFLAST_VALID         (wChnlRxOfflastValid),
         // Read Interfaces
         .CHNL_TX_LEN_READY             (wChnlTxLenReady),
         .CHNL_TX_OFFLAST_READY         (wChnlTxOfflastReady),
         .CORE_SETTINGS_READY           (wCoreSettingsReady),
         .INTR_VECTOR_READY             (wIntrVectorReady),
         .CHNL_TX_DONE_READY            (wChnlTxDoneReady),
         .CHNL_RX_DONE_READY            (wChnlRxDoneReady),
         .CHNL_NAME_READY               (wChnlNameReady), // TODO: Could do this on a per-channel basis
         // Inputs
         // Read Data
         .CORE_SETTINGS                 (wCoreSettings),
         .CHNL_TX_REQLEN                (wChnlTxReqLen),
         .CHNL_TX_OFFLAST               (wChnlTxOfflast),
         .CHNL_TX_DONELEN               (wChnlTxDoneLen),
         .CHNL_RX_DONELEN               (wChnlRxDoneLen),
         .INTR_VECTOR                   (wIntrVector),
         .RST_IN                        (rRst),
         /*AUTOINST*/
         // Outputs
         .TXC_DATA_VALID                (TXC_DATA_VALID),
         .TXC_DATA                      (TXC_DATA[C_PCI_DATA_WIDTH-1:0]),
         .TXC_DATA_START_FLAG           (TXC_DATA_START_FLAG),
         .TXC_DATA_START_OFFSET         (TXC_DATA_START_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXC_DATA_END_FLAG             (TXC_DATA_END_FLAG),
         .TXC_DATA_END_OFFSET           (TXC_DATA_END_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXC_META_VALID                (TXC_META_VALID),
         .TXC_META_FDWBE                (TXC_META_FDWBE[`SIG_FBE_W-1:0]),
         .TXC_META_LDWBE                (TXC_META_LDWBE[`SIG_LBE_W-1:0]),
         .TXC_META_ADDR                 (TXC_META_ADDR[`SIG_LOWADDR_W-1:0]),
         .TXC_META_TYPE                 (TXC_META_TYPE[`SIG_TYPE_W-1:0]),
         .TXC_META_LENGTH               (TXC_META_LENGTH[`SIG_LEN_W-1:0]),
         .TXC_META_BYTE_COUNT           (TXC_META_BYTE_COUNT[`SIG_BYTECNT_W-1:0]),
         .TXC_META_TAG                  (TXC_META_TAG[`SIG_TAG_W-1:0]),
         .TXC_META_REQUESTER_ID         (TXC_META_REQUESTER_ID[`SIG_REQID_W-1:0]),
         .TXC_META_TC                   (TXC_META_TC[`SIG_TC_W-1:0]),
         .TXC_META_ATTR                 (TXC_META_ATTR[`SIG_ATTR_W-1:0]),
         .TXC_META_EP                   (TXC_META_EP),
         // Inputs
         .CLK                           (CLK),
         .RXR_DATA                      (RXR_DATA[C_PCI_DATA_WIDTH-1:0]),
         .RXR_DATA_VALID                (RXR_DATA_VALID),
         .RXR_DATA_START_FLAG           (RXR_DATA_START_FLAG),
         .RXR_DATA_START_OFFSET         (RXR_DATA_START_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .RXR_META_FDWBE                (RXR_META_FDWBE[`SIG_FBE_W-1:0]),
         .RXR_DATA_END_FLAG             (RXR_DATA_END_FLAG),
         .RXR_DATA_END_OFFSET           (RXR_DATA_END_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .RXR_META_LDWBE                (RXR_META_LDWBE[`SIG_LBE_W-1:0]),
         .RXR_META_TC                   (RXR_META_TC[`SIG_TC_W-1:0]),
         .RXR_META_ATTR                 (RXR_META_ATTR[`SIG_ATTR_W-1:0]),
         .RXR_META_TAG                  (RXR_META_TAG[`SIG_TAG_W-1:0]),
         .RXR_META_TYPE                 (RXR_META_TYPE[`SIG_TYPE_W-1:0]),
         .RXR_META_ADDR                 (RXR_META_ADDR[`SIG_ADDR_W-1:0]),
         .RXR_META_BAR_DECODED          (RXR_META_BAR_DECODED[`SIG_BARDECODE_W-1:0]),
         .RXR_META_REQUESTER_ID         (RXR_META_REQUESTER_ID[`SIG_REQID_W-1:0]),
         .RXR_META_LENGTH               (RXR_META_LENGTH[`SIG_LEN_W-1:0]),
         .TXC_DATA_READY                (TXC_DATA_READY),
         .TXC_META_READY                (TXC_META_READY));
    
    // Track receive buffer flow control credits (header & Data)
    recv_credit_flow_ctrl rc_fc 
        (
         // Outputs
         .RXBUF_SPACE_AVAIL             (wRxBufSpaceAvail),
         // Inputs
         .RX_ENG_RD_DONE                (wRxEngRdComplete),
         .TX_ENG_RD_REQ_SENT            (wTxEngRdReqSent),
         .RST                           (rRst),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK),
         .CONFIG_MAX_READ_REQUEST_SIZE  (CONFIG_MAX_READ_REQUEST_SIZE[2:0]),
         .CONFIG_MAX_CPL_DATA           (CONFIG_MAX_CPL_DATA[11:0]),
         .CONFIG_MAX_CPL_HDR            (CONFIG_MAX_CPL_HDR[7:0]),
         .CONFIG_CPL_BOUNDARY_SEL       (CONFIG_CPL_BOUNDARY_SEL));
    // Connect the interrupt vector and controller.
    interrupt 
        #(
          .C_NUM_CHNL                   (C_NUM_CHNL)
          ) 
    intr 
        (// Inputs
         .RST                           (rRst),
         .RX_SG_BUF_RECVD               (wChnlSgRxBufRecvd),
         .RX_TXN_DONE                   (wChnlRxDone),
         .TX_TXN                        (wChnlTxRequest),
         .TX_SG_BUF_RECVD               (wChnlSgTxBufRecvd),
         .TX_TXN_DONE                   (wChnlTxDone),
         .VECT_0_RST                    (wIntrVectorReady[0]),
         .VECT_1_RST                    (wIntrVectorReady[1]),
         .VECT_RST                      (TXC_DATA[31:0]),
         .VECT_0                        (wIntrVector[31:0]),
         .VECT_1                        (wIntrVector[63:32]),
         .INTR_LEGACY_CLR               (1'd0),
         /*AUTOINST*/
         // Outputs
         .INTR_MSI_REQUEST              (INTR_MSI_REQUEST),
         // Inputs
         .CLK                           (CLK),
         .CONFIG_INTERRUPT_MSIENABLE    (CONFIG_INTERRUPT_MSIENABLE),
         .INTR_MSI_RDY                  (INTR_MSI_RDY));


    tx_multiplexer
        #(/*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_NUM_CHNL                   (C_NUM_CHNL),
          .C_TAG_WIDTH                  (C_TAG_WIDTH),
          .C_VENDOR                     (C_VENDOR),
          .C_DEPTH_PACKETS              (C_DEPTH_PACKETS))
    tx_mux_inst
        (
         // Outputs
         .WR_DATA_REN                   (wTxEngWrDataRen[C_NUM_CHNL-1:0]),
         .WR_ACK                        (wTxEngWrAck[C_NUM_CHNL-1:0]),
         .RD_ACK                        (wTxEngRdAck[C_NUM_CHNL-1:0]),
         .INT_TAG                       (wInternalTag[5:0]),
         .INT_TAG_VALID                 (wInternalTagValid),
         .TX_ENG_RD_REQ_SENT            (wTxEngRdReqSent),
         // Inputs
         .RST_IN                        (rRst),
         .WR_REQ                        (wTxEngWrReq[C_NUM_CHNL-1:0]),
         .WR_ADDR                       (wTxEngWrAddr[(C_NUM_CHNL*`SIG_ADDR_W)-1:0]),
         .WR_LEN                        (wTxEngWrLen[(C_NUM_CHNL*`SIG_LEN_W)-1:0]),
         .WR_DATA                       (wTxEngWrData[(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]),
         .WR_SENT                       (wTxEngWrSent[C_NUM_CHNL-1:0]),
         .RD_REQ                        (wTxEngRdReq[C_NUM_CHNL-1:0]),
         .RD_SG_CHNL                    (wTxEngRdSgChnl[(C_NUM_CHNL*2)-1:0]),
         .RD_ADDR                       (wTxEngRdAddr[(C_NUM_CHNL*`SIG_ADDR_W)-1:0]),
         .RD_LEN                        (wTxEngRdLen[(C_NUM_CHNL*`SIG_LEN_W)-1:0]),
         .EXT_TAG                       (wExternalTag[C_TAG_WIDTH-1:0]),
         .EXT_TAG_VALID                 (wExternalTagValid),
         .RXBUF_SPACE_AVAIL             (wRxBufSpaceAvail),
         /*AUTOINST*/
         // Outputs
         .TXR_DATA_VALID                (TXR_DATA_VALID),
         .TXR_DATA                      (TXR_DATA[C_PCI_DATA_WIDTH-1:0]),
         .TXR_DATA_START_FLAG           (TXR_DATA_START_FLAG),
         .TXR_DATA_START_OFFSET         (TXR_DATA_START_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_DATA_END_FLAG             (TXR_DATA_END_FLAG),
         .TXR_DATA_END_OFFSET           (TXR_DATA_END_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_META_VALID                (TXR_META_VALID),
         .TXR_META_FDWBE                (TXR_META_FDWBE[`SIG_FBE_W-1:0]),
         .TXR_META_LDWBE                (TXR_META_LDWBE[`SIG_LBE_W-1:0]),
         .TXR_META_ADDR                 (TXR_META_ADDR[`SIG_ADDR_W-1:0]),
         .TXR_META_LENGTH               (TXR_META_LENGTH[`SIG_LEN_W-1:0]),
         .TXR_META_TAG                  (TXR_META_TAG[`SIG_TAG_W-1:0]),
         .TXR_META_TC                   (TXR_META_TC[`SIG_TC_W-1:0]),
         .TXR_META_ATTR                 (TXR_META_ATTR[`SIG_ATTR_W-1:0]),
         .TXR_META_TYPE                 (TXR_META_TYPE[`SIG_TYPE_W-1:0]),
         .TXR_META_EP                   (TXR_META_EP),
         // Inputs
         .CLK                           (CLK),
         .TXR_DATA_READY                (TXR_DATA_READY),
         .TXR_META_READY                (TXR_META_READY),
         .TXR_SENT                      (TXR_SENT));
    
    // Generate and link up the channels.
    generate
        for (i = 0; i < C_NUM_CHNL; i = i + 1) begin : channels
            channel 
                 #(
                   .C_DATA_WIDTH(C_PCI_DATA_WIDTH), 
                   .C_MAX_READ_REQ(C_MAX_READ_REQ)
                   )
            channel 
                 (
                  .RST(rRst),
                  .CLK(CLK), 
                  .CONFIG_MAX_READ_REQUEST_SIZE(CONFIG_MAX_READ_REQUEST_SIZE), 
                  .CONFIG_MAX_PAYLOAD_SIZE(CONFIG_MAX_PAYLOAD_SIZE), 

                  .PIO_DATA(wChnlReqData), 
                  .ENG_DATA(wRxEngData), 
                
                  .SG_RX_BUF_RECVD(wChnlSgRxBufRecvd[i]),
                  .SG_TX_BUF_RECVD(wChnlSgTxBufRecvd[i]),
                  .TXN_TX(wChnlTxRequest[i]),
                  .TXN_TX_DONE(wChnlTxDone[i]),
                  .TXN_RX_DONE(wChnlRxDone[i]),
                
                  .SG_RX_BUF_LEN_VALID(wChnlSgRxLenValid[i]),
                  .SG_RX_BUF_ADDR_HI_VALID(wChnlSgRxAddrHiValid[i]),
                  .SG_RX_BUF_ADDR_LO_VALID(wChnlSgRxAddrLoValid[i]),
                
                  .SG_TX_BUF_LEN_VALID(wChnlSgTxLenValid[i]),
                  .SG_TX_BUF_ADDR_HI_VALID(wChnlSgTxAddrHiValid[i]),
                  .SG_TX_BUF_ADDR_LO_VALID(wChnlSgTxAddrLoValid[i]),
                
                  .TXN_RX_LEN_VALID(wChnlRxLenValid[i]), 
                  .TXN_RX_OFF_LAST_VALID(wChnlRxOfflastValid[i]), 
                  .TXN_RX_DONE_LEN(wChnlRxDoneLen[(`SIG_RXDONELEN_W*i) +: `SIG_RXDONELEN_W]),
                  .TXN_RX_DONE_ACK(wChnlRxDoneReady[i]),
                
                  .TXN_TX_ACK(wChnlTxLenReady[i]), // ACK'd on length read
                  .TXN_TX_LEN(wChnlTxReqLen[(`SIG_TXRLEN_W*i) +: `SIG_TXRLEN_W]),
                  .TXN_TX_OFF_LAST(wChnlTxOfflast[(`SIG_OFFLAST_W*i) +: `SIG_OFFLAST_W]),
                  .TXN_TX_DONE_LEN(wChnlTxDoneLen[(`SIG_TXDONELEN_W*i) +:`SIG_TXDONELEN_W]),
                  .TXN_TX_DONE_ACK(wChnlTxDoneReady[i]),
                
                  .RX_REQ(wTxEngRdReq[i]),
                  .RX_REQ_ACK(wTxEngRdAck[i]),
                  .RX_REQ_TAG(wTxEngRdSgChnl[(2*i) +:2]),// TODO: `SIG_INTERNALTAG_W
                  .RX_REQ_ADDR(wTxEngRdAddr[(`SIG_ADDR_W*i) +:`SIG_ADDR_W]),
                  .RX_REQ_LEN(wTxEngRdLen[(`SIG_LEN_W*i) +:`SIG_LEN_W]),

                  .TX_REQ(wTxEngWrReq[i]), 
                  .TX_REQ_ACK(wTxEngWrAck[i]),
                  .TX_ADDR(wTxEngWrAddr[(`SIG_ADDR_W*i) +: `SIG_ADDR_W]), 
                  .TX_LEN(wTxEngWrLen[(`SIG_LEN_W*i) +: `SIG_LEN_W]), 
                  .TX_DATA(wTxEngWrData[(C_PCI_DATA_WIDTH*i) +:C_PCI_DATA_WIDTH]),
                  .TX_DATA_REN(wTxEngWrDataRen[i]), 
                  .TX_SENT(wTxEngWrSent[i]),
                
                  .MAIN_DATA_EN(wRxEngMainDataEn[(C_PCI_DATA_WORD_WIDTH*i) +:C_PCI_DATA_WORD_WIDTH]), 
                  .MAIN_DONE(wRxEngMainDone[i]), 
                  .MAIN_ERR(wRxEngMainErr[i]),
                
                  .SG_RX_DATA_EN(wRxEngSgRxDataEn[(C_PCI_DATA_WORD_WIDTH*i) +:C_PCI_DATA_WORD_WIDTH]),  
                  .SG_RX_DONE(wRxEngSgRxDone[i]), 
                  .SG_RX_ERR(wRxEngSgRxErr[i]),

                  .SG_TX_DATA_EN(wRxEngSgTxDataEn[(C_PCI_DATA_WORD_WIDTH*i) +:C_PCI_DATA_WORD_WIDTH]), 
                  .SG_TX_DONE(wRxEngSgTxDone[i]), 
                  .SG_TX_ERR(wRxEngSgTxErr[i]),

                  .CHNL_RX_CLK(CHNL_RX_CLK[i]), 
                  .CHNL_RX(CHNL_RX[i]), 
                  .CHNL_RX_ACK(CHNL_RX_ACK[i]), 
                  .CHNL_RX_LAST(CHNL_RX_LAST[i]), 
                  .CHNL_RX_LEN(CHNL_RX_LEN[(32*i) +:32]), 
                  .CHNL_RX_OFF(CHNL_RX_OFF[(31*i) +:31]), 
                  .CHNL_RX_DATA(CHNL_RX_DATA[(C_PCI_DATA_WIDTH*i) +:C_PCI_DATA_WIDTH]), 
                  .CHNL_RX_DATA_VALID(CHNL_RX_DATA_VALID[i]), 
                  .CHNL_RX_DATA_REN(CHNL_RX_DATA_REN[i]),

                  .CHNL_TX_CLK(CHNL_TX_CLK[i]), 
                  .CHNL_TX(CHNL_TX[i]), 
                  .CHNL_TX_ACK(CHNL_TX_ACK[i]),
                  .CHNL_TX_LAST(CHNL_TX_LAST[i]), 
                  .CHNL_TX_LEN(CHNL_TX_LEN[(32*i) +:32]), 
                  .CHNL_TX_OFF(CHNL_TX_OFF[(31*i) +:31]), 
                  .CHNL_TX_DATA(CHNL_TX_DATA[(C_PCI_DATA_WIDTH*i) +:C_PCI_DATA_WIDTH]), 
                  .CHNL_TX_DATA_VALID(CHNL_TX_DATA_VALID[i]), 
                  .CHNL_TX_DATA_REN(CHNL_TX_DATA_REN[i])
                  );

        end
    endgenerate
endmodule
// Local Variables:
// verilog-library-directories:("." "registers/" "import")
// End:

