// ----------------------------------------------------------------------
// 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:            Filename: schedules.vh
// Version:             Version: 1.0
// Verilog Standard:    Verilog-2005
// Description: This file defines the schedules for each output mux used
// in the tx_alignment alignment pipeline and the connections for each
// mux. The schedule depends on the width of the PCI bus.
// 
// The wSchedule array is intended to be a multiported ROM implemented
// as small memory slices adjacent to the corresponding output
// multiplexer. The wSchedule array is first indexed by the MUX id,
// then the concatenation of the header select bit (3 or 4 DW Header),
// whether or not the packet is Quad word aligned, and a saturating
// counter that counts up from the start of the packet to the maximum
// schedule index for that particular data bus width. 
// 
// For a 256-bit PCIe interface, the schedule is 2 cycles long. 
// For a 128-bit PCIe interface, the schedule is 3 cycles long. 
// For a 64-bit PCIe interface, the schedule is 4 cycles long. 
// For a 32-bit PCIe interface, the schedule is 5 cycles long. 
// 
// This file also contains the array wTxMuxInputs, which defines the
// connections for each output multiplexer. The wTxMuxInputs array is
// indexed by the output multiplexer ID, which provides a concatenated
// bus of all of the DW inputs for that particular mux.
// 
// These schedules are derived from the .csv files:
// SchedulesTable_256.csv SchedulesTable_128.csv SchedulesTable_64.csv
// and SchedulesTable_32.csv
// 
// Author: Dustin Richmond (@darichmond) 
// ----------------------------------------------------------------------
`ifndef SCHEDULES_VH

    `define SCHEDULES_VH

    `define TXA_HDR0_INDEX 0
    `define TXA_HDR1_INDEX 1
    `define TXA_HDR2_INDEX 2
    `define TXA_HDR3_INDEX 3
    `define TXA_DW0_INDEX 4
    `define TXA_DW1_INDEX 5
    `define TXA_DW2_INDEX 6
    `define TXA_DW3_INDEX 7
    `define TXA_DW4_INDEX 8
    `define TXA_DW5_INDEX 9
    `define TXA_DW6_INDEX 10
    `define TXA_DW7_INDEX 11

    `define TXA_5DW 3'b101
    `define TXA_4DW 3'b100
    `define TXA_3DW 3'b011

    `define TXA_3DWH 1'b0
    `define TXA_4DWH 1'b1
    `define TXA_NOB  1'b0
    `define TXA_INSB 1'b1

    `define TXA_READ 1'b1
// 256 Schedule

