// (C) 2001-2014 Altera Corporation. All rights reserved.
// Your use of Altera Corporation's design tools, logic functions and other 
// software and tools, and its AMPP partner logic functions, and any output 
// files any of the foregoing (including device programming or simulation 
// files), and any associated documentation or information are expressly subject 
// to the terms and conditions of the Altera Program License Subscription 
// Agreement, Altera MegaCore Function License Agreement, or other applicable 
// license agreement, including, without limitation, that your use is for the 
// sole purpose of programming logic devices manufactured by Altera and sold by 
// Altera or its authorized distributors.  Please refer to the applicable 
// agreement for further details.


// (C) 2001-2012 Altera Corporation. All rights reserved.

// Your use of Altera Corporation's design tools, logic functions and other 

// software and tools, and its AMPP partner logic functions, and any output 

// files any of the foregoing (including device programming or simulation 

// files), and any associated documentation or information are expressly subject 

// to the terms and conditions of the Altera Program License Subscription 

// Agreement, Altera MegaCore Function License Agreement, or other applicable 

// license agreement, including, without limitation, that your use is for the 

// sole purpose of programming logic devices manufactured by Altera and sold by 

// Altera or its authorized distributors.  Please refer to the applicable 

// agreement for further details.





// $Id: //acds/rel/13.1up/ip/merlin/altera_merlin_burst_adapter/altera_merlin_burst_adapter.sv#1 $

// $Revision: #1 $

// $Date: 2013/11/05 $

// $Author: swbranch $



// -------------------------------------------------------

// Merlin Burst Adapter

// -------------------------------------------------------



