// ----------------------------------------------------------------------
// 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.
// ----------------------------------------------------------------------
//
// Filename:            tx_engine_classic.v
// Version:             1.0
// Verilog Standard:    Verilog-2001
// Description:         The TX Engine takes unformatted request and completions,
// formats these packets into "TLP's" or Transaction Layer Packets and abitrates
// their sending over the PCIe bus. These packets must meet max-request,
// max-payload, and payload termination requirements (see Read Completion
// Boundary). The TX Engine does not check these requirements during operation,
// but may do so during simulation.
// 
// Valid packets are transmitted over the shared PCIe bus as determined
// by the arbiter. 
// 
// This Engine is capable of operating at "line rate".
// Author:              Dustin Richmond (@darichmond)
//-----------------------------------------------------------------------------
`include "trellis.vh"
`include "tlp.vh"
module tx_engine_classic
    #(
      parameter C_PCI_DATA_WIDTH = 128,
      parameter C_PIPELINE_INPUT = 1,
      parameter C_PIPELINE_OUTPUT = 1,
      parameter C_MAX_PAYLOAD_DWORDS = 256,
      parameter C_VENDOR = "ALTERA"
      )
    (
     // Interface: Clocks
     input                                    CLK,

     // Interface: Resets
     input                                    RST_IN,

     // Interface: Configuration 
     input [`SIG_CPLID_W-1:0]                 CONFIG_COMPLETER_ID,

     // Interface: TX Classic
     input                                    TX_TLP_READY,
     output [C_PCI_DATA_WIDTH-1:0]            TX_TLP,
     output                                   TX_TLP_VALID,
     output                                   TX_TLP_START_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_START_OFFSET,
     output                                   TX_TLP_END_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_END_OFFSET,

     // Interface: TXC Engine
     input                                    TXC_DATA_VALID,
     input [C_PCI_DATA_WIDTH-1:0]             TXC_DATA,
     input                                    TXC_DATA_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_DATA_START_OFFSET,
     input                                    TXC_DATA_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_DATA_END_OFFSET,
     output                                   TXC_DATA_READY,

     input                                    TXC_META_VALID,
     input [`SIG_FBE_W-1:0]                   TXC_META_FDWBE,
     input [`SIG_LBE_W-1:0]                   TXC_META_LDWBE,
     input [`SIG_LOWADDR_W-1:0]               TXC_META_ADDR,
     input [`SIG_TYPE_W-1:0]                  TXC_META_TYPE,
     input [`SIG_LEN_W-1:0]                   TXC_META_LENGTH,
     input [`SIG_BYTECNT_W-1:0]                  TXC_META_BYTE_COUNT,
     input [`SIG_TAG_W-1:0]                   TXC_META_TAG,
     input [`SIG_REQID_W-1:0]                 TXC_META_REQUESTER_ID,
     input [`SIG_TC_W-1:0]                    TXC_META_TC,
     input [`SIG_ATTR_W-1:0]                  TXC_META_ATTR,
     input                                    TXC_META_EP,
     output                                   TXC_META_READY,
     output                                   TXC_SENT,
     
     // Interface: TXR Engine
     input                                    TXR_DATA_VALID,
     input [C_PCI_DATA_WIDTH-1:0]             TXR_DATA,
     input                                    TXR_DATA_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_DATA_START_OFFSET,
     input                                    TXR_DATA_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_DATA_END_OFFSET,
     output                                   TXR_DATA_READY,

     input                                    TXR_META_VALID,
     input [`SIG_FBE_W-1:0]                   TXR_META_FDWBE, 
     input [`SIG_LBE_W-1:0]                   TXR_META_LDWBE,
     input [`SIG_ADDR_W-1:0]                  TXR_META_ADDR,
     input [`SIG_LEN_W-1:0]                   TXR_META_LENGTH,
     input [`SIG_TAG_W-1:0]                   TXR_META_TAG,
     input [`SIG_TC_W-1:0]                    TXR_META_TC,
     input [`SIG_ATTR_W-1:0]                  TXR_META_ATTR,
     input [`SIG_TYPE_W-1:0]                  TXR_META_TYPE,
     input                                    TXR_META_EP,
     output                                   TXR_META_READY,
     output                                   TXR_SENT
     );
    localparam C_MUX_TYPE = "SHIFT";
    localparam C_DEPTH_PACKETS = 10;
    /*AUTOWIRE*/
    /*AUTOINPUT*/

    wire [C_PCI_DATA_WIDTH-1:0]               _TXC_DATA;
    wire [C_PCI_DATA_WIDTH-1:0]               _TXR_DATA;
    wire [C_PCI_DATA_WIDTH-1:0]               wTxcTlp;
    wire                                      wTxcTlpEndFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxcTlpEndOffset;
    wire                                      wTxcTlpReady;
    wire                                      wTxcTlpStartFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxcTlpStartOffset;
    wire                                      wTxcTlpValid;

    wire [C_PCI_DATA_WIDTH-1:0]               wTxrTlp;
    wire                                      wTxrTlpEndFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxrTlpEndOffset;
    wire                                      wTxrTlpReady;
    wire                                      wTxrTlpStartFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxrTlpStartOffset;
    wire                                      wTxrTlpValid;

    reg                                       rTxValid;
    reg [`TLP_TYPE_W-1:0]                     rTxType;
    reg                                       rTxEndFlag;
    reg                                       rTxrSent;
    reg                                       rTxcSent;

    assign TXC_SENT = rTxcSent;
    assign TXR_SENT = rTxrSent;
        
    always @(posedge CLK) begin
        if(TX_TLP_START_FLAG) begin
            rTxType <= TX_TLP[`TLP_TYPE_R];
        end
        rTxEndFlag <= TX_TLP_END_FLAG;
        rTxValid <= TX_TLP_VALID & TX_TLP_READY;
        rTxcSent <= rTxEndFlag & rTxValid & (rTxType == `TLP_TYPE_CPL);
        rTxrSent <= rTxEndFlag & rTxValid & (rTxType == `TLP_TYPE_REQ);
    end
    
    generate
        if(C_VENDOR == "XILINX") begin : xilinx_data
            if(C_PCI_DATA_WIDTH == 128) begin : x_be_swap128
                assign _TXC_DATA = {TXC_DATA[103:96], TXC_DATA[111:104], TXC_DATA[119:112], TXC_DATA[127:120],
                                    TXC_DATA[71:64], TXC_DATA[79:72], TXC_DATA[87:80], TXC_DATA[95:88],
                                    TXC_DATA[39:32], TXC_DATA[47:40], TXC_DATA[55:48], TXC_DATA[63:56],
                                    TXC_DATA[07:00], TXC_DATA[15:08], TXC_DATA[23:16], TXC_DATA[31:24]};
                assign _TXR_DATA = {TXR_DATA[103:96], TXR_DATA[111:104], TXR_DATA[119:112], TXR_DATA[127:120],
                                    TXR_DATA[71:64], TXR_DATA[79:72], TXR_DATA[87:80], TXR_DATA[95:88],
                                    TXR_DATA[39:32], TXR_DATA[47:40], TXR_DATA[55:48], TXR_DATA[63:56],
                                    TXR_DATA[07:00], TXR_DATA[15:08], TXR_DATA[23:16], TXR_DATA[31:24]};
            end else if(C_PCI_DATA_WIDTH == 64) begin: x_be_swap64
                assign _TXC_DATA = {TXC_DATA[39:32], TXC_DATA[47:40], TXC_DATA[55:48], TXC_DATA[63:56],
                                    TXC_DATA[07:00], TXC_DATA[15:08], TXC_DATA[23:16], TXC_DATA[31:24]};
                assign _TXR_DATA = {TXR_DATA[39:32], TXR_DATA[47:40], TXR_DATA[55:48], TXR_DATA[63:56],
                                    TXR_DATA[07:00], TXR_DATA[15:08], TXR_DATA[23:16], TXR_DATA[31:24]};
            end else if(C_PCI_DATA_WIDTH == 32) begin: x_be_swap32
                assign _TXC_DATA = {TXC_DATA[07:00], TXC_DATA[15:08], TXC_DATA[23:16], TXC_DATA[31:24]};
                assign _TXR_DATA = {TXR_DATA[07:00], TXR_DATA[15:08], TXR_DATA[23:16], TXR_DATA[31:24]};
            end
        end else begin : altera_data
            assign _TXC_DATA = TXC_DATA;
            assign _TXR_DATA = TXR_DATA;
        end
    endgenerate

    txc_engine_classic
        #(
          .C_PIPELINE_OUTPUT            (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_PIPELINE_INPUT             (C_PIPELINE_INPUT),
          .C_MAX_PAYLOAD_DWORDS         (C_MAX_PAYLOAD_DWORDS),
          .C_DEPTH_PACKETS              (C_DEPTH_PACKETS),
          .C_VENDOR                     (C_VENDOR))
    txc_engine_inst
        (
         // Outputs
         .TXC_TLP                       (wTxcTlp[C_PCI_DATA_WIDTH-1:0] ),
         .TXC_TLP_VALID                 (wTxcTlpValid),
         .TXC_TLP_START_FLAG            (wTxcTlpStartFlag),
         .TXC_TLP_START_OFFSET          (wTxcTlpStartOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXC_TLP_END_FLAG              (wTxcTlpEndFlag),
         .TXC_TLP_END_OFFSET            (wTxcTlpEndOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         // Inputs
         .TXC_TLP_READY                 (wTxcTlpReady),
         .TXC_DATA                      (_TXC_DATA[C_PCI_DATA_WIDTH-1:0]),
         /*AUTOINST*/
         // Outputs
         .TXC_DATA_READY                (TXC_DATA_READY),
         .TXC_META_READY                (TXC_META_READY),
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN),
         .CONFIG_COMPLETER_ID           (CONFIG_COMPLETER_ID[`SIG_CPLID_W-1:0]),
         .TXC_DATA_VALID                (TXC_DATA_VALID),
         .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));

    txr_engine_classic
        #(
          .C_PIPELINE_OUTPUT            (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_PIPELINE_INPUT             (C_PIPELINE_INPUT),
          .C_MAX_PAYLOAD_DWORDS         (C_MAX_PAYLOAD_DWORDS),
          .C_DEPTH_PACKETS              (C_DEPTH_PACKETS),
          .C_VENDOR                     (C_VENDOR))
    txr_engine_inst
        (
         // Outputs
         .TXR_TLP                       (wTxrTlp[C_PCI_DATA_WIDTH-1:0]),
         .TXR_TLP_VALID                 (wTxrTlpValid),
         .TXR_TLP_START_FLAG            (wTxrTlpStartFlag),
         .TXR_TLP_START_OFFSET          (wTxrTlpStartOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_TLP_END_FLAG              (wTxrTlpEndFlag),
         .TXR_TLP_END_OFFSET            (wTxrTlpEndOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_DATA                      (_TXR_DATA[C_PCI_DATA_WIDTH-1:0]),
         // Inputs
         .TXR_TLP_READY                 (wTxrTlpReady),
         /*AUTOINST*/
         // Outputs
         .TXR_DATA_READY                (TXR_DATA_READY),
         .TXR_META_READY                (TXR_META_READY),
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN),
         .CONFIG_COMPLETER_ID           (CONFIG_COMPLETER_ID[`SIG_CPLID_W-1:0]),
         .TXR_DATA_VALID                (TXR_DATA_VALID),
         .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));

    tx_mux
        #(
          .C_PIPELINE_INPUT             (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_PIPELINE_OUTPUT            (C_PIPELINE_OUTPUT),
          .C_MUX_TYPE                   (C_MUX_TYPE),
          .C_VENDOR                     (C_VENDOR))
    tx_mux_inst
        (
         // Inputs
         .TXC_TLP                       (wTxcTlp[C_PCI_DATA_WIDTH-1:0]),
         .TXC_TLP_VALID                 (wTxcTlpValid),
         .TXC_TLP_START_FLAG            (wTxcTlpStartFlag),
         .TXC_TLP_START_OFFSET          (wTxcTlpStartOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXC_TLP_END_FLAG              (wTxcTlpEndFlag),
         .TXC_TLP_END_OFFSET            (wTxcTlpEndOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_TLP                       (wTxrTlp[C_PCI_DATA_WIDTH-1:0]),
         .TXR_TLP_VALID                 (wTxrTlpValid),
         .TXR_TLP_START_FLAG            (wTxrTlpStartFlag),
         .TXR_TLP_START_OFFSET          (wTxrTlpStartOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TXR_TLP_END_FLAG              (wTxrTlpEndFlag),
         .TXR_TLP_END_OFFSET            (wTxrTlpEndOffset[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         // Outputs
         .TXC_TLP_READY                 (wTxcTlpReady),
         .TXR_TLP_READY                 (wTxrTlpReady),
         /*AUTOINST*/
         // Outputs
         .TX_TLP                        (TX_TLP[C_PCI_DATA_WIDTH-1:0]),
         .TX_TLP_VALID                  (TX_TLP_VALID),
         .TX_TLP_START_FLAG             (TX_TLP_START_FLAG),
         .TX_TLP_START_OFFSET           (TX_TLP_START_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         .TX_TLP_END_FLAG               (TX_TLP_END_FLAG),
         .TX_TLP_END_OFFSET             (TX_TLP_END_OFFSET[clog2s(C_PCI_DATA_WIDTH/32)-1:0]),
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN),
         .TX_TLP_READY                  (TX_TLP_READY));
endmodule
// Local Variables:
// verilog-library-directories:("." "../../common/")
// End:
/*
 Filename: tx_mux.v
 Version: 1.0
 Verilog Standard: Verilog-2001

 Description: The tx_mux arbitrates access to the PCI TX interface
 between the the Request and Completion engines. The top level tx_mux
 module instantiates two sub-modules (also declared in this file):
 tx_arbiter and tx_phi. The arbiter choses the next packet that will
 be granted the TX interface, based on the priorities given to
 it. Each priority is the count of how many successive, back-to-back
 packets can be sent by either the TXC or TXR interface before
 granting time to the other engine. The mux is a simple multiplexer
 that uses the select signals from the arbiter.
 
 Notes: Any modifications to this file should meet the conditions set
 forth in the "Trellis Style Guide"

 - The pipeline stage at the start of the mux means that ready stays high for
 both TXC and TXR. This the behavior we want?
 
 Author: Dustin Richmond (@darichmond) 
 Co-Authors:
 */
`timescale 1ns/1ns
`include "trellis.vh"
module tx_mux
    #(
      parameter C_PCI_DATA_WIDTH = 128,
      parameter C_PIPELINE_INPUT = 1,
      parameter C_PIPELINE_OUTPUT = 1,
      parameter C_MUX_TYPE = "SHIFT",
      parameter C_VENDOR = "ALTERA"
      )
    (
     // Interface: Clocks
     input                                    CLK,

     // Interface: Resets
     input                                    RST_IN,

     // Interface: TXC
     input [C_PCI_DATA_WIDTH-1:0]             TXC_TLP,
     output                                   TXC_TLP_READY,
     input                                    TXC_TLP_VALID,
     input                                    TXC_TLP_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_TLP_START_OFFSET,
     input                                    TXC_TLP_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_TLP_END_OFFSET,

     // Interface: TXR
     input [C_PCI_DATA_WIDTH-1:0]             TXR_TLP,
     input                                    TXR_TLP_VALID,
     input                                    TXR_TLP_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_TLP_START_OFFSET,
     input                                    TXR_TLP_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_TLP_END_OFFSET,
     output                                   TXR_TLP_READY,

     // Interface: TX Classic
     input                                    TX_TLP_READY,
     output [C_PCI_DATA_WIDTH-1:0]            TX_TLP,
     output                                   TX_TLP_VALID,
     output                                   TX_TLP_START_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_START_OFFSET,
     output                                   TX_TLP_END_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_END_OFFSET
     );
    localparam C_WIDTH = (C_PCI_DATA_WIDTH + 2 * (clog2s(C_PCI_DATA_WIDTH/32) + 1));
    localparam C_TXC_PRIORITY = 1;
    localparam C_TXR_PRIORITY = 2;
    /*AUTOWIRE*/
    /*AUTOINPUT*/
    /*AUTOOUTPUT*/

    // Input Pipeline Stage to Mux
    wire [C_PCI_DATA_WIDTH-1:0]               wTxcTlp;
    wire                                      wTxcTlpReady;
    wire                                      wTxcTlpValid;
    wire                                      wTxcTlpStartFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxcTlpStartOffset;
    wire                                      wTxcTlpEndFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxcTlpEndOffset;

    wire [C_PCI_DATA_WIDTH-1:0]               wTxrTlp;
    wire                                      wTxrTlpReady;
    wire                                      wTxrTlpValid;
    wire                                      wTxrTlpStartFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxrTlpStartOffset;
    wire                                      wTxrTlpEndFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxrTlpEndOffset;

    // Output of Mux to 
    wire [C_PCI_DATA_WIDTH-1:0]               wTxTlp;
    wire                                      wTxTlpReady;
    wire                                      wTxTlpValid;
    wire                                      wTxTlpStartFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxTlpStartOffset;
    wire                                      wTxTlpEndFlag;
    wire [clog2s(C_PCI_DATA_WIDTH/32)-1:0]    wTxTlpEndOffset;

    pipeline
        #(
          // Parameters
          .C_DEPTH                      (C_PIPELINE_INPUT?1:0),
          .C_USE_MEMORY                 (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_WIDTH                      (C_WIDTH))
    txr_capture_inst
        (
         // Outputs
         .WR_DATA_READY                 (TXR_TLP_READY),
         .RD_DATA                       ({wTxrTlp, wTxrTlpStartFlag, wTxrTlpStartOffset,
                                          wTxrTlpEndFlag, wTxrTlpEndOffset}),
         .RD_DATA_VALID                 (wTxrTlpValid),
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN),
         .WR_DATA                       ({TXR_TLP, 
                                          TXR_TLP_START_FLAG, TXR_TLP_START_OFFSET, 
                                          TXR_TLP_END_FLAG, TXR_TLP_END_OFFSET}),
         .WR_DATA_VALID                 (TXR_TLP_VALID),
         .RD_DATA_READY                 (wTxrTlpReady));
    
    pipeline
        #(
          // Parameters
          .C_DEPTH                         (C_PIPELINE_INPUT?1:0),
          .C_USE_MEMORY                    (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_WIDTH                      (C_WIDTH))
    txc_capture_inst
        (
         // Outputs
         .WR_DATA_READY                    (TXC_TLP_READY),
         .RD_DATA                          ({wTxcTlp, wTxcTlpStartFlag, wTxcTlpStartOffset,
                                             wTxcTlpEndFlag, wTxcTlpEndOffset}),
         .RD_DATA_VALID                    (wTxcTlpValid),
         // Inputs
         .WR_DATA                          ({TXC_TLP, 
                                             TXC_TLP_START_FLAG, TXC_TLP_START_OFFSET, 
                                             TXC_TLP_END_FLAG, TXC_TLP_END_OFFSET}),
         .WR_DATA_VALID                    (TXC_TLP_VALID),
         .RD_DATA_READY                    (wTxcTlpReady),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN));

    tx_arbiter
        #(/*AUTOINSTPARAM*/
          // Parameters
          .C_TXC_PRIORITY               (C_TXC_PRIORITY),
          .C_TXR_PRIORITY               (C_TXR_PRIORITY))
    tx_arbiter_inst
        (
         // Outputs
         .TXR_TLP_READY                    (wTxrTlpReady),
         .TXC_TLP_READY                    (wTxcTlpReady),
         // Inputs
         .TX_TLP_READY                     (wTxTlpReady),
         .TXC_TLP_VALID                    (wTxcTlpValid),
         .TXC_TLP_START_FLAG               (wTxcTlpStartFlag),
         .TXC_TLP_END_FLAG                 (wTxcTlpEndFlag),
         .TXR_TLP_VALID                    (wTxrTlpValid),
         .TXR_TLP_START_FLAG               (wTxrTlpStartFlag),
         .TXR_TLP_END_FLAG                 (wTxrTlpEndFlag),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN));
    
    // MUX Selector

    tx_phi
        #(/*AUTOINSTPARAM*/
          // Parameters
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_MUX_TYPE                   (C_MUX_TYPE),
          .C_WIDTH                      (C_WIDTH))
    tx_phi_inst
        (
         // Outputs
         .TXC_TLP_READY                    (wTxcTlpReady),
         .TXR_TLP_READY                    (wTxrTlpReady),
        
         .TX_TLP                           (wTxTlp),
         .TX_TLP_VALID                     (wTxTlpValid),
         .TX_TLP_START_FLAG                (wTxTlpStartFlag),
         .TX_TLP_START_OFFSET              (wTxTlpStartOffset),
         .TX_TLP_END_FLAG                  (wTxTlpEndFlag),
         .TX_TLP_END_OFFSET                (wTxTlpEndOffset),
         // Inputs
         .TXC_TLP                          (wTxcTlp),
         .TXC_TLP_VALID                    (wTxcTlpValid),
         .TXC_TLP_START_FLAG               (wTxcTlpStartFlag),
         .TXC_TLP_START_OFFSET             (wTxcTlpStartOffset),
         .TXC_TLP_END_FLAG                 (wTxcTlpEndFlag),
         .TXC_TLP_END_OFFSET               (wTxcTlpEndOffset),
        
         .TXR_TLP                          (wTxrTlp),
         .TXR_TLP_VALID                    (wTxrTlpValid),
         .TXR_TLP_START_FLAG               (wTxrTlpStartFlag),
         .TXR_TLP_START_OFFSET             (wTxrTlpStartOffset),
         .TXR_TLP_END_FLAG                 (wTxrTlpEndFlag),
         .TXR_TLP_END_OFFSET               (wTxrTlpEndOffset),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN));

    pipeline
        #(
          // Parameters
          .C_DEPTH                      (C_PIPELINE_OUTPUT?1:0),
          .C_USE_MEMORY                 (0),
          /*AUTOINSTPARAM*/
          // Parameters
          .C_WIDTH                      (C_WIDTH))
    tx_output_inst
        (
         // Outputs
         .WR_DATA_READY                    (wTxTlpReady),
         .RD_DATA                          ({TX_TLP, 
                                             TX_TLP_START_FLAG, TX_TLP_START_OFFSET, 
                                             TX_TLP_END_FLAG, TX_TLP_END_OFFSET}),
         .RD_DATA_VALID                    (TX_TLP_VALID),
         // Inputs
         .WR_DATA                          ({wTxTlp, wTxTlpStartFlag, wTxTlpStartOffset,
                                             wTxTlpEndFlag, wTxTlpEndOffset}),
         .WR_DATA_VALID                    (wTxTlpValid),
         .RD_DATA_READY                    (TX_TLP_READY),
         /*AUTOINST*/
         // Inputs
         .CLK                           (CLK),
         .RST_IN                        (RST_IN));

endmodule
// Local Variables:
// verilog-library-directories:("." "../../../common/")
// End:

/* 
 Description: The tx_arbiter arbitrates between TXC and TXR channels. The C_TX*_PRIORITY
 values are counters are the maximum number of uninterrupted TXR or TXC packets that can be
 transmitted without transmitting a packet of the other type. 
 
 Notes: Any modifications to this file should meet the conditions set
 forth in the "Trellis Style Guide"

 Author: Dustin Richmond (@darichmond) 
 Co-Authors:
 */
module tx_arbiter
    #(
      parameter C_TXC_PRIORITY = 1,
      parameter C_TXR_PRIORITY = 1)
    (
     // Interface: Clocks
     input  CLK,

     // Interface: Resets     
     input  RST_IN,

     // Interface: TX Classic Flow Control
     input  TX_TLP_READY,

     // Interface: TXR Flow Control
     output TXR_TLP_READY,
     input  TXR_TLP_VALID,
     input  TXR_TLP_START_FLAG,
     input  TXR_TLP_END_FLAG,

     // Interface: TXC Flow Control
     output TXC_TLP_READY,
     input  TXC_TLP_VALID,
     input  TXC_TLP_START_FLAG,
     input  TXC_TLP_END_FLAG

     );
    
    localparam S_TXARB_IDLE = 0; // STATE: Idle state for the arbiter (not currently used)
    localparam S_TXARB_TRANSMIT_TXR = 1; // STATE: Transmit TXR packets until the priority counter is reached
    localparam S_TXARB_TRANSMIT_TXC = 2; // STATE: Transmit TXC packets until the priority counter is reached

    // S_TXARB_PRIORITY is a special state that encodes the type (TXR/TXC) with
    // higher priority so that the state machine (below) is general.
    localparam S_TXARB_PRIORITY = (S_TXARB_TRANSMIT_TXR >= S_TXARB_TRANSMIT_TXC)? S_TXARB_TRANSMIT_TXR: S_TXARB_TRANSMIT_TXC;
    localparam C_NUM_STATES = S_TXARB_TRANSMIT_TXC;
    
    wire    wTxrGrant;
    wire    wTxrReq;
    wire    wTxrDone;

    wire    wTxcGrant;
    wire    wTxcReq;
    wire    wTxcDone;

    reg [clog2s(C_NUM_STATES):0] rArbState,_rArbState;

    reg                          rTxrLast,_rTxrLast; // Reset on RST_IN or TXC_TLP_READY
    reg                          rTxcLast,_rTxcLast; // Reset on RST_IN or TXR_TLP_READY

    reg                          rTxrActive,_rTxrActive; // Reset on RST_IN or TXC_TLP_READY
    reg                          rTxcActive,_rTxcActive; // Reset on RST_IN or TXR_TLP_READY

    reg [clog2s(C_TXC_PRIORITY)-1:0] rTxcCounter,_rTxcCounter; // Reset on RST_IN or TXC_TLP_READY
    reg [clog2s(C_TXR_PRIORITY)-1:0] rTxrCounter,_rTxrCounter; // Reset on RST_IN or TXR_TLP_READY

    assign TXR_TLP_READY = wTxrGrant & TX_TLP_READY; // TODO: Not great
    assign wTxrReq = TXR_TLP_START_FLAG & TXR_TLP_VALID;
    assign wTxrDone = TXR_TLP_END_FLAG & TXR_TLP_READY;
    assign wTxrGrant = (rArbState == S_TXARB_TRANSMIT_TXR);

    assign TXC_TLP_READY = wTxcGrant & TX_TLP_READY; // TODO: Not great
    assign wTxcReq = TXC_TLP_START_FLAG & TXC_TLP_VALID;
    assign wTxcDone = TXC_TLP_END_FLAG & TXC_TLP_READY;
    assign wTxcGrant = (rArbState == S_TXARB_TRANSMIT_TXC);
    
    always @(*) begin
        // Defaults
        _rTxcCounter  = rTxcCounter;
        _rTxcActive   = rTxcActive;
        _rTxcLast     = rTxcLast;
        
        if(wTxrGrant) begin
            _rTxcCounter = 0;
        end else if(wTxcReq & wTxcGrant & ~rTxcLast) begin
            _rTxcCounter = _rTxcCounter + 1;
        end 

        if(wTxcReq & wTxcGrant) begin
            _rTxcActive = 1;
        end else if(wTxcDone) begin
            _rTxcActive = 0;
        end

        if(wTxrGrant | RST_IN) begin
            _rTxcLast = 0;
        end else if(wTxcReq & wTxcGrant) begin
            _rTxcLast = (rTxcCounter == (C_TXC_PRIORITY - 1));
        end
    end // always @ (*)

    always @(posedge CLK) begin
        if(RST_IN) begin
            rTxcCounter <= #1 0;
            rTxcActive  <= #1 0;
            rTxcLast    <= #1 0;
        end else begin
            rTxcCounter <= #1  _rTxcCounter;
            rTxcActive  <= #1  _rTxcActive;
            rTxcLast    <= #1  _rTxcLast;
        end
    end

    always @(*) begin
        // Defaults
        _rTxrCounter  = rTxrCounter;
        _rTxrActive   = rTxrActive;
        _rTxrLast     = rTxrLast;
        
        if(wTxcGrant) begin
            _rTxrCounter = 0;
        end else if(wTxrReq & wTxrGrant & ~rTxrLast) begin
            _rTxrCounter = _rTxrCounter + 1;
        end 

        if(wTxrReq & wTxrGrant) begin
            _rTxrActive = 1;
        end else if(wTxrDone) begin
            _rTxrActive = 0;
        end

        if(wTxcGrant | RST_IN) begin
            _rTxrLast = 0;
        end else if(wTxrReq & wTxrGrant) begin
            /* verilator lint_off WIDTH */
            _rTxrLast  = (rTxrCounter == (C_TXR_PRIORITY - 1));
            /* verilator lint_on WIDTH */
        end
    end
    
    always @(posedge CLK) begin
        if(RST_IN) begin
            rTxrCounter <= #1 0;
            rTxrActive  <= #1 0;
            rTxrLast    <= #1 0;
        end else begin
            rTxrCounter <= #1 _rTxrCounter;
            rTxrActive  <= #1 _rTxrActive;
            rTxrLast    <= #1 _rTxrLast;
        end
    end

    // User encoded state machine
    always @(*) begin
        _rArbState = rArbState;

        case(rArbState)
            S_TXARB_TRANSMIT_TXR: begin
                if((rTxrLast & wTxrDone & wTxcReq) | (~rTxrActive & ~wTxrReq & wTxcReq)) begin
                    _rArbState = S_TXARB_TRANSMIT_TXC;
                end
            end
            S_TXARB_TRANSMIT_TXC: begin
                if((rTxcLast & wTxcDone & wTxrReq) | (~rTxcActive & ~wTxcReq & wTxrReq)) begin
                    _rArbState = S_TXARB_TRANSMIT_TXR;
                end
            end
            default: begin
                // Error! This should never happen...
            end
        endcase
    end // always @ begin
    
    always @(posedge CLK) begin
        if(RST_IN) begin
            rArbState <= #1 S_TXARB_PRIORITY;
        end else begin
            rArbState <= #1 _rArbState;
        end
    end
    
endmodule

/* 
 Description: The tx_phi wraps a mux instantiation for the tx_mux. It is
 controlled by the tx_arbiter
 
 Notes: Any modifications to this file should meet the conditions set
 forth in the "Trellis Style Guide"

 Author: Dustin Richmond (@darichmond) 
 Co-Authors:
 */
module tx_phi
    #(
      parameter C_PCI_DATA_WIDTH = 10'd128,
      parameter C_MUX_TYPE = "SHIFT",
      parameter C_WIDTH = (C_PCI_DATA_WIDTH + 2 * (clog2s(C_PCI_DATA_WIDTH/32) + 1))
      )
    (
     // Interface: Clocks
     input                                    CLK,

     // Interface: Resets
     input                                    RST_IN,

     // Interface: TXC Flow Control
     input                                    TXC_TLP_READY,

     // Interface: TXR Flow Control
     input                                    TXR_TLP_READY,

     // Interface: TXC
     input [C_PCI_DATA_WIDTH-1:0]             TXC_TLP,
     input                                    TXC_TLP_VALID,
     input                                    TXC_TLP_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_TLP_START_OFFSET,
     input                                    TXC_TLP_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXC_TLP_END_OFFSET,

     // Interface: TXR
     input [C_PCI_DATA_WIDTH-1:0]             TXR_TLP,
     input                                    TXR_TLP_VALID,
     input                                    TXR_TLP_START_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_TLP_START_OFFSET,
     input                                    TXR_TLP_END_FLAG,
     input [clog2s(C_PCI_DATA_WIDTH/32)-1:0]  TXR_TLP_END_OFFSET,


     // Interface: TX Classic
     output [C_PCI_DATA_WIDTH-1:0]            TX_TLP,
     output                                   TX_TLP_VALID,
     output                                   TX_TLP_START_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_START_OFFSET,
     output                                   TX_TLP_END_FLAG,
     output [clog2s(C_PCI_DATA_WIDTH/32)-1:0] TX_TLP_END_OFFSET
     );

    // Width = 2 * (DATA WIDTH + VALID + START FLAG + START OFFSET + END FLAG + END OFFSET)
    localparam C_MUX_WIDTH = C_PCI_DATA_WIDTH + 3 + 2*clog2s(C_PCI_DATA_WIDTH/32);
    
    wire [2*C_MUX_WIDTH-1:0]                  wAggregate;

    assign wAggregate = {{TXR_TLP,TXR_TLP_VALID,TXR_TLP_START_FLAG,
                          TXR_TLP_START_OFFSET,TXR_TLP_END_FLAG,TXR_TLP_END_OFFSET},
                         {TXC_TLP,TXC_TLP_VALID,TXC_TLP_START_FLAG,
                          TXC_TLP_START_OFFSET,TXC_TLP_END_FLAG,TXC_TLP_END_OFFSET}};

    mux
        #(
          // Parameters
          .C_NUM_INPUTS                 (2),
          .C_CLOG_NUM_INPUTS            (1),
          .C_WIDTH                      (C_MUX_WIDTH),
          .C_MUX_TYPE                   ("SELECT")
          /*AUTOINSTPARAM*/)
    mux_inst
        (
         // Outputs
         .MUX_OUTPUT                    ({TX_TLP,TX_TLP_VALID,TX_TLP_START_FLAG,
                                          TX_TLP_START_OFFSET,TX_TLP_END_FLAG,
                                          TX_TLP_END_OFFSET}),
         // Inputs
         .MUX_INPUTS                    (wAggregate),
         .MUX_SELECT                    (TXR_TLP_READY)
         /*AUTOINST*/);

endmodule