// Ugly as sin, but works
generate 
    if(C_DATA_WIDTH == 256) begin
        assign wTxMuxInputs[0] = {wAggregate[`TXA_DW5_INDEX],
                                  wAggregate[`TXA_DW4_INDEX],
                                  wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_HDR0_INDEX]};
        assign wSchedule[0][{`TXA_3DW,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[0][{`TXA_4DW,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_4DW,1'b1}] = 2'd2;

        assign wSchedule[0][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_5DW,1'b1}] = 2'd1;

        
        assign wTxMuxInputs[1] = {wAggregate[`TXA_DW6_INDEX],
                                  wAggregate[`TXA_DW5_INDEX],
                                  wAggregate[`TXA_DW4_INDEX],
                                  wAggregate[`TXA_HDR1_INDEX]};

        assign wSchedule[1][{`TXA_3DW,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[1][{`TXA_4DW,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_4DW,1'b1}] = 2'd2;

        assign wSchedule[1][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_5DW,1'b1}] = 2'd1;

        assign wTxMuxInputs[2] = {wAggregate[`TXA_DW7_INDEX],
                                  wAggregate[`TXA_DW6_INDEX],
                                  wAggregate[`TXA_DW5_INDEX],
                                  wAggregate[`TXA_HDR2_INDEX]};

        assign wSchedule[2][{`TXA_3DW,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[2][{`TXA_4DW,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_4DW,1'b1}] = 2'd2;

        assign wSchedule[2][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_5DW,1'b1}] = 2'd1;

        assign wTxMuxInputs[3] = {wAggregate[`TXA_DW7_INDEX],
                                  wAggregate[`TXA_DW6_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR3_INDEX]};

        assign wSchedule[3][{`TXA_3DW,1'b0}] = 2'd1;
        assign wSchedule[3][{`TXA_3DW,1'b1}] = 2'd1;

        assign wSchedule[3][{`TXA_4DW,1'b0}] = 2'd0;
        assign wSchedule[3][{`TXA_4DW,1'b1}] = 2'd3;

        assign wSchedule[3][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[3][{`TXA_5DW,1'b1}] = 2'd2;

        assign wTxMuxInputs[4] = {wAggregate[`TXA_DW7_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_DW0_INDEX]};

        assign wSchedule[4][{`TXA_3DW,1'b0}] = 2'd2;
        assign wSchedule[4][{`TXA_3DW,1'b1}] = 2'd2;

        assign wSchedule[4][{`TXA_4DW,1'b0}] = 2'd0;
        assign wSchedule[4][{`TXA_4DW,1'b1}] = 2'd0;

        assign wSchedule[4][{`TXA_5DW,1'b0}] = 2'd3;
        assign wSchedule[4][{`TXA_5DW,1'b1}] = 2'd3;

        assign wTxMuxInputs[5] = {wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX]};

        assign wSchedule[5][{`TXA_3DW,1'b0}] = 2'd3;
        assign wSchedule[5][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[5][{`TXA_4DW,1'b0}] = 2'd1;
        assign wSchedule[5][{`TXA_4DW,1'b1}] = 2'd1;

        assign wSchedule[5][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[5][{`TXA_5DW,1'b1}] = 2'd0;

        assign wTxMuxInputs[6] = {wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW1_INDEX]};

        assign wSchedule[6][{`TXA_3DW,1'b0}] = 2'd3;
        assign wSchedule[6][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[6][{`TXA_4DW,1'b0}] = 2'd1;
        assign wSchedule[6][{`TXA_4DW,1'b1}] = 2'd1;

        assign wSchedule[6][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[6][{`TXA_5DW,1'b1}] = 2'd0;

        assign wTxMuxInputs[7] = {wAggregate[`TXA_DW4_INDEX],
                                  wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW2_INDEX]};

        assign wSchedule[7][{`TXA_3DW,1'b0}] = 2'd3;
        assign wSchedule[7][{`TXA_3DW,1'b1}] = 2'd3;

        assign wSchedule[7][{`TXA_4DW,1'b0}] = 2'd1;
        assign wSchedule[7][{`TXA_4DW,1'b1}] = 2'd1;

        assign wSchedule[7][{`TXA_5DW,1'b0}] = 2'd0;
        assign wSchedule[7][{`TXA_5DW,1'b1}] = 2'd0;

    end else if (C_DATA_WIDTH == 128) begin

        assign wTxMuxInputs[0] = {wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR0_INDEX]};

        assign wSchedule[0][{`TXA_3DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_3DW,1'b0,1'b1}] = 2'd2;
        assign wSchedule[0][{`TXA_3DW,1'b1,1'b0}] = 2'd2;
        
        assign wSchedule[0][{`TXA_4DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_4DW,1'b0,1'b1}] = 2'd1;
        assign wSchedule[0][{`TXA_4DW,1'b1,1'b0}] = 2'd1;

        assign wSchedule[0][{`TXA_5DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[0][{`TXA_5DW,1'b0,1'b1}] = 2'd3;
        assign wSchedule[0][{`TXA_5DW,1'b1,1'b0}] = 2'd3;

        assign wTxMuxInputs[1] = {wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR1_INDEX]};

        assign wSchedule[1][{`TXA_3DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_3DW,1'b0,1'b1}] = 2'd3;
        assign wSchedule[1][{`TXA_3DW,1'b1,1'b0}] = 2'd3;

        assign wSchedule[1][{`TXA_4DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_4DW,1'b0,1'b1}] = 2'd2;
        assign wSchedule[1][{`TXA_4DW,1'b1,1'b0}] = 2'd2;

        assign wSchedule[1][{`TXA_5DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[1][{`TXA_5DW,1'b0,1'b1}] = 2'd1;
        assign wSchedule[1][{`TXA_5DW,1'b1,1'b0}] = 2'd1;

        assign wTxMuxInputs[2] = {wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_HDR2_INDEX]};

        assign wSchedule[2][{`TXA_3DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_3DW,1'b0,1'b1}] = 2'd3;
        assign wSchedule[2][{`TXA_3DW,1'b1,1'b0}] = 2'd3;

        assign wSchedule[2][{`TXA_4DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_4DW,1'b0,1'b1}] = 2'd2;
        assign wSchedule[2][{`TXA_4DW,1'b1,1'b0}] = 2'd2;

        assign wSchedule[2][{`TXA_5DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[2][{`TXA_5DW,1'b0,1'b1}] = 2'd1;
        assign wSchedule[2][{`TXA_5DW,1'b1,1'b0}] = 2'd1;

        assign wTxMuxInputs[3] = {wAggregate[`TXA_DW3_INDEX],
                                  wAggregate[`TXA_DW2_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR3_INDEX]};

        assign wSchedule[3][{`TXA_3DW,1'b0,1'b0}] = 2'd1;
        assign wSchedule[3][{`TXA_3DW,1'b0,1'b1}] = 2'd1;
        assign wSchedule[3][{`TXA_3DW,1'b1,1'b0}] = 2'd1;

        assign wSchedule[3][{`TXA_4DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[3][{`TXA_4DW,1'b0,1'b1}] = 2'd3;
        assign wSchedule[3][{`TXA_4DW,1'b1,1'b0}] = 2'd3;

        assign wSchedule[3][{`TXA_5DW,1'b0,1'b0}] = 2'd0;
        assign wSchedule[3][{`TXA_5DW,1'b0,1'b1}] = 2'd2;
        assign wSchedule[3][{`TXA_5DW,1'b1,1'b0}] = 2'd2;

    end else if (C_DATA_WIDTH == 64) begin

        assign wTxMuxInputs[0] = {wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR2_INDEX],
                                  wAggregate[`TXA_HDR0_INDEX]};

        assign wSchedule[0][{`TXA_3DW,2'b00}] = 2'd0;
        assign wSchedule[0][{`TXA_3DW,2'b01}] = 2'd1;
        assign wSchedule[0][{`TXA_3DW,2'b10}] = 2'd3;
        assign wSchedule[0][{`TXA_3DW,2'b11}] = 2'd3;
        
        assign wSchedule[0][{`TXA_4DW,2'b00}] = 2'd0;
        assign wSchedule[0][{`TXA_4DW,2'b01}] = 2'd1;
        assign wSchedule[0][{`TXA_4DW,2'b10}] = 2'd2;
        assign wSchedule[0][{`TXA_4DW,2'b11}] = 2'd2;

        assign wSchedule[0][{`TXA_5DW,2'b00}] = 2'd0;
        assign wSchedule[0][{`TXA_5DW,2'b01}] = 2'd1;
        assign wSchedule[0][{`TXA_5DW,2'b10}] = 2'd3;
        assign wSchedule[0][{`TXA_5DW,2'b11}] = 2'd3;

        assign wTxMuxInputs[1] = {wAggregate[`TXA_DW1_INDEX],
                                  wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR3_INDEX],
                                  wAggregate[`TXA_HDR1_INDEX]};

        assign wSchedule[1][{`TXA_3DW,2'b00}] = 2'd0;
        assign wSchedule[1][{`TXA_3DW,2'b01}] = 2'd2;
        assign wSchedule[1][{`TXA_3DW,2'b10}] = 2'd2;
        assign wSchedule[1][{`TXA_3DW,2'b11}] = 2'd2;

        assign wSchedule[1][{`TXA_4DW,2'b00}] = 2'd0;
        assign wSchedule[1][{`TXA_4DW,2'b01}] = 2'd1;
        assign wSchedule[1][{`TXA_4DW,2'b10}] = 2'd3;
        assign wSchedule[1][{`TXA_4DW,2'b11}] = 2'd3;
        
        assign wSchedule[1][{`TXA_5DW,2'b00}] = 2'd0;
        assign wSchedule[1][{`TXA_5DW,2'b01}] = 2'd1;
        assign wSchedule[1][{`TXA_5DW,2'b10}] = 2'd2;
        assign wSchedule[1][{`TXA_5DW,2'b11}] = 2'd2;

    end else if (C_DATA_WIDTH == 32) begin

        assign wTxMuxInputs[0] = {wAggregate[`TXA_DW0_INDEX],
                                  wAggregate[`TXA_HDR3_INDEX],
                                  wAggregate[`TXA_HDR2_INDEX],
                                  wAggregate[`TXA_HDR1_INDEX],
                                  wAggregate[`TXA_HDR0_INDEX]};

        assign wSchedule[0][{`TXA_3DW,3'b000}] = 3'd0;
        assign wSchedule[0][{`TXA_3DW,3'b001}] = 3'd1;
        assign wSchedule[0][{`TXA_3DW,3'b010}] = 3'd2;
        assign wSchedule[0][{`TXA_3DW,3'b011}] = 3'd4;
        assign wSchedule[0][{`TXA_3DW,3'b100}] = 3'd4;
        assign wSchedule[0][{`TXA_3DW,3'b101}] = 3'd4;
        
        assign wSchedule[0][{`TXA_4DW,3'b000}] = 3'd0;
        assign wSchedule[0][{`TXA_4DW,3'b001}] = 3'd1;
        assign wSchedule[0][{`TXA_4DW,3'b010}] = 3'd2;
        assign wSchedule[0][{`TXA_4DW,3'b011}] = 3'd3;
        assign wSchedule[0][{`TXA_4DW,3'b100}] = 3'd4;
        assign wSchedule[0][{`TXA_4DW,3'b101}] = 3'd4;

        assign wSchedule[0][{`TXA_5DW,3'b000}] = 3'd0;
        assign wSchedule[0][{`TXA_5DW,3'b001}] = 3'd1;
        assign wSchedule[0][{`TXA_5DW,3'b010}] = 3'd2;
        assign wSchedule[0][{`TXA_5DW,3'b011}] = 3'd3;
        assign wSchedule[0][{`TXA_5DW,3'b100}] = 3'd4;
        assign wSchedule[0][{`TXA_5DW,3'b101}] = 3'd4;
    end else begin
        // Error!!!
    end
endgenerate
`endif