`timescale 1 ns / 1 ns



// <burstwrap value> + 1

// By definition, burstwrap values are of the form 2^n - 1; adding 1 is a non-ripple operation.

module altera_merlin_burst_adapter_burstwrap_increment #(parameter WIDTH = 8)

  (

    input [WIDTH - 1:0] mask,

    output [WIDTH - 1:0] inc

  );

    genvar i;

    generate begin : burstwrap_increment_gen

        assign inc[0] = ~mask[0];

        for (i = 1; i < WIDTH; i = i+1) begin : burstwrap_increment_loop

          assign inc[i] = mask[i - 1] & ~mask[i];

        end

      end

    endgenerate

endmodule



module altera_merlin_burst_adapter_adder #(parameter WIDTH = 8) (

    input cin,

    input  [WIDTH-1 : 0] a,

    input  [WIDTH-1 : 0] b,

    output [WIDTH-1 : 0] sum

  );



  genvar i;

  generate begin : full_adder

      wire [WIDTH-1:0] carry;

      assign sum[0]  = a[0] ^ b[0] ^ cin;

      assign carry[0] = a[0] & b[0] | a[0] & cin | b[0] & cin;



      for (i = 1; i < WIDTH; i = i+1) begin : full_adder_loop

          assign sum[i] = a[i] ^ b[i] ^ carry[i-1];

          assign carry[i] = a[i] & b[i] | a[i] & carry[i-1] | b[i] & carry[i-1];

      end



  end endgenerate

endmodule



// a - b = a + ~b + 1

module altera_merlin_burst_adapter_subtractor #(parameter WIDTH = 8) (

    input  [WIDTH-1 : 0] a,

    input  [WIDTH-1 : 0] b,

    output [WIDTH-1 : 0] diff

  );



  altera_merlin_burst_adapter_adder #(.WIDTH (WIDTH)) subtract (

    .cin (1'b1),

    .a (a),

    .b (~b),

    .sum (diff)

  );

endmodule



// Pipeline position:

//   0: register module inputs

//   1: register module output

// I would have expected that with register retiming/duplication turned on, the

// pipeline position parameter would have no effect.  Not so,

// PIPELINE_POSITION=1 is significantly better than PIPELINE_POSITION=0.



module altera_merlin_burst_adapter_min #(parameter PKT_BYTE_CNT_W=8, PKT_BURSTWRAP_W=8, PIPELINE_POSITION = 1)

  (

    input clk,

    input reset,

    input [PKT_BYTE_CNT_W - 1 : 0] a,

    input [PKT_BYTE_CNT_W - 1 : 0] b,

    input [PKT_BURSTWRAP_W - 1 : 0] c,

    input c_enable,

    input [PKT_BYTE_CNT_W - 1 : 0] d,

    output reg [PKT_BYTE_CNT_W - 1 : 0] result

  );



    wire [PKT_BYTE_CNT_W : 0] ab_diff;

    wire [PKT_BYTE_CNT_W : 0] ac_diff;

    wire [PKT_BYTE_CNT_W : 0] bc_diff;

    wire a_lt_b;

    wire a_lt_c;

    wire b_lt_c;



    reg [PKT_BYTE_CNT_W - 1 : 0] a_reg;

    reg [PKT_BYTE_CNT_W - 1 : 0] b_reg;

    reg [PKT_BURSTWRAP_W - 1 : 0] c_reg;

    reg c_enable_reg;

    reg [PKT_BYTE_CNT_W - 1 : 0] d_reg;



    generate

      if (PIPELINE_POSITION == 0) begin

        always_ff @(posedge clk or posedge reset) begin

          if (reset) begin

            a_reg <= '0;

            b_reg <= '0;

            c_reg <= '0;

            c_enable_reg <= '0;

            d_reg <= '0;

          end

          else begin

            a_reg <= a;

            b_reg <= b;

            c_reg <= c;

            c_enable_reg <= c_enable;

            d_reg <= d;

          end

        end

      end

      else begin

        always @* begin

            a_reg = a;

            b_reg = b;

            c_reg = c;

            c_enable_reg = c_enable;

            d_reg = d;

        end

      end

    endgenerate



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) ab_sub (

      .a ({1'b0, a_reg}),

      .b ({1'b0, b_reg}),

      .diff (ab_diff)

    );

    assign a_lt_b = ab_diff[PKT_BYTE_CNT_W];



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) ac_sub (

      .a ({1'b0, a_reg}),

      .b ({{(PKT_BYTE_CNT_W - PKT_BURSTWRAP_W + 1) {1'b0}}, c_reg}),

      .diff (ac_diff)

    );

    assign a_lt_c = ac_diff[PKT_BYTE_CNT_W];



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) bc_sub (

      .a ({1'b0, b_reg}),

      .b ({ {(PKT_BYTE_CNT_W - PKT_BURSTWRAP_W + 1) {1'b0}}, c_reg}),

      .diff (bc_diff)

    );

    assign b_lt_c = bc_diff[PKT_BYTE_CNT_W];



    // If d is greater than any of the values, it'll be greater than the min,

    // certainly.  If d is greater than the min, use d.  Of course, ignore c if

    // !c_enable.



    // Note: d is "number-of-symbols", of width PKT_BYTE_CNT_W. So, a constant,

    // and a power of 2 (until we support non-power-of-2 symbols/interface

    // here).

    // wire use_d = (d > a) || (d > b) || ( (d > c) && c_enable);

    // I think there's something clever I can do with masks, but my head hurts,

    // so try something simpler.

    // wire use_d =

    //   (&(~a[PKT_BYTE_CNT_W - 1:LOG2_NUMSYMBOLS])) ||

    //   (&(~b[PKT_BYTE_CNT_W-1:LOG2_NUMSYMBOLS])) ||

    //   ((&(~c[PKT_BURSTWRAP_W-1:LOG2_NUMSYMBOLS])) && c_enable

    // );

    wire [PKT_BYTE_CNT_W : 0] da_diff;

    wire [PKT_BYTE_CNT_W : 0] db_diff;

    wire [PKT_BYTE_CNT_W : 0] dc_diff;

    wire d_gt_a;

    wire d_gt_b;

    wire d_gt_c;



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) da_sub (

      .a ({1'b0, d_reg}),

      .b ({1'b0, a_reg}),

      .diff (da_diff)

    );

    assign d_gt_a = ~da_diff[PKT_BYTE_CNT_W];



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) db_sub (

      .a ({1'b0, d_reg}),

      .b ({1'b0, b_reg}),

      .diff (db_diff)

    );

    assign d_gt_b = ~db_diff[PKT_BYTE_CNT_W];



    altera_merlin_burst_adapter_subtractor #(.WIDTH (PKT_BYTE_CNT_W + 1)) dc_sub (

      .a ({1'b0, d_reg}),

      .b ({ {(PKT_BYTE_CNT_W - PKT_BURSTWRAP_W + 1) {1'b0}}, c_reg}),

      .diff (dc_diff)

    );

    assign d_gt_c = ~(d_reg < c_reg); // kevtan mod ~dc_diff[PKT_BYTE_CNT_W];



    wire use_d = d_gt_a || d_gt_b || (d_gt_c && c_enable_reg);



    wire [4:0] cmp = {a_lt_b, a_lt_c, b_lt_c, c_enable_reg, use_d};



    reg [PKT_BYTE_CNT_W - 1 : 0] p1_result;

    always @(a_reg or b_reg or c_reg or d_reg or cmp) begin

      casex (cmp)

        5'b00010: p1_result = c_reg;

        5'b00110: p1_result = b_reg;

        5'b01110: p1_result = b_reg;

        5'b10010: p1_result = c_reg;

        5'b11010: p1_result = a_reg;

        5'b11110: p1_result = a_reg;



        5'b00000: p1_result = b_reg;

        5'b00100: p1_result = b_reg;

        5'b01100: p1_result = b_reg;

        5'b10000: p1_result = a_reg;

        5'b11000: p1_result = a_reg;

        5'b11100: p1_result = a_reg;



        5'b????1: p1_result = d_reg;



        default: p1_result = 'X; // don't-care

      endcase

    end



    generate

      if (PIPELINE_POSITION == 1) begin

        always_ff @(posedge clk or posedge reset) begin

          if (reset) begin

            result <= '0;

          end

          else begin

            result <= p1_result;

          end

        end

      end

      else begin

        always @* begin

          result = p1_result;

        end

      end

    endgenerate

endmodule





module altera_merlin_burst_adapter

#(

  parameter // Merlin packet parameters

    PKT_BEGIN_BURST             = 81,

    PKT_ADDR_H                  = 79,

    PKT_ADDR_L                  = 48,

    PKT_BYTE_CNT_H              = 5,

    PKT_BYTE_CNT_L              = 0,

    PKT_BURSTWRAP_H             = 11,

    PKT_BURSTWRAP_L             = 6,

    PKT_TRANS_COMPRESSED_READ   = 14,

    PKT_TRANS_WRITE             = 13,

    PKT_TRANS_READ              = 12,

    PKT_BYTEEN_H                = 83,

    PKT_BYTEEN_L                = 80,

    PKT_BURST_TYPE_H            = 88,

    PKT_BURST_TYPE_L            = 87,    

    PKT_BURST_SIZE_H            = 86,

    PKT_BURST_SIZE_L            = 84,

    IN_NARROW_SIZE              = 0,

    OUT_NARROW_SIZE             = 0,

    OUT_FIXED                   = 0,

    OUT_COMPLETE_WRAP           = 0,

    ST_DATA_W                   = 89,

    ST_CHANNEL_W                = 8,



    // Component-specific parameters

    BYTEENABLE_SYNTHESIS        = 0,

    BURSTWRAP_CONST_MASK        = 0,

    BURSTWRAP_CONST_VALUE       = -1,

    NO_WRAP_SUPPORT = 0,

    PIPE_INPUTS = 0,

    OUT_BYTE_CNT_H              = 5,

    OUT_BURSTWRAP_H             = 11,

    COMPRESSED_READ_SUPPORT     = 1

)

(

    input clk,

    input reset,



    // -------------------

    // Command Sink (Input)

    // -------------------

    input                           sink0_valid,

    input  [ST_DATA_W-1 : 0]        sink0_data,

    input  [ST_CHANNEL_W-1 : 0]     sink0_channel,

    input                           sink0_startofpacket,

    input                           sink0_endofpacket,

    output reg                      sink0_ready,



    // -------------------

    // Command Source (Output)

    // -------------------

    output reg                      source0_valid,

    output reg [ST_DATA_W-1    : 0] source0_data,

    output reg [ST_CHANNEL_W-1 : 0] source0_channel,

    output reg                      source0_startofpacket,

    output reg                      source0_endofpacket,

    input                           source0_ready

);

  localparam PKT_BURSTWRAP_W = PKT_BURSTWRAP_H - PKT_BURSTWRAP_L + 1;



  generate if (COMPRESSED_READ_SUPPORT == 1) begin : altera_merlin_burst_adapter_full

    altera_merlin_burst_adapter_full #(

      .PKT_BEGIN_BURST           (PKT_BEGIN_BURST),

      .PKT_ADDR_H                (PKT_ADDR_H ),

      .PKT_ADDR_L                (PKT_ADDR_L),

      .PKT_BYTE_CNT_H            (PKT_BYTE_CNT_H),

      .PKT_BYTE_CNT_L            (PKT_BYTE_CNT_L ),

      .PKT_BURSTWRAP_H           (PKT_BURSTWRAP_H),

      .PKT_BURSTWRAP_L           (PKT_BURSTWRAP_L),

      .PKT_TRANS_COMPRESSED_READ (PKT_TRANS_COMPRESSED_READ),

      .PKT_TRANS_WRITE           (PKT_TRANS_WRITE),

      .PKT_TRANS_READ            (PKT_TRANS_READ),

      .PKT_BYTEEN_H              (PKT_BYTEEN_H),

      .PKT_BYTEEN_L              (PKT_BYTEEN_L),

      .PKT_BURST_TYPE_H          (PKT_BURST_TYPE_H),

      .PKT_BURST_TYPE_L          (PKT_BURST_TYPE_L),

      .PKT_BURST_SIZE_H          (PKT_BURST_SIZE_H),

      .PKT_BURST_SIZE_L          (PKT_BURST_SIZE_L),

      .IN_NARROW_SIZE            (IN_NARROW_SIZE),

      .BYTEENABLE_SYNTHESIS      (BYTEENABLE_SYNTHESIS),

      .OUT_NARROW_SIZE           (OUT_NARROW_SIZE),

      .OUT_FIXED                 (OUT_FIXED),

      .OUT_COMPLETE_WRAP         (OUT_COMPLETE_WRAP),

      .ST_DATA_W                 (ST_DATA_W),

      .ST_CHANNEL_W              (ST_CHANNEL_W),

      .BURSTWRAP_CONST_MASK      (BURSTWRAP_CONST_MASK),

      .BURSTWRAP_CONST_VALUE     (BURSTWRAP_CONST_VALUE),

	    .PIPE_INPUTS		    (PIPE_INPUTS),

	    .NO_WRAP_SUPPORT	    (NO_WRAP_SUPPORT),

      .OUT_BYTE_CNT_H            (OUT_BYTE_CNT_H),

      .OUT_BURSTWRAP_H           (OUT_BURSTWRAP_H)

    ) the_ba(

      .clk                   (clk),

      .reset                 (reset),

      .sink0_valid           (sink0_valid),

      .sink0_data            (sink0_data),

      .sink0_channel         (sink0_channel),

      .sink0_startofpacket   (sink0_startofpacket),

      .sink0_endofpacket     (sink0_endofpacket),

      .sink0_ready           (sink0_ready),

      .source0_valid         (source0_valid),

      .source0_data          (source0_data),

      .source0_channel       (source0_channel),

      .source0_startofpacket (source0_startofpacket),

      .source0_endofpacket   (source0_endofpacket),

      .source0_ready         (source0_ready)

    );

  end

  else begin : altera_merlin_burst_adapter_uncompressed_only

    altera_merlin_burst_adapter_uncompressed_only #(

      .PKT_BYTE_CNT_H            (PKT_BYTE_CNT_H),

      .PKT_BYTE_CNT_L            (PKT_BYTE_CNT_L ),

      .PKT_BYTEEN_H              (PKT_BYTEEN_H),

      .PKT_BYTEEN_L              (PKT_BYTEEN_L),

      .ST_DATA_W                 (ST_DATA_W),

      .ST_CHANNEL_W              (ST_CHANNEL_W)

    ) the_ba(

      .clk                   (clk),

      .reset                 (reset),

      .sink0_valid           (sink0_valid),

      .sink0_data            (sink0_data),

      .sink0_channel         (sink0_channel),

      .sink0_startofpacket   (sink0_startofpacket),

      .sink0_endofpacket     (sink0_endofpacket),

      .sink0_ready           (sink0_ready),

      .source0_valid         (source0_valid),

      .source0_data          (source0_data),

      .source0_channel       (source0_channel),

      .source0_startofpacket (source0_startofpacket),

      .source0_endofpacket   (source0_endofpacket),

      .source0_ready         (source0_ready)

    );

  end endgenerate 



  // synthesis translate_off

  // Check for incoming burstwrap values inconsistent with

  // BURSTWRAP_CONST_MASK.

  always @(posedge clk or posedge reset) begin

    if (~reset && sink0_valid &&

        BURSTWRAP_CONST_MASK[PKT_BURSTWRAP_W - 1:0] &

        (BURSTWRAP_CONST_VALUE[PKT_BURSTWRAP_W - 1:0] ^ sink0_data[PKT_BURSTWRAP_H : PKT_BURSTWRAP_L])

      ) begin

      $display("%t: %m: Error: burstwrap value %X is inconsistent with BURSTWRAP_CONST_MASK value %X", $time(), sink0_data[PKT_BURSTWRAP_H : PKT_BURSTWRAP_L], BURSTWRAP_CONST_MASK[PKT_BURSTWRAP_W - 1:0]);

    end

  end

  // synthesis translate_on

endmodule



module altera_merlin_burst_adapter_uncompressed_only

#(

  parameter // Merlin packet parameters

    PKT_BYTE_CNT_H  = 5,

    PKT_BYTE_CNT_L  = 0,

    PKT_BYTEEN_H    = 83,

    PKT_BYTEEN_L    = 80,

    ST_DATA_W       = 84,

    ST_CHANNEL_W    = 8

)

(

    input clk,

    input reset,



    // -------------------

    // Command Sink (Input)

    // -------------------

    input                       sink0_valid,

    input  [ST_DATA_W-1 : 0]    sink0_data,

    input  [ST_CHANNEL_W-1 : 0] sink0_channel,

    input                       sink0_startofpacket,

    input                       sink0_endofpacket,

    output reg                  sink0_ready,



    // -------------------

    // Command Source (Output)

    // -------------------

    output reg                      source0_valid,

    output reg [ST_DATA_W-1    : 0] source0_data,

    output reg [ST_CHANNEL_W-1 : 0] source0_channel,

    output reg                      source0_startofpacket,

    output reg                      source0_endofpacket,

    input                           source0_ready

);

  localparam 

    PKT_BYTE_CNT_W    = PKT_BYTE_CNT_H - PKT_BYTE_CNT_L + 1,

    NUM_SYMBOLS       = PKT_BYTEEN_H - PKT_BYTEEN_L + 1;



  wire [PKT_BYTE_CNT_W - 1 : 0] num_symbols_sig = NUM_SYMBOLS[PKT_BYTE_CNT_W - 1 : 0];



  always_comb begin : source0_data_assignments

    source0_valid = sink0_valid;

    source0_channel = sink0_channel;

    source0_startofpacket = sink0_startofpacket;

    source0_endofpacket = sink0_endofpacket;

    sink0_ready = source0_ready;



    source0_data = sink0_data;

    source0_data[PKT_BYTE_CNT_H : PKT_BYTE_CNT_L] = num_symbols_sig;

  end



endmodule





module altera_merlin_burst_adapter_full

#(

  parameter // Merlin packet parameters

    PKT_BEGIN_BURST             = 81,

    PKT_ADDR_H                  = 79,

    PKT_ADDR_L                  = 48,

    PKT_BYTE_CNT_H              = 5,

    PKT_BYTE_CNT_L              = 0,

    PKT_BURSTWRAP_H             = 11,

    PKT_BURSTWRAP_L             = 6,

    PKT_TRANS_COMPRESSED_READ   = 14,

    PKT_TRANS_WRITE             = 13,

    PKT_TRANS_READ              = 12,

    PKT_BYTEEN_H                = 83,

    PKT_BYTEEN_L                = 80,

    PKT_BURST_TYPE_H            = 88,

    PKT_BURST_TYPE_L            = 87,    

    PKT_BURST_SIZE_H            = 86,

    PKT_BURST_SIZE_L            = 84,   

    IN_NARROW_SIZE              = 0,

    OUT_NARROW_SIZE             = 0,

    OUT_FIXED                   = 0,

    OUT_COMPLETE_WRAP           = 0,

    ST_DATA_W                   = 89,

    ST_CHANNEL_W                = 8,



    // Component-specific parameters

    BYTEENABLE_SYNTHESIS        = 0,

    BURSTWRAP_CONST_MASK        = 0,

    PIPE_INPUTS			        = 0,

    NO_WRAP_SUPPORT		        = 0,

    BURSTWRAP_CONST_VALUE       = -1,

    OUT_BYTE_CNT_H              = 5,

    OUT_BURSTWRAP_H             = 11

)

(



    input clk,

    input reset,



    // -------------------

    // Command Sink (Input)

    // -------------------

    input                       sink0_valid,

    input  [ST_DATA_W-1 : 0]    sink0_data,

    input  [ST_CHANNEL_W-1 : 0] sink0_channel,

    input                       sink0_startofpacket,

    input                       sink0_endofpacket,

    output reg                  sink0_ready,



    // -------------------

    // Command Source (Output)

    // -------------------

    output reg                      source0_valid,

    output reg [ST_DATA_W-1    : 0] source0_data,

    output reg [ST_CHANNEL_W-1 : 0] source0_channel,

    output reg                      source0_startofpacket,

    output reg                      source0_endofpacket,

    input                           source0_ready

);

  localparam 

    PKT_BYTE_CNT_W          = PKT_BYTE_CNT_H - PKT_BYTE_CNT_L + 1,

    PKT_ADDR_W              = PKT_ADDR_H - PKT_ADDR_L + 1,

    PKT_BYTEEN_W            = PKT_BYTEEN_H - PKT_BYTEEN_L + 1,

    OUT_BYTE_CNT_W          = OUT_BYTE_CNT_H - PKT_BYTE_CNT_L + 1,

    OUT_BURSTWRAP_W         = OUT_BURSTWRAP_H - PKT_BURSTWRAP_L + 1,

    PKT_BURSTWRAP_W         = PKT_BURSTWRAP_H - PKT_BURSTWRAP_L + 1,

    OUT_MAX_BYTE_CNT        = 1 << (OUT_BYTE_CNT_W - 1),

    OUT_MAX_BURSTWRAP       = (1 << OUT_BURSTWRAP_W) - 1,

    NUM_SYMBOLS             = PKT_BYTEEN_H - PKT_BYTEEN_L + 1,

    PKT_BURST_SIZE_W        = PKT_BURST_SIZE_H - PKT_BURST_SIZE_L + 1,

    PKT_BURST_TYPE_W        = PKT_BURST_TYPE_H - PKT_BURST_TYPE_L + 1,

    LOG2_NUM_SYMBOLS        = (NUM_SYMBOLS == 1) ? 1 :log2ceil(NUM_SYMBOLS);



  // "min" operation on burstwrap values is a bitwise AND.

  // Todo: one input is always set to constant OUT_MAX_BURSTWRAP; this is a

  // number of the form 2^n.  Does this fact yield an optimization?

  function [PKT_BURSTWRAP_W - 1 : 0] altera_merlin_burst_adapter_burstwrap_min(

    input [PKT_BURSTWRAP_W - 1 : 0] a, b

  );

    altera_merlin_burst_adapter_burstwrap_min = a & b;

  endfunction



    // --------------------------------------------------

    // Ceil(log2()) function

    // --------------------------------------------------

    function unsigned[63:0] log2ceil;

        input reg[63:0] val;

        reg [63:0] i;



        begin

            i = 1;

            log2ceil = 0;



            while (i < val) begin

                log2ceil = log2ceil + 1;

                i = i << 1;

            end

        end

    endfunction       



  //----------------------------------------------------

  // AXSIZE encoding: run-time  size of the transaction.

  // ---------------------------------------------------

  function reg[127:0] set_byteenable_based_on_size;

      input [2:0] axsize;

           begin

              case (axsize)

                  3'b000: set_byteenable_based_on_size = 128'h00000000000000000000000000000001;

                  3'b001: set_byteenable_based_on_size = 128'h00000000000000000000000000000003;

                  3'b010: set_byteenable_based_on_size = 128'h0000000000000000000000000000000F;

                  3'b011: set_byteenable_based_on_size = 128'h000000000000000000000000000000FF;

                  3'b100: set_byteenable_based_on_size = 128'h0000000000000000000000000000FFFF;

                  3'b101: set_byteenable_based_on_size = 128'h000000000000000000000000FFFFFFFF;

                  3'b110: set_byteenable_based_on_size = 128'h0000000000000000FFFFFFFFFFFFFFFF;

                  3'b111: set_byteenable_based_on_size = 128'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

                  default:set_byteenable_based_on_size = 128'h00000000000000000000000000000001;

              endcase

          end   

  endfunction



  // ---------------------------------------------------

  // STATE MACHINE DEFINITIONS

  // ---------------------------------------------------

  typedef enum bit [2:0] { // int unsigned {

    ST_IDLE 	    = 3'b000,

    ST_COMP_TRANS   = 3'b001,	// This state is used for compressed transactions

				                // - Address and byte count needs to be calculated for every round internally

    ST_UNCOMP_TRANS = 3'b010, 	// This state is used for uncompressed transaction where address is passthrough 

				                // and bytecount is decremented based on max

    ST_UNCOMP_WR_SUBBURST = 3'b100

  } t_state;

  t_state state, next_state;



  // ---------------------------------------------------

  // AXI Burst Type Encoding

  // ---------------------------------------------------

  typedef enum bit  [1:0]

    {

        FIXED       = 2'b00,

        INCR        = 2'b01,

        WRAP        = 2'b10,

        RESERVED    = 2'b11

    } AxiBurstType;    



  // ------------------------------	

  // Note on signal naming convention used

  // in_*		--> These signals are either coming directly from sink or a combi off the sink signals

  //			--> Timing - zero cycle

  // d0_in_* 	--> Signals that are to be used in this block. It is off a mux between in_* signals 

  //		    and the 'saved' version of the signals

  //		    --> Timing - zero cycle (IF PIPE_INPUTS == 0)

  // d1_in_*    --> Signals that are output of initial flop stage.

  //            --> Timing - always delayed by 1 clock. (vs the input)

	

  // ------------------------------

  // CONSTANTS

  // ------------------------------

  wire [PKT_BYTE_CNT_W - 1 : 0] num_symbols_sig 	    = NUM_SYMBOLS		[PKT_BYTE_CNT_W - 1 : 0];

  wire [PKT_BYTE_CNT_W - 1 : 0] out_max_byte_cnt_sig 	= OUT_MAX_BYTE_CNT	[PKT_BYTE_CNT_W - 1 : 0];	

  

  // quartus integration failure

  wire [63:0]                       log2_numsymbols     = log2ceil(NUM_SYMBOLS);

  wire [PKT_BURST_SIZE_W - 1 : 0]   encoded_numsymbols  = log2_numsymbols[PKT_BURST_SIZE_W-1:0];



  // ---------------------------------------------------

  // INPUT STAGE SIGNALS CONDITIONING

  // ---------------------------------------------------



  // Internal wires

  reg [ST_DATA_W - 1 : 0 ]		d1_in_data;

  reg [ST_CHANNEL_W - 1 : 0 ]		d1_in_channel;

  reg [PKT_BURST_SIZE_W - 1 : 0]	d1_in_size;

  reg [PKT_BURST_TYPE_W - 1 : 0]	d1_in_bursttype;

  reg [PKT_BYTEEN_W - 1 : 0]		d1_in_byteen;

  reg [PKT_BURST_SIZE_W - 1 : 0] 	d0_in_size;

  reg [PKT_BURSTWRAP_W - 1 : 0] 	d0_in_burstwrap;

  reg [PKT_BURST_TYPE_W - 1 : 0] 	d0_in_bursttype;

  reg [PKT_ADDR_W - 1 : 0]	 	d0_in_addr;

  reg [PKT_BYTE_CNT_W - 1 : 0]		d0_in_bytecount;  

  reg	d0_in_narrow;

  reg	d0_in_passthru;

  reg	d0_in_valid;

  reg 	d0_in_sop;

  reg  	d0_in_compressed_read;

  reg  	d0_in_write;

  reg	d0_in_uncompressed_read;

  reg 	d1_in_eop;

  reg	d1_in_uncompressed_read;

  reg  	d1_in_narrow;

  reg   d1_in_passthru;

  reg   in_ready_hold;



  reg [PKT_BYTE_CNT_W - 1 : 0] the_min_byte_cnt_or_num_sym;



  wire [PKT_BURSTWRAP_W - 1 : 0] wrap_mask;

  wire [PKT_BURSTWRAP_W - 1 : 0] incremented_wrap_mask;

  reg disable_wrap_dist_calc;



  // Input stage registers

  reg [ST_DATA_W - 1 : 0]        in_data_reg;

  reg [ST_CHANNEL_W-1 : 0]       in_channel_reg;

  reg [PKT_BYTEEN_W - 1 : 0]	 in_byteen_reg;

  reg [PKT_BURST_SIZE_W - 1 : 0] in_size_reg;

  reg [PKT_BURSTWRAP_W - 1 : 0]  in_burstwrap_reg;

  reg [PKT_BURST_TYPE_W - 1 : 0] in_bursttype_reg;  

  reg [PKT_ADDR_W - 1 : 0]	     in_addr_reg;

  reg [PKT_BYTE_CNT_W - 1 : 0]	 in_bytecount_reg;

  reg in_compressed_read_reg;

  reg in_uncompressed_read_reg;

  reg in_narrow_reg;		// Holds the flag until next burst command.

  reg in_passthru_reg;		// Holds flag until next start of packet command

  reg in_eop_reg;

  reg in_bytecount_reg_zero;

  reg in_write_reg;

  reg in_valid_reg;

  reg in_sop_reg;





  // Length coversion

  reg [PKT_ADDR_W - 1 : 0]     	 int_nxt_addr_reg;

  reg [PKT_ADDR_W - 1 : 0]       int_nxt_addr_reg_dly;

  reg [PKT_BYTE_CNT_W - 1 : 0] 	 int_bytes_remaining_reg;

  reg [PKT_BYTE_CNT_W - 1 : 0]   out_uncomp_byte_cnt_reg;

  reg [PKT_BURSTWRAP_W - 1 :0]	 int_dist_reg;

  reg                            new_burst_reg;

  reg [PKT_BYTE_CNT_W -1:0] 	int_byte_cnt_narrow_reg;



  reg [PKT_ADDR_W - 1 : 0 ]     nxt_addr;

  reg [PKT_ADDR_W - 1 : 0 ]     nxt_addr2;

  reg [PKT_BYTE_CNT_W - 1 : 0]	nxt_byte_cnt;

  reg [PKT_BYTE_CNT_W - 1 : 0] 	nxt_uncomp_subburst_byte_cnt;

  reg [PKT_BYTE_CNT_W - 1 : 0]  nxt_byte_remaining;

  reg [PKT_BURSTWRAP_W - 1 : 0] nxt_dist;

  reg [PKT_ADDR_W - 1 : 0] 	extended_burstwrap;



  reg  [PKT_BYTE_CNT_W -1 :0] d0_int_bytes_remaining;

  reg  [PKT_ADDR_W - 1 : 0 ]  d0_int_nxt_addr;

  reg  [PKT_BURSTWRAP_W - 1 : 0 ] d0_int_dist;



  // Output registers

  reg [PKT_ADDR_W - 1 : 0] 	out_addr_reg;

  reg 				out_valid_reg;

  reg 				out_sop_reg;

  reg 				out_eop_reg;

  reg [PKT_BURSTWRAP_W - 1 : 0] out_burstwrap_reg;

  reg [PKT_BYTE_CNT_W - 1 : 0] 	out_byte_cnt_reg;

  reg 				nxt_in_ready;



//  wire [PKT_ADDR_W - 1 : 0]      nxt_out_addr;

  wire                           nxt_out_valid;

  wire                           nxt_out_sop;

  wire                           nxt_out_eop;

  wire [PKT_BURSTWRAP_W - 1 : 0] nxt_out_burstwrap;

//  wire [PKT_BYTE_CNT_W - 1 : 0]  nxt_bytecount;



  // ----------------

  // ALIAS INPUT MAPPINGS 

  // -----------------

  // cmd              PKT_TRANS_COMPRESSED_READ  PKT_TRANS_READ PKT_TRANS_WRITE

  // read                                     0               1               0

  // compressed read                          1               1               0

  // write                                    0               0               1

  // N.b. The fabric sets both PKT_TRANS_COMPRESSED_READ and PKT_TRANS_READ ???

  wire in_compressed_read	=	sink0_data [PKT_TRANS_COMPRESSED_READ];  

  wire in_write 		    =	sink0_data [PKT_TRANS_WRITE];

  wire in_read			    =	sink0_data [PKT_TRANS_READ];  

  wire in_uncompressed_read	=	in_read & ~sink0_data [PKT_TRANS_COMPRESSED_READ];



  wire [ST_DATA_W - 1 : 0] in_data = sink0_data;

  wire in_valid	= sink0_valid & in_ready_hold;  // Fbz143820 hold ready and internal valid to zero during reset

  wire in_sop	= sink0_startofpacket;

  wire in_eop	= sink0_endofpacket; 

  wire [ST_CHANNEL_W - 1 : 0] in_channel = sink0_channel;

  

  wire [PKT_ADDR_W - 1 : 0 ]	  in_addr      = sink0_data[PKT_ADDR_H : PKT_ADDR_L];

  wire [PKT_BYTEEN_W - 1 : 0]	  in_byteen    = sink0_data[PKT_BYTEEN_H : PKT_BYTEEN_L];

  wire [PKT_BYTE_CNT_W - 1 : 0]	  in_bytecount = sink0_data[PKT_BYTE_CNT_H : PKT_BYTE_CNT_L];

  wire [PKT_BURST_SIZE_W - 1 : 0] in_size      = IN_NARROW_SIZE ? sink0_data[PKT_BURST_SIZE_H : PKT_BURST_SIZE_L] : encoded_numsymbols;



  // Signals decoded based on inputs

  wire [PKT_BYTE_CNT_W - 1 : 0] in_burstcount 	= in_bytecount >> log2_numsymbols[PKT_BYTE_CNT_W -1 :0];

  wire in_narrow 	= in_size < log2_numsymbols[PKT_BYTE_CNT_W -1 :0];

  wire in_passthru	= in_burstcount <= 16;



  wire [PKT_BURST_TYPE_W - 1 : 0] in_bursttype = sink0_data[PKT_BURST_TYPE_H : PKT_BURST_TYPE_L];

  wire [PKT_BURSTWRAP_W - 1 : 0]  in_burstwrap;



  genvar i;

  generate begin : constant_or_variable_burstwrap

    for (i = 0; i < PKT_BURSTWRAP_W; i = i + 1) begin : assign_burstwrap_bit

      if (BURSTWRAP_CONST_MASK[i]) begin

        assign in_burstwrap[i] = BURSTWRAP_CONST_VALUE[i];

      end

      else begin

        assign in_burstwrap[i] = sink0_data[PKT_BURSTWRAP_L + i];

      end

    end

  end endgenerate



  // ----------------------------------

  // Input Load control signals

  // ----------------------------------



generate if (PIPE_INPUTS == 0)

 begin : NON_PIPELINED_INPUTS

    

  // Used to capture sink signals as each incoming cycle is accepted.

  wire	load_next_cmd	= d0_in_valid & sink0_ready;

  

  // Used to capture sink signals as each incoming transaction (currently only used by passthru generation)

  wire	load_next_pkt	= d0_in_valid & sink0_ready & d0_in_sop;  

  

  always_ff @(posedge clk or posedge reset) begin

	if (reset) begin

			in_channel_reg 		<= '0;

			in_data_reg 		<= '0;

			in_burstwrap_reg	<= '0;

			in_bursttype_reg	<= '0;

			in_byteen_reg		<= '0;

			in_narrow_reg		<= '0;

			in_size_reg		    <= '0;

			in_passthru_reg		<= '0;

			in_eop_reg		    <= '0;

			in_bytecount_reg_zero	    <= '0;

			in_uncompressed_read_reg    <= '0;

	end

	else begin

		if (load_next_cmd) begin

			in_channel_reg 		<= in_channel;

			in_data_reg 		<= in_data;

			in_burstwrap_reg	<= in_burstwrap;

			in_bursttype_reg	<= in_bursttype;

			in_byteen_reg		<= in_byteen;

			in_narrow_reg		<= in_narrow;

			in_size_reg		    <= in_size;

			in_bytecount_reg_zero	  <= ~|in_bytecount;

			in_uncompressed_read_reg  <= in_uncompressed_read;

            in_eop_reg                <= in_eop;

		end



		// Passthru is evaluated every transaction

                if (load_next_pkt) begin

                        in_passthru_reg         <= in_passthru;

                end

	end 

  end



  assign d0_in_size 		= new_burst_reg ? in_size	: in_size_reg;

  assign d0_in_addr 		= in_addr; 

  assign d0_in_bytecount	= in_bytecount; 

  assign d0_in_burstwrap	= new_burst_reg ? in_burstwrap 	: in_burstwrap_reg;

  assign d0_in_bursttype	= new_burst_reg ? in_bursttype 	: in_bursttype_reg;

  assign d0_in_narrow 		= new_burst_reg ? in_narrow	: in_narrow_reg;

  assign d0_in_passthru		= load_next_pkt ? in_passthru	: in_passthru_reg;

  assign d0_in_write             = in_write;

  assign d0_in_compressed_read   = in_compressed_read;

  assign d0_in_uncompressed_read = in_uncompressed_read;

  assign d0_in_valid             = in_valid;

  assign d0_in_sop               = in_sop;

  assign d1_in_eop               = in_eop_reg;

  assign d1_in_data              = in_data_reg;

  assign d1_in_channel           = in_channel_reg;

  assign d1_in_size              = in_size_reg;

  assign d1_in_bursttype         = in_bursttype_reg;

  assign d1_in_byteen            = in_byteen_reg;

  assign d1_in_uncompressed_read = in_uncompressed_read_reg;

  assign d1_in_narrow            = in_narrow_reg;

  assign d1_in_passthru          = in_passthru_reg;



 end : NON_PIPELINED_INPUTS



else 

 begin : PIPELINED_INPUTS



  reg [PKT_BURST_SIZE_W - 1 : 0]        d0_int_size;

  reg [PKT_BURSTWRAP_W - 1 : 0]         d0_int_burstwrap;

  reg [PKT_BURST_TYPE_W - 1 : 0]        d0_int_bursttype;

  reg d0_int_narrow;

  reg d0_int_passthru;



  always_ff @(posedge clk or posedge reset) begin

        if (reset) begin

            in_channel_reg          <= '0;

            in_data_reg             <= '0;

            in_burstwrap_reg        <= '0;

            in_bursttype_reg        <= '0;

            in_byteen_reg           <= '0;

            in_narrow_reg           <= '0;

            in_size_reg             <= '0;

            in_addr_reg             <= '0;

            in_passthru_reg         <= '0;

            in_eop_reg              <= '0;

            in_bytecount_reg        <= '0;

            in_bytecount_reg_zero   <= '0;

            in_uncompressed_read_reg  <= '0;

			in_write_reg		<= '0;

			in_compressed_read_reg	<= '0;

			in_uncompressed_read_reg <= '0;

			in_sop_reg		<= '0;

			in_valid_reg		<= '0;

            d1_in_eop               <= '0;

            d1_in_data              <= '0;

            d1_in_channel           <= '0;

            d1_in_size              <= '0;

            d1_in_bursttype         <= '0;

            d1_in_byteen            <= '0;

            d1_in_uncompressed_read <= '0;

            d1_in_narrow            <= '0;

            d1_in_passthru          <= '0;

			d0_int_size           <= '0;

			d0_int_burstwrap      <= '0;

			d0_int_bursttype     <= '0;

			d0_int_narrow       <= '0;

			d0_int_passthru   	<= '0;

        end

        else begin

                if (sink0_ready & in_valid) begin

                        in_channel_reg           <= in_channel;

                        in_data_reg              <= in_data;

                        in_burstwrap_reg         <= in_burstwrap;

                        in_bursttype_reg         <= in_bursttype;

                        in_byteen_reg            <= in_byteen;

                        in_narrow_reg            <= in_narrow;

                        in_size_reg              <= in_size;

                        in_addr_reg              <= in_addr;

                        in_bytecount_reg         <= in_bytecount;

                        in_bytecount_reg_zero    <= ~|in_bytecount;

                        in_uncompressed_read_reg  <= in_uncompressed_read;

                        in_eop_reg               <= in_eop;

                        in_write_reg             <= in_write;

                        in_compressed_read_reg   <= in_compressed_read;

                        in_uncompressed_read_reg <= in_uncompressed_read;

                        in_sop_reg               <= in_sop;

                end

                // Passthru is evaluated every transaction

                if (sink0_ready & in_sop & in_valid) begin

                        in_passthru_reg         <= in_passthru;

                end



		if (sink0_ready) in_valid_reg             <= in_valid;



		if ( 	( (state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) | 

			( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin

                        d1_in_eop               <= in_eop_reg;

                        d1_in_data              <= in_data_reg;

                        d1_in_channel           <= in_channel_reg;

                        d1_in_size              <= in_size_reg;

                        d1_in_bursttype         <= in_bursttype_reg;

                        d1_in_byteen            <= in_byteen_reg;

                        d1_in_uncompressed_read <= in_uncompressed_read_reg;

                        d1_in_narrow            <= in_narrow_reg;

                        d1_in_passthru          <= in_passthru_reg;

		end



                if (    ( (state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |

                        ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin

		  d0_int_size        <= in_size_reg;

		  d0_int_burstwrap   <= in_burstwrap_reg;

		  d0_int_bursttype   <= in_bursttype_reg;

		  d0_int_narrow      <= in_narrow_reg;

		  d0_int_passthru    <= in_passthru_reg;

		end





	end

  end



  assign d0_in_size             = new_burst_reg ? in_size_reg : d0_int_size;

  assign d0_in_addr             = in_addr_reg;

  assign d0_in_bytecount        = in_bytecount_reg;

  assign d0_in_burstwrap        = new_burst_reg ? in_burstwrap_reg : d0_int_burstwrap;

  assign d0_in_bursttype        = new_burst_reg ? in_bursttype_reg : d0_int_bursttype;

  assign d0_in_narrow           = new_burst_reg ? in_narrow_reg : d0_int_narrow;

  assign d0_in_passthru         = new_burst_reg ? in_passthru_reg : d0_int_passthru;

  assign d0_in_write             = in_write_reg;

  assign d0_in_compressed_read   = in_compressed_read_reg;

  assign d0_in_uncompressed_read = in_uncompressed_read_reg;

  assign d0_in_valid             = in_valid_reg;

  assign d0_in_sop               = in_sop_reg;



 end : PIPELINED_INPUTS

endgenerate



  // -------------------------------

  // Length Calculation Input Staging.

  // -------------------------------



  reg [PKT_ADDR_W -1 : 0] 	int_nxt_addr_with_offset;



  reg [PKT_BURSTWRAP_W - 1 : 0] no_wrap_dist;



  // These 2 values are part of break up of calculation from pre-flop to post-flop for timing optimization

  assign int_nxt_addr_with_offset  = int_nxt_addr_reg | extended_burstwrap & (int_nxt_addr_reg_dly + int_byte_cnt_narrow_reg);



  // Unaligned address support

  reg [PKT_ADDR_W + LOG2_NUM_SYMBOLS - 1 : 0 ] d0_in_addr_aligned_full;

  altera_merlin_address_alignment 

    # ( 

        .ADDR_W             (PKT_ADDR_W),

        .BURSTWRAP_W        (1), // Not used in burst adapter calculation usage of this module

        .TYPE_W             (0), // Not used in burst adapter calculation usage of this module

        .SIZE_W             (PKT_BURST_SIZE_W),

        .INCREMENT_ADDRESS  (0),

        .NUMSYMBOLS        (NUM_SYMBOLS)

        ) align_address_to_size

        (

            .clk(1'b0), .reset(1'b0), .in_valid(1'b0), .in_sop(1'b0), .in_eop(1'b0), .out_ready(),  // Dummy. Not used in INCREMENT_ADDRESS=0 settings

                                                                                                    // This block is purely combi

            .in_data    ( { d0_in_addr , d0_in_size } ),

            .out_data   ( d0_in_addr_aligned_full )

        );



  // On start of every new burst, take in new input values for calculations

  assign d0_int_bytes_remaining = new_burst_reg ? d0_in_bytecount: int_bytes_remaining_reg - out_byte_cnt_reg;

  assign d0_int_nxt_addr        = new_burst_reg ? d0_in_addr_aligned_full[PKT_ADDR_W-1:0] : int_nxt_addr_with_offset;

  assign d0_int_dist            = NO_WRAP_SUPPORT ? no_wrap_dist : incremented_wrap_mask - ( d0_int_nxt_addr[PKT_BURSTWRAP_W-1:0] & wrap_mask);

  always_comb begin



    if (OUT_BURSTWRAP_W == 0) begin // Special case: 1-symbol, fixed-burst slave.

      no_wrap_dist = ~nxt_out_burstwrap[PKT_BURSTWRAP_W] ? num_symbols_sig : '1;

    end

    else if (OUT_BURSTWRAP_W == 1) begin

     no_wrap_dist =  ~nxt_out_burstwrap[PKT_BURSTWRAP_W - 1] ? num_symbols_sig : '1;

    end

    else if (LOG2_NUM_SYMBOLS <= OUT_BURSTWRAP_W) begin



     no_wrap_dist = (|nxt_out_burstwrap[PKT_BURSTWRAP_W - 1: 0] &  ~nxt_out_burstwrap[PKT_BURSTWRAP_W - 1]) ? 

                    num_symbols_sig : '1;

    end

    else begin

     no_wrap_dist = num_symbols_sig;

    end



  end



  // -------------------------------

  // Output Load Control Signals 

  // -------------------------------



  // Used by output flops to load in next state when:

  // 1. source has taken command (or ready to accept)

  // 2. if no command is pending (IDLE)

  wire	load_next_out_cmd	= source0_ready | ~source0_valid;

  //wire  load_next_out_pkt	= (source0_ready & source0_endofpacket) | ~source0_valid;



  // ---------------------------------------------------

  // INTERMEDIATE CONTROL FLAGS / HOLDING REGISTERS

  // ---------------------------------------------------  

  

  always_comb begin



    // Default case : Always try to use the slaves max byte count. If a narrow transfer occurs, follow the masters num_symbols_sig

    the_min_byte_cnt_or_num_sym = d0_in_narrow ? num_symbols_sig : out_max_byte_cnt_sig;





    if (OUT_BURSTWRAP_W == 0) begin // Special case: 1-symbol, fixed-burst slave.

      disable_wrap_dist_calc = ~d0_in_burstwrap[OUT_BURSTWRAP_W];

    end

    else begin

      if (OUT_NARROW_SIZE || OUT_FIXED || OUT_COMPLETE_WRAP) begin  //AXI Slave

	// When burst type is "RESERVED" it means that a fix burst wide-to-narrow has occured

	// kevtan : added highest bit of wrap mask

        disable_wrap_dist_calc 		= (d0_in_passthru && d0_in_bursttype != RESERVED) | nxt_out_burstwrap[PKT_BURSTWRAP_W - 1]; 

        the_min_byte_cnt_or_num_sym	= (d0_in_narrow   && ~d0_in_passthru && d0_in_bursttype==WRAP) ? num_symbols_sig : out_max_byte_cnt_sig; 

                                              // kevtan : Fbz140322 : in case of narrow transfer, chop to smallest if it's not passthru

                                              //                      Calculation is messed up if narrow   

                                              //                    : added term to only chop to smallest in case of wrapping transactions

      end

      else if (OUT_BURSTWRAP_W == PKT_BURSTWRAP_W) begin // Sequential slave

        disable_wrap_dist_calc = d0_in_burstwrap[PKT_BURSTWRAP_W - 1];

      end

      else begin 

	// Dont really have a full story here to tell "Default?"

	// This assumes that OUT_BURSTWRAP_W < PKT_BURSTWRAP_W. Then looks at the slave's wrap boundary.

	// If d0_in_burstwrap[OUT_BURSTWRAP_W] is set, this is sequential?

	// If d0_in_burstwrap[OUT_BURSTWRAP_W - 1] is set, then it needs to be sequential to the slave?

        disable_wrap_dist_calc =  ~d0_in_burstwrap[OUT_BURSTWRAP_W] & d0_in_burstwrap[OUT_BURSTWRAP_W - 1];

      end

    end

  end

  

  

  // ----------------------------------------------------

  // FSM : Finite State Machine

  // For handling the control signals for burst adapter.

  // Note: Arcs in the SM will only take effect is there's no backpressurring from the source

  // ---------------------------------------------------

  

  always_comb begin : state_transition

    // default

    next_state = ST_IDLE;



    case (state)

	ST_IDLE : begin

		next_state = ST_IDLE;

					

		if (d0_in_valid) begin

			if (d0_in_write | d0_in_uncompressed_read) 	next_state = ST_UNCOMP_TRANS;

			if (d0_in_compressed_read)                  next_state = ST_COMP_TRANS;

		end

	end



	ST_UNCOMP_TRANS : begin

		next_state = ST_UNCOMP_TRANS;

		

		if (source0_endofpacket) begin

			if (~d0_in_valid) next_state = ST_IDLE;

			else begin

                if (d0_in_write | d0_in_uncompressed_read)	next_state = ST_UNCOMP_TRANS;

                if (d0_in_compressed_read)                  next_state = ST_COMP_TRANS;

            end

		end

        else begin

            if (|nxt_uncomp_subburst_byte_cnt)   next_state = ST_UNCOMP_WR_SUBBURST;

        end

	end



	ST_UNCOMP_WR_SUBBURST : begin

        next_state = ST_UNCOMP_WR_SUBBURST;



        if (source0_endofpacket) begin

            if (~d0_in_valid) next_state = ST_IDLE;

            else begin

                if (d0_in_write | d0_in_uncompressed_read)  next_state = ST_UNCOMP_TRANS;

                if (d0_in_compressed_read)                  next_state = ST_COMP_TRANS;

            end

        end

        else begin

            if (~|nxt_uncomp_subburst_byte_cnt)	next_state = ST_UNCOMP_TRANS;

        end				

    end



	ST_COMP_TRANS : begin

        next_state = ST_COMP_TRANS;



        if (source0_endofpacket) begin

            if (~d0_in_valid) begin

                next_state = ST_IDLE;

            end

            else begin

                if (d0_in_write | d0_in_uncompressed_read)	next_state = ST_UNCOMP_TRANS;

                if (d0_in_compressed_read) 			next_state = ST_COMP_TRANS;

            end

        end

    end		



  endcase

  end



  // ----------------------------------------------------

  // FSM : Controlled output control signals

  // ----------------------------------------------------

  

  // in_ready is asserted when:

  // 1. IDLE

  // 2. COMPRESSED TRANSACTION 	 : When not being back pressured by source and sending out last cmd.

  // 3. UNCOMPRESSED TRANSACTION : When not being back pressured by source



  assign nxt_in_ready = (state == ST_COMP_TRANS) ? source0_endofpacket & source0_ready | ~source0_valid :  

			            (state == ST_UNCOMP_TRANS | state == ST_UNCOMP_WR_SUBBURST) ? source0_ready | ~source0_valid :

			            in_ready_hold; // Fbz143820 hold ready and internal valid to zero during reset

  

  // out_valid is asserted:

  // 1. Following sink_valid unless in ST_COMP_TRANS, where it's always one, unless it's endofpacket.

  assign nxt_out_valid = ((state == ST_COMP_TRANS) & ~source0_endofpacket ) ? 1'b1 : d0_in_valid;

  

  // out_startofpacket

  // 1. Following sink_startofpacket unless in ST_COMP_TRANS, where it's always one for first cycle before accepted.

  assign nxt_out_sop = ( (state == ST_COMP_TRANS) & source0_ready & !new_burst_reg) ? 1'b0 : d0_in_sop;

  

  // out_endofpacket ??

  // Follows sink_endofpacket unless in ST_COMP_TRANS, where it is a compare of whether this is the last cycle

  assign nxt_out_eop = (state == ST_COMP_TRANS) ? ( source0_ready? new_burst_reg : in_bytecount_reg_zero ) : d1_in_eop; 







  always_ff @(posedge clk or posedge reset) begin

	if (reset) 	begin

		state		    <= ST_IDLE;

		out_valid_reg 	<= '0;

		out_sop_reg 	<= '0;

        in_ready_hold   <= '0;

	end

	else begin

	if (~source0_valid | source0_ready) begin

		state 		    <= next_state;

		out_valid_reg	<= nxt_out_valid;

		out_sop_reg 	<= nxt_out_sop;

    end

        in_ready_hold <= 1'b1;

	end

  end 

  

  assign sink0_ready = nxt_in_ready; // COMBI OUT??

  

  // ---------------------------------------------------

  // Converter

  // ---------------------------------------------------  



  // ---------------------------------------------------

  // Wrap boundary distance calculation

  // ---------------------------------------------------  



  // Wrap mask takes in nxt_out_burstwrap to handle cases where there's a wrapping Avalon slave with boundary < PKT_BURSTWRAP_W

  assign wrap_mask = disable_wrap_dist_calc ? '1 : nxt_out_burstwrap;



  // Must be valid in the cycle prior to each begin-subburst, for calculating begin_subburst_byte_cnt.

  altera_merlin_burst_adapter_burstwrap_increment #(.WIDTH (PKT_BURSTWRAP_W)) the_burstwrap_increment

  (

    .mask (wrap_mask),

    .inc (incremented_wrap_mask)

  );

  

  // ---------------------------------------------------

  // Length Converter

  // ---------------------------------------------------



  always_comb 

   begin : EXT_BURSTWRAP

        extended_burstwrap  = { {(PKT_ADDR_W - PKT_BURSTWRAP_W) {d0_in_burstwrap[PKT_BURSTWRAP_W -1]}}, d0_in_burstwrap };

   end



  altera_merlin_burst_adapter_min #(

    .PKT_BYTE_CNT_W (PKT_BYTE_CNT_W),

    .PKT_BURSTWRAP_W (PKT_BURSTWRAP_W),

    .PIPELINE_POSITION (2) // NO PIPELINE (ALL COMBI)

    )

   the_min (

    .clk (clk),

    .reset (reset),

    .a (d0_int_bytes_remaining),

    .b (the_min_byte_cnt_or_num_sym),

    .c (d0_int_dist),

    .c_enable (~wrap_mask[PKT_BURSTWRAP_W - 1]),

    .d (num_symbols_sig),

    .result (nxt_byte_cnt)

  );   



// synthesis translate_off



// TEMP ASSERTION FOR OWN CHECKING

//always @(posedge clk or posedge reset) begin

//        if (~reset && in_bursttype==WRAP && sink0_valid && sink0_ready && NO_WRAP_SUPPORT==1) begin

//        	$display ("SELF_CHK: WRAP transaction seen in no wrap support settings");

//	end

//end



// synthesis translate_on



  // ---------------------------------------

  // Next Address Calculation

  // ---------------------------------------

  always_comb 

   begin : NXT_ADDR_CALC



 	 nxt_addr  = d0_int_nxt_addr & ~extended_burstwrap;

	 // this part of calculation is moved to post flop (nxt_addr2 = (extended_burstwrap & (d0_int_nxt_addr + nxt_byte_cnt_narrow));



   end

 

  // ---------------------------------------

  // Length Converter Registers

  // ---------------------------------------

  always_ff @(posedge clk or posedge reset) begin

	if (reset) begin

		out_byte_cnt_reg	    <= '0;

		int_byte_cnt_narrow_reg <= '0;

		int_bytes_remaining_reg	<= '0;

		int_nxt_addr_reg	    <= '0;

        int_nxt_addr_reg_dly    <= '0;

		new_burst_reg		    <= '0;

		out_addr_reg		    <= '0;

	end

	else begin

	   if (load_next_out_cmd) begin

        out_byte_cnt_reg        <= nxt_byte_cnt;

        int_byte_cnt_narrow_reg <= (nxt_byte_cnt >> log2_numsymbols[PKT_BYTE_CNT_W -1 :0]) << d0_in_size;

        int_bytes_remaining_reg	<= d0_int_bytes_remaining;

        int_nxt_addr_reg        <= nxt_addr;

        int_nxt_addr_reg_dly    <= d0_int_nxt_addr;

        // New burst is when next byte count is equal to bytes remaining. (Used only in COMPRESSED transaction)

        new_burst_reg           <= (nxt_byte_cnt == d0_int_bytes_remaining) | next_state != ST_COMP_TRANS;

        // Initial address and non-COMPRESSED transaction address does not use offset.

        out_addr_reg		    <= new_burst_reg ? d0_in_addr : int_nxt_addr_with_offset;

	   end

	end

  end



 // ----------------------------------------------------

 // Uncompressed transaction calculations

 // Address 	: No changes, just pass through (handled in the flop in for out_addr_reg) // Make it to the output?

 // Byte count 	: For reads, this will be just the num_symbols_sig

 // 		    : For writes, it will need to decrement for subsequent reads unless it's 0, 

 //               in which the next calculated byte count is used.

 // ----------------------------------------------------



  always_comb 

	begin : UNCOMPRESSED_SUBBURST_BYTE_CNT_CALC



	// During start of uncompressed transaction, load the nxt_uncomp_subburst_byte_cnt with the "current output byte count - num_symbols_sig"

	// After that, on subsequent cycles, load in the 'saved' byte count value - num_symbols_sig

	// This signal is used also for transition of the state machine to ensure we will reload the byte count with the results from 

	// length converter if we decremented to zero.

	// In essence, the wrap boundary is still observed and maintained. [Hence the use of the current output byte count when in ST_UNCOMP_TRANS.



	nxt_uncomp_subburst_byte_cnt  = 

		(state == ST_UNCOMP_TRANS) ?  

			( (source0_valid & source0_ready) ? out_byte_cnt_reg - num_symbols_sig : out_uncomp_byte_cnt_reg ) :

			out_uncomp_byte_cnt_reg - ( (source0_valid & source0_ready)? num_symbols_sig : '0)  ;



   end



  always_ff @(posedge clk or posedge reset) begin   

    if (reset) begin

		out_uncomp_byte_cnt_reg	<= '0;

    end

    else begin

	if (load_next_out_cmd) begin

		out_uncomp_byte_cnt_reg <= nxt_uncomp_subburst_byte_cnt;

	end

    end

  end



  // ---------------------------------------------------

  // Burst Type Generation

  // AXI/Avalon masters - Avalon slave	- This is pass through from packet to slave

  // AXI/Avalon masters - AXI slave		- It will always be converted to INCR type

  // ---------------------------------------------------    

  reg [PKT_BURST_TYPE_W - 1 : 0 ] out_bursttype;



  // bursttype will switch to INCR if repeated wraps detected (NOTE: ??)

  assign out_bursttype = ((d1_in_bursttype == RESERVED)| (~d1_in_passthru & OUT_NARROW_SIZE)) ? INCR : d1_in_bursttype;



  // ---------------------------------------------------

  // Burst Wrap Generation

  // Burst wrap is taken to be just the MIN between OUT_MAX_BURSTWRAP and the input burstwrap

  // This is to handle cases where the slave's wrapping boundary is different from the master's

  // Essentially, the master transaction characteristics are honored, but the burst wrap is modified. 

  // (Arguably, this can be handled by the slave)

  // NOTE: Internally, this is used to generate the wrap_mask, so to calculate the correct wrapping distance.

  // ---------------------------------------------------    

  

  assign nxt_out_burstwrap = altera_merlin_burst_adapter_burstwrap_min(OUT_MAX_BURSTWRAP, d0_in_burstwrap);



  always_ff @(posedge clk or posedge reset) begin

        if (reset) 	out_burstwrap_reg <= '0;

        else 		

                if (    ( (state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |

                        ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin

		out_burstwrap_reg <= nxt_out_burstwrap;

		end

  end



  // ---------------------------------------------------

  // Byte enable generation

  // Follow unless : in compressed transaction.

  // --------------------------------------------------- 

  reg  [LOG2_NUM_SYMBOLS - 1 : 0 ] out_addr_masked;

  wire [127:0 ] d1_initial_byteen = set_byteenable_based_on_size(d1_in_size);   // To fix quartus integration error. 

                                                                                // Unused bits are expected to be synthesized away

  reg  [PKT_BYTEEN_W - 1 : 0 ] out_byteen;



  // Unaligned address changes.

  // NOTE : Assumption : Byte enable is calculated for all cycles coming out from BA, and needs to be based on aligned address.

  //                     Hence, it cannot take directly output address of BA (which sends out unaligned address for 1st cycle)

    always_ff @(posedge clk or posedge reset) begin

        if (reset)                  out_addr_masked <= '0;

        else 

            if (load_next_out_cmd)  out_addr_masked <= new_burst_reg ? d0_in_addr_aligned_full[LOG2_NUM_SYMBOLS-1:0] : int_nxt_addr_with_offset[LOG2_NUM_SYMBOLS-1:0];

    end



  always_comb begin

	if (BYTEENABLE_SYNTHESIS == 1 && d1_in_narrow == 1 && (state == ST_COMP_TRANS) ) 

		out_byteen 	= d1_initial_byteen [NUM_SYMBOLS-1:0] << out_addr_masked;

	else

		out_byteen	= d1_in_byteen;

  end





  // --------------------------------------------------- 

  // Mapping of output signals. This will help to see what is comb out or flop out

  // --------------------------------------------------- 

  

  always_comb begin : source0_out_assignments

    

	source0_valid		    = out_valid_reg;

	source0_startofpacket	= out_sop_reg;

	source0_endofpacket	    = nxt_out_eop; 	// COMBI



	// Generic assign to all data

	source0_data 	= d1_in_data;		

    source0_channel = d1_in_channel;



    	// Override fields the component is aware of.

    	source0_data[PKT_BYTE_CNT_H : PKT_BYTE_CNT_L] 		= d1_in_uncompressed_read ? num_symbols_sig : 

                                                              (state == ST_UNCOMP_WR_SUBBURST) ? out_uncomp_byte_cnt_reg : 

                                                              out_byte_cnt_reg; // COMBI

    	source0_data[PKT_ADDR_H : PKT_ADDR_L]               = out_addr_reg; 

    	source0_data[PKT_BURSTWRAP_H : PKT_BURSTWRAP_L]     = out_burstwrap_reg;

    	source0_data[PKT_BURST_TYPE_H : PKT_BURST_TYPE_L]   = out_bursttype;	// COMBI

    	source0_data[PKT_BYTEEN_H: PKT_BYTEEN_L]            = out_byteen;		// COMBI

  end



  

endmodule





