// (C) 2001-2016 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/15.1/ip/merlin/altera_merlin_burst_adapter/new_source/altera_merlin_burst_adapter_new.sv#1 $
// $Revision: #1 $
// $Date: 2015/08/09 $
// $Author: swbranch $

`timescale 1 ns / 1 ns

// -------------------------------------------------------------------
// Merlin Burst Adapter: converts incoming burst packets to fit slave burst
// capabilities. 
// -------------------------------------------------------------------
module altera_merlin_burst_adapter_new
#(
    parameter 
    // Standard merlin packet parameters that indicate
    // field position within the packet
    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,
    ST_DATA_W                   = 89,
    ST_CHANNEL_W                = 8,

    // The values here are used to infer the slave's maximum
    // burst count and constant wrapping boundary (if it exists)
    OUT_BYTE_CNT_H              = 5,
    OUT_BURSTWRAP_H             = 11,

    // Indicates if incoming packets can have sizes less
    // than the data width
    IN_NARROW_SIZE              = 0,

    // Indicates if the endpoint slave can accept packets
    // with sizes less than the data width
    OUT_NARROW_SIZE             = 0,

    // Indicates if the endpoint slave can accept fixed bursts
    OUT_FIXED                   = 0,

    // Indicates if the endpoint slave can accept wrap bursts
    OUT_COMPLETE_WRAP           = 0,

    // Enables byteenable synthesis, used to convert size to
    // byteenables
    BYTEENABLE_SYNTHESIS        = 0,

    // A mask that indicates which bits of the burstwrap field are
    // constant. Used for optimization purposes.
    BURSTWRAP_CONST_MASK        = 0,

    // Indicates the value of burstwrap bits that are constant when
    // used with BURSTWRAP_CONST_MASK
    BURSTWRAP_CONST_VALUE       = -1,

    // Controls wrapping support. For optimization purposes.
    NO_WRAP_SUPPORT             = 0,
    INCOMPLETE_WRAP_SUPPORT     = 1,

    // Pipelining options
    PIPE_INPUTS                 = 0,
    PIPE_INTERNAL               = 0
)
(
    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
);

    // Widths of various fields in the packet
    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,
    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;

    localparam
    NUM_SYMBOLS           = PKT_BYTEEN_H - PKT_BYTEEN_L + 1,
    LOG2_NUM_SYMBOLS      = log2ceil(NUM_SYMBOLS),
    ADDR_MASK_SEL         = (NUM_SYMBOLS == 1) ? 1 : log2ceil(NUM_SYMBOLS);
    
    // We try to keep everything in terms of words (transfers) instead of
    // bytes in this implementation. Cognitive ease!
    localparam
    IN_LEN_W              = PKT_BYTE_CNT_W - LOG2_NUM_SYMBOLS,
    MAX_IN_LEN            = 1 << (IN_LEN_W - 1),
    OUT_LEN_W             = OUT_BYTE_CNT_W - LOG2_NUM_SYMBOLS,
    MAX_OUT_LEN           = 1 << (OUT_LEN_W - 1),

    BNDRY_WIDTH           = PKT_BURSTWRAP_W,
    OUT_BOUNDARY          = MAX_OUT_LEN * NUM_SYMBOLS,
    BYTE_TO_WORD_SHIFT    = log2ceil(NUM_SYMBOLS),
    BYTE_TO_WORD_SHIFT_W  = log2ceil(BYTE_TO_WORD_SHIFT) + 1;

    // Determines the protocol from the features that are enabled or disabled.
    // Should be moved to the code that parameterizes this adapter.
    localparam
    AXI_SLAVE             = OUT_FIXED & OUT_NARROW_SIZE & OUT_COMPLETE_WRAP,
    IS_WRAP_AVALON_SLAVE  = !AXI_SLAVE & (PKT_BURSTWRAP_H != OUT_BURSTWRAP_H),
    IS_INCR_SLAVE         = !AXI_SLAVE & !IS_WRAP_AVALON_SLAVE,
    NON_BURSTING_SLAVE    = (MAX_OUT_LEN == 1),
    // This parameter indicates that the system is purely INCR avalon master/slave
    INCR_AVALON_SYS       = IS_INCR_SLAVE && (PKT_BURSTWRAP_W == 1) && (OUT_BURSTWRAP_W == 1) && (IN_NARROW_SIZE == 0);

    // ---------------------------------------------------
    // State definitions
    // ---------------------------------------------------
    typedef enum bit [1:0] {

        // The idle state.
        ST_IDLE         = 2'b00,

        // Adapter enters this state when the converters accept a compressed 
        // transaction (read). Address and burst length is calculated 
        // for every output transfer.
        ST_COMP_TRANS   = 2'b01,

        // Adapter enters this state when the converters accept uncompressed 
        // transactions (writes, generally). Address is passed through and 
        // burst length is decremented according to the conventions of the
        // packet format.
        ST_UNCOMP_TRANS = 2'b10
    } t_state;

    t_state state, next_state;

    // ---------------------------------------------------
    // Merlin packet burst type encoding
    // ---------------------------------------------------
    typedef enum bit[1:0]
    {
        FIXED       = 2'b00,
        INCR        = 2'b01,
        WRAP        = 2'b10,
        REP_WRAP    = 2'b11
    } BurstType;

    // ---------------------------------------------------
    // Here we go!
    //
    // An optional input pipeline stage. We typically do not use this
    // because the interconnect allows users to add pipelines just
    // before the burst adapter inputs.
    //
    // Signal prefix entering this stage: sink0_*
    // Signal prefix exiting this stage: sink0_pipe_*
    // ---------------------------------------------------
    wire                         sink0_pipe_valid;
    wire [ST_DATA_W    - 1 : 0]  sink0_pipe_data;
    wire [ST_CHANNEL_W - 1 : 0]  sink0_pipe_channel;
    wire                         sink0_pipe_sop;
    wire                         sink0_pipe_eop;
    wire                         sink0_pipe_ready;

    generate
    if (PIPE_INPUTS == 1) begin : input_pipeline
        altera_avalon_st_pipeline_stage #(
            .SYMBOLS_PER_BEAT (1),
            .BITS_PER_SYMBOL  (ST_DATA_W),
            .USE_PACKETS      (1),
            .USE_EMPTY        (0),
            .EMPTY_WIDTH      (0),
            .CHANNEL_WIDTH    (ST_CHANNEL_W),
            .PACKET_WIDTH     (2),
            .ERROR_WIDTH      (0),
            .PIPELINE_READY   (1)
        ) input_pipe (
            .clk               (clk),
            .reset             (reset),

            .in_ready          (sink0_ready),
            .in_valid          (sink0_valid),
            .in_startofpacket  (sink0_startofpacket),
            .in_endofpacket    (sink0_endofpacket),
            .in_data           (sink0_data),
            .in_channel        (sink0_channel),

            .out_ready         (sink0_pipe_ready),
            .out_valid         (sink0_pipe_valid),
            .out_startofpacket (sink0_pipe_sop),
            .out_endofpacket   (sink0_pipe_eop),
            .out_data          (sink0_pipe_data),
            .out_channel       (sink0_pipe_channel),

            .in_empty          (1'b0),
            .in_error          (1'b0),
            .out_empty         (),
            .out_error         ()
        );
    end
    else begin : no_input_pipeline

        assign sink0_pipe_valid   = sink0_valid;
        assign sink0_pipe_data    = sink0_data;
        assign sink0_pipe_channel = sink0_channel;
        assign sink0_pipe_sop     = sink0_startofpacket;
        assign sink0_pipe_eop     = sink0_endofpacket;
        assign sink0_ready        = sink0_pipe_ready;

    end 
    endgenerate

    // --------------------------------------------------
    // Signal extraction stage. We extract signals from
    // the packet payload and compute some values.
    //
    // Signal prefix entering this stage: sink0_pipe_*
    // Signal prefix exiting this stage: in_*
    // --------------------------------------------------
    wire [PKT_BURST_TYPE_W - 1 : 0]  in_bursttype         = sink0_pipe_data[PKT_BURST_TYPE_H : PKT_BURST_TYPE_L];
    wire [PKT_BYTE_CNT_W   - 1 : 0]  in_bytecount         = sink0_pipe_data[PKT_BYTE_CNT_H : PKT_BYTE_CNT_L];
    wire [PKT_ADDR_W       - 1 : 0]  in_addr              = sink0_pipe_data[PKT_ADDR_H : PKT_ADDR_L];
    wire [63 : 0]                    log2_numsymbols      = log2ceil(NUM_SYMBOLS);
    wire [PKT_BYTE_CNT_W   - 1 : 0]  in_burstcount        = in_bytecount >> log2_numsymbols[PKT_BYTE_CNT_W - 1 : 0];
    wire [IN_LEN_W         - 1 : 0]  in_len               = in_burstcount[IN_LEN_W - 1 : 0];
    wire [PKT_BURST_SIZE_W - 1 : 0]  in_size              = sink0_pipe_data[PKT_BURST_SIZE_H : PKT_BURST_SIZE_L];
    wire                             in_write             = sink0_pipe_data[PKT_TRANS_WRITE];
    wire                             in_compressed_read   = sink0_pipe_data[PKT_TRANS_COMPRESSED_READ];
    wire                             in_read              = sink0_pipe_data[PKT_TRANS_READ];
    wire                             in_uncompressed_read = in_read & ~sink0_pipe_data[PKT_TRANS_COMPRESSED_READ];
    wire                             in_sop               = sink0_pipe_sop;
    wire                             in_eop               = sink0_pipe_eop;
    wire [PKT_BYTEEN_W     - 1 : 0]  in_byteen            = sink0_pipe_data[PKT_BYTEEN_H : PKT_BYTEEN_L];
    wire                             in_passthru          = in_burstcount <= 16;

    wire                             in_valid;
    reg                              in_ready_hold;
    wire                             in_narrow;
    wire [PKT_BURSTWRAP_W  - 1 : 0]  in_burstwrap;
    wire [PKT_ADDR_W       - 1 : 0]  in_aligned_addr;
    wire [PKT_BURSTWRAP_W  - 1 : 0]  in_boundary;

    // Used to keep ready low during reset
    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            in_ready_hold <= '0;
        end else begin
            in_ready_hold <= '1;
        end
    end

    assign in_valid = sink0_pipe_valid & in_ready_hold;
    assign in_narrow = in_size < log2_numsymbols[PKT_BYTE_CNT_W - 1 : 0];

    // Optimization: extract burstwrap, and drive the constant bits to
    // their constant values to help the synthesis tool.
    genvar i;
    generate
        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_pipe_data[PKT_BURSTWRAP_L + i];
            end
        end
    endgenerate

    // Addresses in the packet can be unaligned. Here we align the address
    // for ease of internal calculations. The initial output address may
    // still be unaligned to preserve the original transaction intention.
    
    wire [PKT_ADDR_W + LOG2_NUM_SYMBOLS - 1 : 0] out_mask_and_aligned_addr;
    altera_merlin_address_alignment
    #(
        .ADDR_W             (PKT_ADDR_W),
        .BURSTWRAP_W        (1), // unused because we just want to align address
        .TYPE_W             (0), // unused because we just want to align address
        .SIZE_W             (PKT_BURST_SIZE_W),
        .INCREMENT_ADDRESS  (0),
        .NUMSYMBOLS         (NUM_SYMBOLS)
    ) align_address_to_size
    (
        // Not used when INCREMENT_ADDRESS = 0
        .clk       (1'b0), 
        .reset     (1'b0), 
        .in_valid  (1'b0), 
        .in_sop    (1'b0), 
        .in_eop    (1'b0), 
        .out_ready (),

        .in_data   ({ in_addr, in_size }),
        .out_data  (out_mask_and_aligned_addr)
    );

    assign in_aligned_addr = out_mask_and_aligned_addr[PKT_ADDR_W - 1 : 0];

    // Incrementing the burstwrap provides the wrapping boundary for
    // wrapping transactions.
    altera_merlin_burst_adapter_burstwrap_increment 
    #(
        .WIDTH (PKT_BURSTWRAP_W)
    ) the_burstwrap_increment
    (
        .mask (in_burstwrap),
        .inc  (in_boundary)
    );

    localparam OUT_BNDRY_ADDR_SEL_W = log2ceil(OUT_BOUNDARY);
    localparam OUT_BOUNDARY_WIDTH   = OUT_BNDRY_ADDR_SEL_W + 1;

    // address to use for distance calculations when the transaction
    // boundary is less than the slave's wrapping boundary.
    wire [PKT_ADDR_W           - 1 : 0]     in_bndry_addr_sel;

    // the length (in words) to the transaction boundary (if it exists)
    wire [IN_LEN_W             - 1 : 0]     len_to_in_bndry;

    // the length (in words) to the slave's boundary (if it exists)
    wire [OUT_BOUNDARY_WIDTH   - 1 : 0]     len_to_out_bndry;

    reg  [IN_LEN_W             - 1 : 0]     first_len;
    wire [BYTE_TO_WORD_SHIFT_W - 1 : 0]     byte_to_word_shift;
    assign byte_to_word_shift = BYTE_TO_WORD_SHIFT[BYTE_TO_WORD_SHIFT_W - 1 : 0];

    // This part calculates the length that is required to align the burst to
    // the transaction's wrapping boundary (if it exists), or to the slave's
    // wrapping boundary (if it exists). We pre-compute this ahead of the
    // converters to minimize the logic loops in determining the output
    // burst lengths. Note that incoming addresses for wrapping transactions
    // are always aligned to size by definition.

    assign in_bndry_addr_sel = in_addr & in_burstwrap;
    assign len_to_in_bndry = (in_boundary - in_bndry_addr_sel) >> byte_to_word_shift;
    
    generate

        if (OUT_BNDRY_ADDR_SEL_W > 0) begin : len_to_out_bndry_calc
            wire [OUT_BNDRY_ADDR_SEL_W - 1 : 0] out_bndry_addr_sel;

            // We have to use the aligned address, because this part may
            // handle incoming incrementing bursts which can be unaligned.
            assign out_bndry_addr_sel = in_aligned_addr[OUT_BNDRY_ADDR_SEL_W - 1 : 0];
            assign len_to_out_bndry   = (OUT_BOUNDARY - out_bndry_addr_sel) >> byte_to_word_shift;
        end 
        
        // A nonsensical corner-case of a wrapping slave with 
        // MAX_OUT_LEN = 1, NUM_SYMBOLS = 1
        else begin : len_to_out_bndry_calc_corner
            assign len_to_out_bndry = OUT_BOUNDARY >> byte_to_word_shift;
        end

    endgenerate

    // --------------------------------------------------
    // Optional internal pipeline stage. 
    //
    // Note that we still buffer the transfer if the pipeline stage is 
    // unused, because the adapter must accept read transactions before 
    // converting them. Failure to do this will lead to masters receiving 
    // responses before their commands have been accepted in unpipelined 
    // systems. The buffering registers are named in_*_reg.
    //
    // Notes on signal naming convention used:
    //
    // in_*       --> These signals are coming directly from the previous stage.
    //            --> Timing - zero cycle delta
    // d0_in_*    --> Signals that are outputs of this stage.
    //            --> Timing - zero cycle delta (IF PIPE_INTERNAL == 0) else 1 clock
    // d1_in_*    --> Signals that are outputs of this stage.
    //            --> Timing - always delayed by 1 clock. (vs the input)
    // --------------------------------------------------
    reg                             in_sop_reg;
    reg                             in_eop_reg;
    reg                             in_valid_reg;
    reg                             in_compressed_read_reg;
    reg                             in_uncompressed_read_reg;
    reg                             in_write_reg;
    reg                             in_passthru_reg;
    reg [PKT_BURST_SIZE_W - 1 : 0]  in_size_reg;
    reg [ST_DATA_W        - 1 : 0]  in_data_reg;
    reg [ST_CHANNEL_W     - 1 : 0]  in_channel_reg;
    reg [PKT_BURST_TYPE_W - 1 : 0]  in_bursttype_reg;
    reg [PKT_BURSTWRAP_W  - 1 : 0]  in_burstwrap_reg;
    reg [PKT_BYTEEN_W     - 1 : 0]  in_byteen_reg;
    reg [PKT_ADDR_W       - 1 : 0]  in_addr_reg;
    reg [PKT_ADDR_W       - 1 : 0]  in_aligned_addr_reg;
    reg [IN_LEN_W         - 1 : 0]  in_len_reg;
    reg                             in_narrow_reg;

    reg [PKT_ADDR_W       - 1 : 0]  d0_in_addr;
    reg [PKT_ADDR_W       - 1 : 0]  d0_in_aligned_addr;
    reg                             d0_in_sop;
    reg                             d0_in_compressed_read;
    reg                             d0_in_uncompressed_read;
    reg                             d0_in_write;
    reg [PKT_BURST_TYPE_W - 1 : 0]  d0_in_bursttype;
    reg [PKT_BURSTWRAP_W  - 1 : 0]  d0_in_burstwrap;
    reg [PKT_BURSTWRAP_W  - 1 : 0]  d0_in_burstwrap_value;
    reg [PKT_BURST_SIZE_W - 1 : 0]  d0_in_size;
    reg [PKT_BURST_SIZE_W - 1 : 0]  d0_in_size_value;
    reg [IN_LEN_W         - 1 : 0]  d0_in_len;
    reg                             d0_in_valid;
        
    reg                             d1_in_narrow;
    reg [PKT_ADDR_W       - 1 : 0]  d1_in_aligned_addr;
    reg                             d1_in_eop;
    reg                             d1_in_compressed_read;
    reg                             d1_in_uncompressed_read;
    reg [ST_DATA_W        - 1 : 0]  d1_in_data;
    reg [ST_CHANNEL_W     - 1 : 0]  d1_in_channel;
    reg                             d1_in_write;
    reg [PKT_BURST_TYPE_W - 1 : 0]  d1_in_bursttype;
    reg [PKT_BURSTWRAP_W  - 1 : 0]  d1_in_burstwrap;
    reg                             d1_in_passthru;
    reg [PKT_BURST_SIZE_W - 1 : 0]  d1_in_size;
    reg [PKT_BYTEEN_W     - 1 : 0]  d1_in_byteen;

    reg                             nb;

    generate
        if (PIPE_INTERNAL == 0) begin : no_internal_pipeline

            always_ff @(posedge clk or posedge reset) begin
                if (reset) begin
                    in_eop_reg               <= '0;
                    in_compressed_read_reg   <= '0;
                    in_uncompressed_read_reg <= '0;
                    in_data_reg              <= '0;
                    in_channel_reg           <= '0;
                    in_write_reg             <= '0;
                    in_bursttype_reg         <= '0;
                    in_burstwrap_reg         <= '0;
                    in_passthru_reg          <= '0;
                    in_size_reg              <= '0;
                    in_byteen_reg            <= '0;
                    in_aligned_addr_reg      <= '0;
                    in_narrow_reg            <= '0;
                end else begin
                    if (sink0_pipe_valid & sink0_pipe_ready) begin
                        in_eop_reg               <= in_eop;
                        in_data_reg              <= sink0_pipe_data;
                        in_channel_reg           <= sink0_pipe_channel;
                        in_compressed_read_reg   <= in_compressed_read;
                        in_uncompressed_read_reg <= in_uncompressed_read;
                        in_write_reg             <= in_write;
                        in_bursttype_reg         <= in_bursttype;
                        in_burstwrap_reg         <= in_burstwrap;
                        in_size_reg              <= in_size;
                        in_byteen_reg            <= in_byteen;
                        in_aligned_addr_reg      <= in_aligned_addr;
                        in_narrow_reg            <= in_narrow;
                    end
                    // length changes during packets, so sample
                    // length-dependent signals at the start
                    if (sink0_pipe_valid & sink0_pipe_ready & in_sop) begin
                        in_passthru_reg <= in_passthru;
                    end
                end // else: !if(reset)
            end // always_ff @

            always_comb begin
                d0_in_sop                = in_sop;
                d0_in_compressed_read    = in_compressed_read;
                d0_in_uncompressed_read  = in_uncompressed_read;
                d0_in_write              = in_write;
                d0_in_burstwrap          = in_burstwrap;
                d0_in_size               = in_size;
                d0_in_addr               = in_addr;
                d0_in_aligned_addr       = in_aligned_addr;
                d0_in_len                = in_len;
                d0_in_valid              = in_valid;

                d1_in_eop                = in_eop_reg;
                d1_in_compressed_read    = in_compressed_read_reg;
                d1_in_uncompressed_read  = in_uncompressed_read_reg;
                d1_in_write              = in_write_reg;
                d1_in_burstwrap          = in_burstwrap_reg;
                d1_in_size               = in_size_reg;
                d1_in_aligned_addr       = in_aligned_addr_reg;
                d1_in_data               = in_data_reg;
                d1_in_channel            = in_channel_reg;
                d1_in_bursttype          = in_bursttype_reg;
                d1_in_passthru           = in_passthru_reg;
                d1_in_byteen             = in_byteen_reg;
                d1_in_narrow             = in_narrow_reg;

                // Assign after the related d1_in_* signals have been assigned.
                d0_in_size_value         = nb ? d0_in_size : d1_in_size;
                d0_in_burstwrap_value    = nb ? d0_in_burstwrap : d1_in_burstwrap;
            end

        end // block: no_internal_pipeline
        else begin : internal_pipeline

            reg [PKT_BURST_SIZE_W - 1 : 0] d0_in_size_dl;
            reg [PKT_BURSTWRAP_W - 1 : 0]  d0_in_burstwrap_dl;

            always_ff @(posedge clk or posedge reset) begin
                if (reset) begin
                    in_eop_reg               <= '0;
                    in_sop_reg               <= '0;
                    in_compressed_read_reg   <= '0;
                    in_uncompressed_read_reg <= '0;
                    in_data_reg              <= '0;
                    in_channel_reg           <= '0;
                    in_write_reg             <= '0;
                    in_bursttype_reg         <= '0;
                    in_burstwrap_reg         <= '0;
                    in_passthru_reg          <= '0;
                    in_size_reg              <= '0;
                    in_byteen_reg            <= '0;
                    in_addr_reg              <= '0;
                    in_aligned_addr_reg      <= '0;
                    in_len_reg               <= '0;
                    in_narrow_reg            <= '0;
                    in_valid_reg             <= '0;
                    
                    d1_in_eop                <= '0;
                    d1_in_compressed_read    <= '0;
                    d1_in_data               <= '0;
                    d1_in_channel            <= '0;
                    d1_in_write              <= '0;
                    d1_in_bursttype          <= '0;
                    d1_in_burstwrap          <= '0;
                    d1_in_passthru           <= '0;
                    d1_in_size               <= '0;
                    d0_in_size_dl            <= '0;
                    d0_in_burstwrap_dl       <= '0;
                    d1_in_byteen             <= '0;
                end else begin
                    if (sink0_pipe_valid & sink0_pipe_ready) begin
                        in_eop_reg               <= in_eop;
                        in_sop_reg               <= in_sop;
                        in_data_reg              <= sink0_pipe_data;
                        in_channel_reg           <= sink0_pipe_channel;
                        in_compressed_read_reg   <= in_compressed_read;
                        in_uncompressed_read_reg <= in_uncompressed_read;
                        in_write_reg             <= in_write;
                        in_bursttype_reg         <= in_bursttype;
                        in_burstwrap_reg         <= in_burstwrap;
                        in_size_reg              <= in_size;
                        in_byteen_reg            <= in_byteen;
                        in_addr_reg              <= in_addr;
                        in_aligned_addr_reg      <= in_aligned_addr;
                        in_len_reg               <= in_len;
                        in_narrow_reg            <= in_narrow;
                    end
                    // length changes during packets, so sample
                    // length-dependent signals at the start
                    if (in_valid & sink0_pipe_ready & in_sop)
                        in_passthru_reg <= in_passthru;
                    if (sink0_pipe_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_compressed_read   <= in_compressed_read_reg;
                        d1_in_data              <= in_data_reg;
                        d1_in_channel           <= in_channel_reg;
                        d1_in_write             <= in_write_reg;
                        d1_in_bursttype         <= in_bursttype_reg;
                        d1_in_burstwrap         <= in_burstwrap_reg;
                        d0_in_burstwrap_dl      <= in_burstwrap_reg;
                        d1_in_passthru          <= in_passthru_reg;
                        d1_in_size              <= in_size_reg;
                        d0_in_size_dl           <= in_size_reg;
                        d1_in_byteen            <= in_byteen_reg;
                        d1_in_aligned_addr      <= in_aligned_addr_reg;
                        d1_in_narrow            <= in_narrow_reg;
                        d1_in_uncompressed_read <= in_uncompressed_read_reg;
                    end // if (((state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |...
                end // else: !if(reset)
            end // always_ff @

            always_comb begin
                d0_in_valid             = in_valid_reg;
                d0_in_sop               = in_sop_reg;
                d0_in_compressed_read   = in_compressed_read_reg;
                d0_in_uncompressed_read = in_uncompressed_read_reg;
                d0_in_write             = in_write_reg;
                d0_in_burstwrap         = in_burstwrap_reg;
                d0_in_size              = in_size_reg;
                d0_in_size_value        = nb ? in_size_reg : d0_in_size_dl;
                d0_in_burstwrap_value   = nb ? in_burstwrap_reg : d0_in_burstwrap_dl;
                d0_in_addr              = in_addr_reg;
                d0_in_aligned_addr      = in_aligned_addr_reg;
                d0_in_len               = in_len_reg;
            end // always_comb
        end // block: internal_pipeline

    endgenerate

    // --------------------------------------------------
    // Control logic stage: state machine
    // --------------------------------------------------
    always_ff @(posedge clk or posedge reset) begin
        if (reset)  begin
            state <= ST_IDLE;
        end else begin
            if (~source0_valid | source0_ready) begin
                state <= next_state;
            end
        end
    end

    always_comb begin : state_transition
        next_state = ST_IDLE;   // default
        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
            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

    // --------------------------------------------------
    // Control logic stage: signals for the converters. These signals
    // enable the correct converter for a burst type, and act as a 
    // select line when muxing the converter outputs.
    //
    // Each type of slave receives its own control logic stage, optimized
    // for that particular type.
    // --------------------------------------------------
    wire [PKT_BYTE_CNT_W  - 1 : 0]  out_byte_cnt;
    wire [IN_LEN_W        - 1 : 0]  incr_out_len;
    wire [IN_LEN_W        - 1 : 0]  wrap_out_len;
    wire [IN_LEN_W        - 1 : 0]  incr_uncompr_out_len;
    wire [IN_LEN_W        - 1 : 0]  wrap_uncompr_out_len;
    wire [PKT_ADDR_W      - 1 : 0]  incr_out_addr;
    wire [PKT_ADDR_W      - 1 : 0]  wrap_out_addr;
    wire [PKT_ADDR_W      - 1 : 0]  fixed_out_addr;
    reg  [PKT_ADDR_W      - 1 : 0]  uncompr_out_addr;
    wire [IN_LEN_W        - 1 : 0]  fixed_out_len;
    wire [PKT_ADDR_W      - 1 : 0]  out_addr;

    wire                    in_full_size_write_wrap;
    wire                    in_full_size_read_wrap;
    wire                    in_default_converter;
    wire                    in_full_size_incr;
    reg                     in_default_converter_reg;
    reg                     in_full_size_incr_reg;
    reg                     in_full_size_write_wrap_reg;
    reg                     in_full_size_read_wrap_reg;

    wire                    new_burst;
    wire                    fixed_new_burst;
    wire                    wrap_new_burst;
    wire                    incr_new_burst;

    wire                    next_out_sop;
    wire                    next_out_eop;
    wire                    is_passthru;
    wire                    enable_incr_converter;
    wire                    enable_fixed_converter;
    wire                    enable_write_wrap_converter;
    wire                    enable_read_wrap_converter;
    wire                    enable_incr_write_converter;
    wire                    enable_incr_read_converter;
    reg [IN_LEN_W - 1 : 0]  d0_first_len;


    // -----------------------------------------------------------------------
    // Enable the converters when:
    // - (sink0_pipe_valid  && (source0_ready | ~source0_valid):
    //         : when the BA is in idle (!source_valid) and there is a packet coming at input
    //           or the outpacket has been accepted and there is a packet coming
    // - (source0_endofpacket ?  1'b0 :(state == ST_COMP_TRANS) && (!source0_valid | source0_ready))
    //         : For compressed read, need something consider at end_of_packet, only when seeing
    //           end_of_packet then turn off converter.
    // Each converter will be turned on with its own enable based on different type of incoming burst
    // -----------------------------------------------------------------------
    generate
        if (NON_BURSTING_SLAVE) begin : non_bursting_converter_control
            wire [PKT_BYTE_CNT_W  - 1 : 0]  fixed_out_byte_cnt;
            assign fixed_out_byte_cnt = fixed_out_len << log2_numsymbols;

            if (PIPE_INTERNAL == 0) begin : NO_PIPELINE_INPUT
                always_comb begin
                    d0_in_bursttype            = nb ? in_bursttype : in_bursttype_reg;
                end
            end
            else begin : PIPELINE_INPUT
                    reg [PKT_BURST_TYPE_W - 1 :0]  d0_in_bursttype_dl;
                always_ff @(posedge clk or posedge reset) begin
                    if (reset) begin
                        d0_in_bursttype_dl         <= '0;
                    end else begin
                        if (((state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |
                            ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin
                            d0_in_bursttype_dl        <= in_bursttype_reg;
                        end
                    end // else: !if(reset)
                end // always_ff @
                always_comb begin
                    d0_in_bursttype            = nb ? in_bursttype_reg : d0_in_bursttype_dl;
                end
            end

            //nb: new burst signal
            assign nb                        =  fixed_new_burst;

            // -----------------------------------------------------------------------
            // I. Conveter enable signals: Turn on/off each conveter accordingly
            // -----------------------------------------------------------------------
            assign enable_fixed_converter = (d0_in_valid  && (source0_ready | !source0_valid) || (source0_endofpacket ?  1'b0 :(state == ST_COMP_TRANS) && (!source0_valid | source0_ready)));
           
            // -----------------------------------------------------------------------
            // II. Packet signals
            // -----------------------------------------------------------------------
            assign next_out_sop  = ((state == ST_COMP_TRANS) & source0_ready & !(fixed_new_burst)) ? 1'b0 : d0_in_sop;
            assign next_out_eop = (state == ST_COMP_TRANS) ?  fixed_new_burst  : d1_in_eop;
            
            // -----------------------------------------------------------------------
            // III. Output select
            // -----------------------------------------------------------------------
            assign out_byte_cnt  = fixed_out_byte_cnt;
            assign out_addr      = fixed_out_addr;
        end
        else if (INCR_AVALON_SYS) begin : incr_avalon_converter_control
            wire [PKT_BYTE_CNT_W  - 1 : 0]  incr_out_byte_cnt;
            assign incr_out_byte_cnt  = (d1_in_compressed_read ? incr_out_len : incr_uncompr_out_len) << log2_numsymbols;

            //nb: new burst signal
            assign nb                        =  incr_new_burst;
            
            // -----------------------------------------------------------------------
            // I. Conveter enable signals: Turn on/off each conveter accordingly
            // -----------------------------------------------------------------------
            assign enable_incr_converter = (d0_in_valid  && (source0_ready | !source0_valid) || (source0_endofpacket ?  1'b0 :(state == ST_COMP_TRANS) && (!source0_valid | source0_ready)));
            
            // -----------------------------------------------------------------------
            // II. Packet signals
            // -----------------------------------------------------------------------
            assign next_out_sop  = ((state == ST_COMP_TRANS) & source0_ready & !(incr_new_burst)) ? 1'b0 : d0_in_sop;
            assign next_out_eop = (state == ST_COMP_TRANS) ?  incr_new_burst  : d1_in_eop;
            
            // -----------------------------------------------------------------------
            // III. Output select
            // -----------------------------------------------------------------------
            assign out_byte_cnt  = incr_out_byte_cnt;
            assign out_addr  =  incr_out_addr;
        end
        else begin : other_converter_control
            if (IS_WRAP_AVALON_SLAVE) begin
                wire                    in_narrow_or_fixed;
                wire                    in_read_but_not_fixed_or_narrow;
                wire                    in_write_but_not_fixed_or_narrow;
                reg                     in_read_but_not_fixed_or_narrow_reg;
                reg                     in_write_but_not_fixed_or_narrow_reg;
                reg                     in_narrow_or_fixed_reg;
                reg                     d0_in_read_but_not_fixed_or_narrow;
                reg                     d0_in_write_but_not_fixed_or_narrow;
                reg                     d0_in_default_converter;
                reg                     d1_in_narrow_or_fixed;
                reg                     d1_in_read_but_not_fixed_or_narrow;
                reg                     d1_in_write_but_not_fixed_or_narrow;
                reg                     d1_in_default_converter;
                reg [IN_LEN_W - 1 : 0]  first_len_reg;

                wire [PKT_BYTE_CNT_W - 1 : 0]  fixed_out_byte_cnt;
                wire [PKT_BYTE_CNT_W - 1 : 0]  incr_out_byte_cnt;
                wire                    in_fixed = (in_bursttype == 2'b00) || (in_bursttype == 2'b11);

                // nb: new burst
                assign nb                               = (d1_in_narrow_or_fixed ? fixed_new_burst : new_burst);
                assign in_read_but_not_fixed_or_narrow  = in_compressed_read & !in_narrow_or_fixed;
                assign in_write_but_not_fixed_or_narrow = in_write & !in_narrow_or_fixed;
                assign in_narrow_or_fixed               = in_narrow || in_fixed;
                assign in_default_converter             = in_fixed || in_narrow || in_uncompressed_read;
                assign incr_out_byte_cnt                = (d1_in_compressed_read ? incr_out_len : incr_uncompr_out_len) << log2_numsymbols;
                assign fixed_out_byte_cnt               = fixed_out_len << log2_numsymbols;

                //----------------------------------------------------------------
                // I. Pipeline input stage
                //----------------------------------------------------------------
                if (PIPE_INTERNAL == 0) begin : NO_PIPELINE_INPUT
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_narrow_or_fixed_reg               <= '0;
                            in_read_but_not_fixed_or_narrow_reg  <= '0;
                            in_write_but_not_fixed_or_narrow_reg <= '0;
                            in_default_converter_reg             <= '0;
                        end else begin
                            if (sink0_pipe_ready & sink0_pipe_valid) begin
                                in_narrow_or_fixed_reg               <= in_narrow_or_fixed;
                                in_read_but_not_fixed_or_narrow_reg  <= in_read_but_not_fixed_or_narrow;
                                in_write_but_not_fixed_or_narrow_reg <= in_write_but_not_fixed_or_narrow;
                                in_default_converter_reg             <= in_default_converter;
                            end // if (sink0_pipe_ready & sink0_pipe_valid)
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_first_len                         = first_len;
                        d0_in_read_but_not_fixed_or_narrow   = in_read_but_not_fixed_or_narrow;
                        d0_in_write_but_not_fixed_or_narrow  = in_write_but_not_fixed_or_narrow;
                        d0_in_default_converter              = in_default_converter;
                        d1_in_narrow_or_fixed                = in_narrow_or_fixed_reg;
                        d1_in_read_but_not_fixed_or_narrow   = in_read_but_not_fixed_or_narrow_reg;
                        d1_in_write_but_not_fixed_or_narrow  = in_write_but_not_fixed_or_narrow_reg;
                        d1_in_default_converter              = in_default_converter_reg;
                    end // always_comb
                end // block: NO_PIPELINE_INPUT
                else begin : PIPELINE_INPUT
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_narrow_or_fixed_reg               <= '0;
                            in_read_but_not_fixed_or_narrow_reg  <= '0;
                            in_write_but_not_fixed_or_narrow_reg <= '0;
                            in_default_converter_reg             <= '0;
                            d1_in_narrow_or_fixed                <= '0;
                            d1_in_read_but_not_fixed_or_narrow   <= '0;
                            d1_in_write_but_not_fixed_or_narrow  <= '0;
                            d1_in_default_converter              <= '0;
                            first_len_reg                        <= '0;
                        end else begin
                            if (sink0_pipe_ready & sink0_pipe_valid) begin
                                in_narrow_or_fixed_reg               <= in_narrow_or_fixed;
                                in_read_but_not_fixed_or_narrow_reg  <= in_read_but_not_fixed_or_narrow;
                                in_write_but_not_fixed_or_narrow_reg <= in_write_but_not_fixed_or_narrow;
                                in_default_converter_reg             <= in_default_converter;
                            end // if (sink0_pipe_ready & sink0_pipe_valid)
                            if (((state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |
                                ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin
                                first_len_reg                       <= first_len;
                                d1_in_narrow_or_fixed               <= in_narrow_or_fixed_reg;
                                d1_in_read_but_not_fixed_or_narrow  <= in_read_but_not_fixed_or_narrow_reg;
                                d1_in_write_but_not_fixed_or_narrow <= in_write_but_not_fixed_or_narrow_reg;
                                d1_in_default_converter             <= in_default_converter_reg;
                            end
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_in_default_converter              = in_default_converter_reg;
                        d0_first_len                         = first_len_reg;
                        d0_in_read_but_not_fixed_or_narrow   = in_read_but_not_fixed_or_narrow_reg;
                        d0_in_write_but_not_fixed_or_narrow  = in_write_but_not_fixed_or_narrow_reg;
                    end
                end // block: PIPELINE_INPUT

                // -------------------------------------------------------------------------
                // II. First length calculation
                // -------------------------------------------------------------------------
                wire same_boundary;
                // ----------------------------------------------------------
                // Slave is a wrapping slave, if in_burst wrap has same boundary
                // pass the burst untouched.
                // ----------------------------------------------------------
                if (OUT_BNDRY_ADDR_SEL_W <= PKT_BURSTWRAP_W - 1) begin
                    assign same_boundary = (in_boundary[OUT_BNDRY_ADDR_SEL_W] == 1);
                end else begin
                    assign same_boundary = 0;
                end

                // --------------------------------------------------------------------------
                // 1. If in_burst wrapping boundary is lager or INCR burst then always
                // send first sub_burst length is aligned to slave boudary,
                // 2. Else aligned to master boundary
                // Notes:
                // For INCR, it is tricky that the length can be any value but as the slave is
                // wrapping, still needs to convert the burst at slave boundary
                // (in_len <= len_to_out_bndry): can tell the in INCR burst can totally
                // fit in slave boundary -> pass thru
                // This works same way for INCOMPLETE wrap as well, so cannot make seperate
                // optimization when dont support INCOMPLETE wrap
                // --------------------------------------------------------------------------
                wire in_len_smaller_not_cross_out_bndry;
                wire in_len_smaller_not_cross_in_bndry;

                assign in_len_smaller_not_cross_out_bndry  = (in_len <= len_to_out_bndry);
                assign in_len_smaller_not_cross_in_bndry   = (in_len <= len_to_in_bndry);
                always_comb begin
                    if ((in_boundary > OUT_BOUNDARY) || (in_burstwrap[BNDRY_WIDTH - 1] == 1)) begin
                        first_len  = len_to_out_bndry;
                        if (in_len_smaller_not_cross_out_bndry || same_boundary)
                            first_len = in_len;
                    end
                    else begin
                        first_len  = len_to_in_bndry;
                        if (in_len_smaller_not_cross_in_bndry || same_boundary)
                            first_len = in_len;
                    end
                end // always_comb

                // -----------------------------------------------------------------------
                // III. Conveter enable signals: Turn on/off each conveter accordingly
                // -----------------------------------------------------------------------
                // WRAPPING AVALON: two conveters:
                //  1. wrap_burst_conveter    -> handle full_size INCR, WRAP
                //  2. default_burst_conveter -> handle narrow_size burst
                //  opt, seperate enable for write and reach
                // -----------------------------------------------------------------------
                // fixed_new_burst && new_burst : note this for incr_write as it is write_enable, cannot turn on incase a read happen before
                assign enable_incr_write_converter = (d0_in_valid && d0_in_write_but_not_fixed_or_narrow && fixed_new_burst && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_write_but_not_fixed_or_narrow && !nb));
                assign enable_incr_read_converter  = (d0_in_valid && d0_in_read_but_not_fixed_or_narrow && fixed_new_burst && (source0_ready || !source0_valid) || (( state == ST_COMP_TRANS) && source0_ready && d1_in_read_but_not_fixed_or_narrow && !nb));
                assign enable_fixed_converter      = (d0_in_valid && d0_in_default_converter && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_default_converter && !nb));

                // -----------------------------------------------------------------------
                // IV. Packet signals
                // -----------------------------------------------------------------------
                assign next_out_sop  = ((state == ST_COMP_TRANS) & source0_ready & !(d1_in_default_converter ? fixed_new_burst : new_burst)) ? 1'b0 : d0_in_sop;
                assign next_out_eop  = (state == ST_COMP_TRANS) ?  (d1_in_default_converter ? fixed_new_burst : new_burst)  : d1_in_eop;
                
                // -----------------------------------------------------------------------
                // V. Output select
                // -----------------------------------------------------------------------
                assign out_byte_cnt  = d1_in_default_converter ? fixed_out_byte_cnt : incr_out_byte_cnt;
                assign out_addr      = d1_in_default_converter ? fixed_out_addr : incr_out_addr;
            end // if (IS_WRAP_AVALON_SLAVE)

            if (AXI_SLAVE) begin
                reg [IN_LEN_W - 1 : 0]   first_len_reg;
                reg                      d0_in_incr;
                reg                      d1_in_incr;
                reg                      in_incr_reg;
                wire                     in_read_wrap_conveter;
                wire                     in_write_wrap_conveter;
                reg                      in_read_wrap_conveter_reg;
                reg                      in_write_wrap_conveter_reg;

                reg                      d0_in_read_wrap_conveter;
                reg                      d0_in_write_wrap_conveter;
                reg                      d0_in_default_converter;
                reg                      d1_in_read_wrap_conveter;
                reg                      d1_in_write_wrap_conveter;
                reg                      d1_in_default_converter;

                wire                     in_incr                          = (in_bursttype == 2'b01) && !in_uncompressed_read;
                wire                     in_wrap                          = (in_bursttype == 2'b10);
                wire                     in_fixed                         = (in_bursttype == 2'b00) || (in_bursttype == 2'b11);
                wire                     in_narrow_read_wrap_smaller_16   = in_narrow && in_wrap && is_passthru && in_compressed_read;
                wire                     in_narrow_write_wrap_smaller_16  = in_narrow && in_wrap && is_passthru && in_write;
                wire                     in_narrow_wrap_larger_16         = in_narrow && in_wrap && !is_passthru;
                
                wire [PKT_BYTE_CNT_W  - 1 : 0]  wrap_out_byte_cnt;
                wire [PKT_BYTE_CNT_W  - 1 : 0]  fixed_out_byte_cnt;
                wire [PKT_BYTE_CNT_W  - 1 : 0]  incr_out_byte_cnt;

                assign incr_out_byte_cnt  = (d1_in_compressed_read ? incr_out_len : incr_uncompr_out_len) << log2_numsymbols;
                assign wrap_out_byte_cnt  = (d1_in_compressed_read ? wrap_out_len : wrap_uncompr_out_len) << log2_numsymbols;
                assign fixed_out_byte_cnt = fixed_out_len << log2_numsymbols;

                assign in_full_size_read_wrap  = in_compressed_read & in_wrap & !in_narrow;
                assign in_full_size_write_wrap = in_write & in_wrap & !in_narrow;
                assign in_read_wrap_conveter   = in_full_size_read_wrap  || in_narrow_read_wrap_smaller_16;
                assign in_write_wrap_conveter  = in_full_size_write_wrap || in_narrow_write_wrap_smaller_16;
                assign in_default_converter    = in_narrow_wrap_larger_16 || in_fixed || in_uncompressed_read;

                //nb: new burst signal
                assign nb                       = (d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst));
                // is_passthru : still read from real input, as we want to shift 1 clock here, all control signal and first len
                assign is_passthru = in_sop ? (in_passthru) : in_passthru_reg;
                
                //----------------------------------------------------------------
                // I. Pipeline input stage
                //----------------------------------------------------------------
                if(PIPE_INTERNAL == 0) begin : NO_PIPELINE_INPUT
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_write_wrap_conveter_reg <= '0;
                            in_read_wrap_conveter_reg  <= '0;
                            in_default_converter_reg   <= '0;
                            in_incr_reg                <= '0;
                        end else begin
                            if (sink0_pipe_ready & sink0_pipe_valid) begin
                                in_write_wrap_conveter_reg <= in_write_wrap_conveter;
                                in_read_wrap_conveter_reg  <= in_read_wrap_conveter;
                                in_default_converter_reg   <= in_default_converter;
                                in_incr_reg                <= in_incr;
                            end
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_in_incr                 = in_incr;
                        d0_in_default_converter    = in_default_converter;
                        d0_in_read_wrap_conveter   = in_read_wrap_conveter;
                        d0_in_write_wrap_conveter  = in_write_wrap_conveter;
                        d0_first_len               = first_len;
                        d1_in_default_converter    = in_default_converter_reg;
                        d1_in_read_wrap_conveter   = in_read_wrap_conveter_reg;
                        d1_in_write_wrap_conveter  = in_write_wrap_conveter_reg;
                        d1_in_incr                 = in_incr_reg;
                        d0_in_bursttype            = nb ? in_bursttype : in_bursttype_reg;
                    end
                end
                else begin : PIPELINE_INPUT
                        reg [PKT_BURST_TYPE_W - 1 :0]  d0_in_bursttype_dl;
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_write_wrap_conveter_reg <= '0;
                            in_read_wrap_conveter_reg  <= '0;
                            in_default_converter_reg   <= '0;
                            d1_in_default_converter    <= '0;
                            d1_in_read_wrap_conveter   <= '0;
                            d1_in_write_wrap_conveter  <= '0;
                            first_len_reg              <= '0;
                            in_incr_reg                <= '0;
                            d0_in_bursttype_dl         <= '0;
                        end else begin
                            if (sink0_pipe_ready & in_valid) begin
                                in_write_wrap_conveter_reg <= in_write_wrap_conveter;
                                in_read_wrap_conveter_reg  <= in_read_wrap_conveter;
                                in_default_converter_reg   <= in_default_converter;
                                first_len_reg              <= first_len;
                                in_incr_reg                <= in_incr;
                            end
                            if (((state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |
                                ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin
                                d1_in_default_converter   <= in_default_converter_reg;
                                d1_in_read_wrap_conveter  <= in_read_wrap_conveter_reg;
                                d1_in_write_wrap_conveter <= in_write_wrap_conveter_reg;
                                d1_in_incr                <= in_incr_reg;
                                d0_in_bursttype_dl        <= in_bursttype_reg;
                            end
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_in_incr                 = in_incr_reg;
                        d0_in_default_converter    = in_default_converter_reg;
                        d0_in_read_wrap_conveter   = in_read_wrap_conveter_reg;
                        d0_in_write_wrap_conveter  = in_write_wrap_conveter_reg;
                        d0_first_len               = first_len_reg;
                        d0_in_bursttype            = nb ? in_bursttype_reg : d0_in_bursttype_dl;
                    end
                end

                // -------------------------------------------------------------------------
                // II. First length calculation
                // -------------------------------------------------------------------------
                // For AXI slave, avalon master must set alwaysBurstMaxBurst so
                // INCOMPLETE wrap burst will not happen
                // 1. If any wrapping burst that smaller than 16 -> pass thru
                // 2. Else first sub_burst length is aligned to slave boundary
                // -------------------------------------------------------------------------
                //wire passthru = (in_len < len_to_out_bndry) || is_passthru; // why compare here? Keep this until we figure out why.
                always_comb begin
                    if (in_boundary > OUT_BOUNDARY) begin
                        first_len = is_passthru ? in_len : len_to_out_bndry;
                    end else begin
                        first_len = is_passthru ? in_len : len_to_in_bndry;
                    end
                end // always_comb

                // -----------------------------------------------------------------------
                // III. Conveter enable signals: Turn on/off each conveter accordingly
                // -----------------------------------------------------------------------
                // AXI slave: three conveters:
                //  1. wrap_burst_conveter    -> handle WRAP
                //     1.1 : full size wrap   --> convert to fit in slave boundary
                //     1.2 : narrow size wrap
                //                            ---> <= 16 : pass thru
                //                            ---> > 16 : convert to non-bursting
                //  2. incr_burst_convter     -> handle full/narrow size INCR
                //  3. default_burst_conveter -> handle FIXED
                // -----------------------------------------------------------------------
                // Note: narrow wrap with length larger 16 can happen with Avalon narrow wraping
                // master to AXI slave. To support this, it will hurt fmax
                // also the WA adapter currently not pack data in this case, to be better support
                // need to start from WA first
                // -----------------------------------------------------------------------
                assign new_burst                   = incr_new_burst && wrap_new_burst;
                assign enable_incr_converter       = (d0_in_valid && d0_in_incr && fixed_new_burst && wrap_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_incr && !nb));
                assign enable_write_wrap_converter = (d0_in_valid && d0_in_write_wrap_conveter && fixed_new_burst && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_write_wrap_conveter && !nb));
                assign enable_read_wrap_converter  = (d0_in_valid && d0_in_read_wrap_conveter && fixed_new_burst && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_read_wrap_conveter && !nb));
                assign enable_fixed_converter      = (d0_in_valid && d0_in_default_converter && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_default_converter && !nb));
                
                // -----------------------------------------------------------------------
                // IV. Packet signals
                // -----------------------------------------------------------------------
                assign next_out_sop  = ((state == ST_COMP_TRANS) & source0_ready & !(d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst))) ? 1'b0 : d0_in_sop;
                assign next_out_eop = (state == ST_COMP_TRANS) ?  (d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst))  : d1_in_eop;

                // -----------------------------------------------------------------------
                // V. Output select
                // -----------------------------------------------------------------------
                assign out_byte_cnt  = d1_in_default_converter ? fixed_out_byte_cnt : (d1_in_incr ? incr_out_byte_cnt : wrap_out_byte_cnt);
                assign out_addr      = d1_in_default_converter ? fixed_out_addr : (d1_in_incr ? incr_out_addr : wrap_out_addr);
            end // if (AXI_SLAVE)

            if (IS_INCR_SLAVE) begin
                reg [IN_LEN_W - 1 : 0]   first_len_reg;
                reg                      d0_in_default_converter;
                reg                      d0_in_full_size_incr;
                reg                      d0_in_full_size_write_wrap;
                reg                      d0_in_full_size_read_wrap;
                reg                      d1_in_default_converter;
                reg                      d1_in_full_size_incr;
                reg                      d1_in_full_size_write_wrap;
                reg                      d1_in_full_size_read_wrap;
                reg                      d1_in_incr;
                reg                      in_incr_reg;
                wire                     in_incr  = (in_bursttype == 2'b01);
                wire                     in_wrap  = (in_bursttype == 2'b10);

                wire [PKT_BYTE_CNT_W  - 1 : 0]  incr_out_byte_cnt;
                wire [PKT_BYTE_CNT_W  - 1 : 0]  fixed_out_byte_cnt;

                assign incr_out_byte_cnt  = (d1_in_compressed_read ? incr_out_len : incr_uncompr_out_len) << log2_numsymbols;
                assign fixed_out_byte_cnt = fixed_out_len << log2_numsymbols;

                if (NO_WRAP_SUPPORT) begin
                    assign in_default_converter      = !in_full_size_incr;
                    assign nb   = d1_in_default_converter ? fixed_new_burst : incr_new_burst;
                end
                else begin
                    wire    in_narrow_incr;
                    wire    in_fixed = (in_bursttype == 2'b00) || (in_bursttype == 2'b11);

                    assign in_narrow_incr       = in_incr & in_narrow;
                    assign in_default_converter = in_fixed || in_narrow || in_narrow_incr || in_uncompressed_read;
                    assign nb                   = (d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst));
                end

                assign in_full_size_incr         = in_incr & !in_narrow & !in_uncompressed_read;
                assign in_full_size_write_wrap   = in_write & in_wrap & !in_narrow;
                assign in_full_size_read_wrap    = in_compressed_read & in_wrap & !in_narrow;
                
                //----------------------------------------------------------------
                // I. Pipeline input stage
                //----------------------------------------------------------------
                if(PIPE_INTERNAL == 0) begin : NO_PIPELINE_INPUT
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_full_size_write_wrap_reg <= '0;
                            in_full_size_read_wrap_reg  <= '0;
                            in_full_size_incr_reg       <= '0;
                            in_default_converter_reg    <= '0;
                            in_incr_reg                 <= '0;
                        end else begin
                            if (sink0_pipe_ready & sink0_pipe_valid) begin
                                in_incr_reg                 <= in_incr;
                                in_full_size_incr_reg       <= in_full_size_incr;
                                in_full_size_write_wrap_reg <= in_full_size_write_wrap;
                                in_full_size_read_wrap_reg  <= in_full_size_read_wrap;
                                in_default_converter_reg    <= in_default_converter;
                            end
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_in_default_converter     = in_default_converter;
                        d0_in_full_size_incr        = in_full_size_incr;
                        d0_in_full_size_write_wrap  = in_full_size_write_wrap;
                        d0_in_full_size_read_wrap   = in_full_size_read_wrap;
                        d0_first_len                = first_len;
                        d1_in_incr                  = in_incr_reg;
                        d1_in_default_converter     = in_default_converter_reg;
                        d1_in_full_size_incr        = in_full_size_incr_reg;
                        d1_in_full_size_write_wrap  = in_full_size_write_wrap_reg;
                        d1_in_full_size_read_wrap   = in_full_size_read_wrap_reg;
                        d0_in_bursttype             = nb ? in_bursttype : in_bursttype_reg;
                    end
                end
                else begin : PIPELINE_INPUT
                    reg [PKT_BURST_TYPE_W - 1 :0]  d0_in_bursttype_dl;
                    always_ff @(posedge clk or posedge reset) begin
                        if (reset) begin
                            in_full_size_write_wrap_reg <= '0;
                            in_full_size_read_wrap_reg  <= '0;
                            in_full_size_incr_reg       <= '0;
                            in_default_converter_reg    <= '0;
                            d1_in_default_converter     <= '0;
                            d1_in_full_size_incr        <= '0;
                            d1_in_full_size_write_wrap  <= '0;
                            d1_in_full_size_read_wrap   <= '0;
                            d1_in_incr                  <= '0;
                            first_len_reg               <= '0;
                            in_incr_reg                 <= '0;
                            d0_in_bursttype_dl          <= '0;
                        end else begin
                            if (sink0_pipe_ready & in_valid) begin
                                in_full_size_incr_reg       <= in_full_size_incr;
                                in_full_size_write_wrap_reg <= in_full_size_write_wrap;
                                in_full_size_read_wrap_reg  <= in_full_size_read_wrap;
                                in_default_converter_reg    <= in_default_converter;
                                in_incr_reg                 <= in_incr;
                                first_len_reg               <= first_len;
                            end
                            if (((state != ST_COMP_TRANS) & (~source0_valid | source0_ready)) |
                                ( (state == ST_COMP_TRANS) & (~source0_valid | source0_ready & source0_endofpacket) ) ) begin
                                d1_in_default_converter    <= in_default_converter_reg;
                                d1_in_full_size_incr       <= in_full_size_incr_reg;
                                d1_in_full_size_write_wrap <= in_full_size_write_wrap_reg;
                                d1_in_full_size_read_wrap  <= in_full_size_read_wrap_reg;
                                d1_in_incr                 <= in_incr_reg;
                                d0_in_bursttype_dl         <= in_bursttype_reg;
                            end
                        end // else: !if(reset)
                    end // always_ff @
                    always_comb begin
                        d0_in_default_converter     = in_default_converter_reg;
                        d0_in_full_size_incr        = in_full_size_incr_reg;
                        d0_in_full_size_write_wrap  = in_full_size_write_wrap_reg;
                        d0_in_full_size_read_wrap   = in_full_size_read_wrap_reg;
                        d0_first_len                = first_len_reg;
                        d0_in_bursttype             = nb ? in_bursttype_reg : d0_in_bursttype_dl;
                    end
                end
                
                // --------------------------------------------------------------------------------------
                // II. First length calculation
                // --------------------------------------------------------------------------------------
                // Note: the slave is INCR slave, in pratical is has no boundary so if in burst is wrap
                // the sub burst can send out "slave max length" first fs the in burst not yet wraps back
                // To simplify and optimize: the first sub_burst length stills send out aligned length first
                // --------------------------------------------------------------------------------------
                // If no INCOMPLETE wrap burst
                // 1. in_boundary is larger out_boundary; first sub_burst length is: aligned to out boundary
                // 2. in_boundary is smaller out_boundary; first sub_burst length is: aligned to in boundary
                // --------------------------------------------------------------------------------------
                if (!NO_WRAP_SUPPORT) begin : HAVE_WRAP_BURSTING_SUPPORT
                    if (!INCOMPLETE_WRAP_SUPPORT) begin : no_incomplete_wrap_support
                        assign first_len = (in_boundary > OUT_BOUNDARY) ? len_to_out_bndry : len_to_in_bndry;
                    end
                    else begin : incomplete_wrap_support
                        // -------------------------------------------------------------------------
                        // If INCOMPLETE wrap support
                        // 1. The idea is still same, based on boundary and select either aligned to in/out boundary
                        // 2. But need to check if in_len is smaller to "aligned" in/out boundary for incomplete case
                        // -> the burst is pass thru is in_len is smaller
                        // -------------------------------------------------------------------------
                        wire in_len_smaller_aligned_out_bdry = (in_len <= len_to_out_bndry);
                        wire in_len_smaller_aligned_in_bdry  = (in_len <= len_to_in_bndry);
                        always_comb begin
                            if (in_boundary > OUT_BOUNDARY) begin
                                first_len = (in_len_smaller_aligned_out_bdry) ? in_len : len_to_out_bndry;
                            end
                            else begin
                                first_len = (in_len_smaller_aligned_in_bdry) ? in_len : len_to_in_bndry;
                            end
                        end
                    end // block: incomplete_wrap_support
                end

                // -----------------------------------------------------------------------
                // III. Conveter enable signals: Turn on/off each conveter accordingly
                // -----------------------------------------------------------------------
                // INCR slave: three conveters:
                //  1. wrap_burst_conveter    -> handle WRAP
                //  2. incr_burst_convter     -> handle INCR
                //  2. default_burst_conveter -> handle narrow burst
                // -----------------------------------------------------------------------
                // -----------------------------------------------------------------------
                // Purposely support AXI to Avalon: with no wrapping suppport
                // all wrapping transaction witll be converted to non-bursting sub-burst
                // 21-January-2014
                // -----------------------------------------------------------------------
                if (NO_WRAP_SUPPORT) begin
                    assign enable_incr_converter        = (d0_in_valid && d0_in_full_size_incr && fixed_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_full_size_incr && !nb));
                    assign enable_fixed_converter       = (d0_in_valid && d0_in_default_converter && incr_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_default_converter && !nb));
                    
                    // -----------------------------------------------------------------------
                    // IV. Packet signals
                    // -----------------------------------------------------------------------
                    assign next_out_sop  = (state == ST_COMP_TRANS) & source0_ready & !(d1_in_default_converter ? fixed_new_burst : incr_new_burst) ? 1'b0 : d0_in_sop;
                    assign next_out_eop = (state == ST_COMP_TRANS) ?  (d1_in_default_converter ? fixed_new_burst : incr_new_burst)  : d1_in_eop;
                    
                    // -----------------------------------------------------------------------
                    // V. Output select
                    // -----------------------------------------------------------------------
                    assign out_byte_cnt  = d1_in_default_converter ? fixed_out_byte_cnt : incr_out_byte_cnt;
                    assign out_addr  = d1_in_default_converter ? fixed_out_addr : incr_out_addr;
                end
                else begin
                    assign new_burst                    = incr_new_burst && wrap_new_burst;
                    assign enable_incr_converter        = (d0_in_valid && d0_in_full_size_incr && fixed_new_burst && wrap_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_full_size_incr && !nb));
                    assign enable_fixed_converter       = (d0_in_valid && d0_in_default_converter && new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_default_converter && !nb));
                    assign enable_write_wrap_converter  = (d0_in_valid && d0_in_full_size_write_wrap && fixed_new_burst && incr_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_full_size_write_wrap && !nb));
                    assign enable_read_wrap_converter   = (d0_in_valid && d0_in_full_size_read_wrap  && fixed_new_burst && incr_new_burst && (source0_ready || !source0_valid) || ((state == ST_COMP_TRANS) && source0_ready && d1_in_full_size_read_wrap && !nb));

                    // -----------------------------------------------------------------------
                    // IV. Packet signals
                    // -----------------------------------------------------------------------
                    assign next_out_sop  = ((state == ST_COMP_TRANS) & source0_ready & !(d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst))) ? 1'b0 : d0_in_sop;
                    assign next_out_eop = (state == ST_COMP_TRANS) ?  (d1_in_default_converter ? fixed_new_burst : (d1_in_incr ? incr_new_burst : wrap_new_burst))  : d1_in_eop;
                    
                    // -----------------------------------------------------------------------
                    // V. Output select
                    // -----------------------------------------------------------------------
                    wire [PKT_BYTE_CNT_W  - 1 : 0]  wrap_out_byte_cnt;
                    assign wrap_out_byte_cnt    = (d1_in_compressed_read ? wrap_out_len : wrap_uncompr_out_len) << log2_numsymbols;
                    
                    assign out_byte_cnt  = d1_in_default_converter ? fixed_out_byte_cnt : (d1_in_incr ? incr_out_byte_cnt : wrap_out_byte_cnt);
                    assign out_addr  = d1_in_default_converter ? fixed_out_addr : (d1_in_incr ? incr_out_addr : wrap_out_addr);
                end
            end
        end
    endgenerate

    // --------------------------------------------------
    // Control signals
    // --------------------------------------------------
    reg   source0_valid_reg;
    wire  next_source0_valid;
    reg   source0_startofpacket_reg;

    wire  is_write;
    assign is_write  = nb ? (d0_in_write) : d1_in_write;

    //-------------------------------------------------------------------------
    // Handshaking and packet signals
    // -----------------------------------------------------------------------
    // source0_valid: takes from in sink_valid unless read then wait until end_of_packet
    assign next_source0_valid  = ((state == ST_COMP_TRANS) & !source0_endofpacket) ? 1'b1 : d0_in_valid;

    // sink0_ready needs always to be asserted first, hold one after reset
    assign sink0_pipe_ready  = (state == ST_UNCOMP_TRANS) ? source0_ready || !source0_valid : (state == ST_COMP_TRANS) ? nb && source0_ready || !source0_valid : in_ready_hold;

    always_ff @(posedge clk or posedge reset) begin
        if (reset)  begin
            source0_valid_reg         <= '0;
            source0_startofpacket_reg <= '1;
        end else begin
            if (~source0_valid | source0_ready) begin
                source0_valid_reg         <= next_source0_valid;
                source0_startofpacket_reg <= next_out_sop;
            end
        end // else: !if(reset)
    end // always_ff @

    // Assign output signals
    always_comb begin
        source0_endofpacket    = next_out_eop;
        source0_startofpacket  = source0_startofpacket_reg;
        source0_valid          = source0_valid_reg;
    end

    // --------------------------------------------------
    // Converters instantiation and signal mappings.
    // --------------------------------------------------
    generate
        if (NON_BURSTING_SLAVE) begin : non_bursting_slave_converters_sel
            altera_default_burst_converter
            #(
             .PKT_BURST_TYPE_W    (PKT_BURST_TYPE_W),
             .PKT_ADDR_W          (PKT_ADDR_W),
             .PKT_BURSTWRAP_W     (PKT_BURSTWRAP_W),
             .PKT_BURST_SIZE_W    (PKT_BURST_SIZE_W),
             .LEN_W               (IN_LEN_W),
             .IS_AXI_SLAVE        (AXI_SLAVE)
            )
            the_default_burst_converter
            (
             .clk                       (clk),
             .reset                     (reset),
             .enable                    (enable_fixed_converter), // turn on if a fixed
             .in_addr                   (d0_in_aligned_addr),
             .in_addr_reg               (d1_in_aligned_addr),
             .in_bursttype              (d0_in_bursttype),
             .in_burstwrap_reg          (d1_in_burstwrap),
             .in_burstwrap_value        (d0_in_burstwrap_value),
             .in_len                    (d0_in_len),
             .in_size_value             (d0_in_size_value),
             .in_is_write               (is_write),
             .out_len                   (fixed_out_len),
             .out_addr                  (fixed_out_addr),
             .new_burst                 (fixed_new_burst)
            );
        end
        else if (INCR_AVALON_SYS) begin : system_purely_avalon_converter_sel
            //-----------------------------------------------------------------
            // When system is purely INCR, only need one converter.
            //-----------------------------------------------------------------
            altera_incr_burst_converter
            #(
             .MAX_IN_LEN          (MAX_IN_LEN),
             .MAX_OUT_LEN         (MAX_OUT_LEN),
             .ADDR_WIDTH          (PKT_ADDR_W),
             .BNDRY_WIDTH         (PKT_BURSTWRAP_W),
             .BURSTSIZE_WIDTH     (PKT_BURST_SIZE_W),
             .IN_NARROW_SIZE      (IN_NARROW_SIZE),
             .NUM_SYMBOLS         (NUM_SYMBOLS),
             .PURELY_INCR_AVL_SYS (INCR_AVALON_SYS)
            )
            the_converter_for_avalon_incr_slave
            (
             .clk                     (clk),
             .reset                   (reset),
             .enable                  (enable_incr_converter),
             .in_len                  (d0_in_len),
             .in_sop                  (d0_in_sop),
             .in_burstwrap_reg        (d1_in_burstwrap),
             .in_size_t               (d0_in_size),
             .in_size_reg             (d1_in_size),
             .in_addr                 (d0_in_aligned_addr),
             .in_addr_reg             (d1_in_aligned_addr),
             .is_write                (is_write),
             .out_len                 (incr_out_len),
             .uncompr_out_len         (incr_uncompr_out_len),
             .out_addr                (incr_out_addr),
             .new_burst_export        (incr_new_burst)
            );
        end
        else begin : converters_selection
            if (IS_WRAP_AVALON_SLAVE) begin : wrapping_avalon_slave_converter_sel
                altera_wrap_burst_converter
                #(
                 .MAX_IN_LEN            (MAX_IN_LEN),
                 .MAX_OUT_LEN           (MAX_OUT_LEN),
                 .ADDR_WIDTH            (PKT_ADDR_W),
                 .BNDRY_WIDTH           (PKT_BURSTWRAP_W),
                 .AXI_SLAVE             (AXI_SLAVE),
                 .NUM_SYMBOLS           (NUM_SYMBOLS),
                 .OPTIMIZE_WRITE_BURST  (0)
                )
                the_converter_for_avalon_wrap_slave
                (
                 .clk                               (clk),
                 .reset                             (reset),
                 .enable_read                       (enable_incr_read_converter),
                 .enable_write                      (enable_incr_write_converter),
                 .in_len                            (d0_in_len),
                 .first_len                         (d0_first_len),
                 .in_sop                            (d0_in_sop),
                 .in_burstwrap                      (d0_in_burstwrap),
                 .in_burstwrap_reg                  (d1_in_burstwrap),
                 .in_boundary                       (in_boundary),
                 .in_addr                           (d0_in_aligned_addr),
                 .in_addr_reg                       (d1_in_aligned_addr),
                 .out_len                           (incr_out_len),
                 .uncompr_out_len                   (incr_uncompr_out_len),
                 .out_addr                          (incr_out_addr),
                 .new_burst_export                  (new_burst)
                );

                altera_default_burst_converter
                #(
                 .PKT_BURST_TYPE_W    (PKT_BURST_TYPE_W),
                 .PKT_ADDR_W          (PKT_ADDR_W),
                 .PKT_BURSTWRAP_W     (PKT_BURSTWRAP_W),
                 .PKT_BURST_SIZE_W    (PKT_BURST_SIZE_W),
                 .LEN_W               (IN_LEN_W),
                 .IS_AXI_SLAVE        (AXI_SLAVE)
                )
                the_default_burst_converter
                (
                 .clk                       (clk),
                 .reset                     (reset),
                 .enable                    (enable_fixed_converter), // turn on if a fixed
                 .in_addr                   (d0_in_aligned_addr),
                 .in_addr_reg               (d1_in_aligned_addr),
                 .in_bursttype              (d0_in_bursttype),
                 .in_burstwrap_reg          (d1_in_burstwrap),
                 .in_burstwrap_value        (d0_in_burstwrap_value),
                 .in_len                    (d0_in_len),
                 .in_size_value             (d0_in_size_value),
                 .in_is_write               (is_write),
                 .out_len                   (fixed_out_len),
                 .out_addr                  (fixed_out_addr),
                 .new_burst                 (fixed_new_burst)
                );
            end
            if (AXI_SLAVE) begin : axi_slave_converter_sel
                altera_wrap_burst_converter
                #(
                 .MAX_IN_LEN              (MAX_IN_LEN),
                 .MAX_OUT_LEN             (MAX_OUT_LEN),
                 .ADDR_WIDTH              (PKT_ADDR_W),
                 .BNDRY_WIDTH             (PKT_BURSTWRAP_W),
                 .NUM_SYMBOLS             (NUM_SYMBOLS),
                 .AXI_SLAVE               (AXI_SLAVE),
                 .OPTIMIZE_WRITE_BURST    (0)
                )
                the_converter_for_avalon_wrap_slave
                (
                 .clk                               (clk),
                 .reset                             (reset),
                 .enable_read                       (enable_read_wrap_converter),
                 .enable_write                      (enable_write_wrap_converter),
                 .in_len                            (d0_in_len),
                 .first_len                         (d0_first_len),
                 .in_sop                            (d0_in_sop),
                 .in_burstwrap                      (d0_in_burstwrap),
                 .in_burstwrap_reg                  (d1_in_burstwrap),
                 .in_boundary                       (in_boundary),
                 .in_addr                           (d0_in_aligned_addr),
                 .in_addr_reg                       (d1_in_aligned_addr),
                 .out_len                           (wrap_out_len),
                 .uncompr_out_len                   (wrap_uncompr_out_len),
                 .out_addr                          (wrap_out_addr),
                 .new_burst_export                  (wrap_new_burst)
                );

                altera_incr_burst_converter
                #(
                 .MAX_IN_LEN          (MAX_IN_LEN),
                 .MAX_OUT_LEN         (MAX_OUT_LEN),
                 .ADDR_WIDTH          (PKT_ADDR_W),
                 .BNDRY_WIDTH         (PKT_BURSTWRAP_W),
                 .BURSTSIZE_WIDTH     (PKT_BURST_SIZE_W),
                 .IN_NARROW_SIZE      (IN_NARROW_SIZE),
                 .NUM_SYMBOLS         (NUM_SYMBOLS),
                 .PURELY_INCR_AVL_SYS (INCR_AVALON_SYS)
                )
                the_converter_for_avalon_incr_slave
                (
                 .clk                (clk),
                 .reset              (reset),
                 .enable             (enable_incr_converter),
                 .in_len             (d0_in_len),
                 .in_sop             (d0_in_sop),
                 .in_burstwrap_reg   (d1_in_burstwrap),
                 .in_size_t          (d0_in_size),
                 .in_size_reg        (d1_in_size),
                 .in_addr            (d0_in_aligned_addr),
                 .in_addr_reg        (d1_in_aligned_addr),
                 .is_write           (is_write),
                 .out_len            (incr_out_len),
                 .uncompr_out_len    (incr_uncompr_out_len),
                 .out_addr           (incr_out_addr),
                 .new_burst_export   (incr_new_burst)
                );

                // --------------------------------------------------
                // The fixed burst converter module
                // --------------------------------------------------
                altera_default_burst_converter
                #(
                 .PKT_BURST_TYPE_W    (PKT_BURST_TYPE_W),
                 .PKT_ADDR_W          (PKT_ADDR_W),
                 .PKT_BURSTWRAP_W     (PKT_BURSTWRAP_W),
                 .PKT_BURST_SIZE_W    (PKT_BURST_SIZE_W),
                 .LEN_W               (IN_LEN_W),
                 .IS_AXI_SLAVE        (AXI_SLAVE)
                )
                the_default_burst_converter
                (
                 .clk                       (clk),
                 .reset                     (reset),
                 .enable                    (enable_fixed_converter), // turn on if a fixed
                 .in_addr                   (d0_in_aligned_addr),
                 .in_addr_reg               (d1_in_aligned_addr),
                 .in_bursttype              (d0_in_bursttype),
                 .in_burstwrap_reg          (d1_in_burstwrap),
                 .in_burstwrap_value        (d0_in_burstwrap_value),
                 .in_len                    (d0_in_len),
                 .in_size_value             (d0_in_size_value),
                 .in_is_write               (is_write),
                 .out_len                   (fixed_out_len),
                 .out_addr                  (fixed_out_addr),
                 .new_burst                 (fixed_new_burst)
                );
            end
            if (IS_INCR_SLAVE) begin : incr_slave_converter_sel
                if (NO_WRAP_SUPPORT) begin : no_wrap_incr_slave_converter_sel
                    altera_incr_burst_converter
                    #(
                     .MAX_IN_LEN          (MAX_IN_LEN),
                     .MAX_OUT_LEN         (MAX_OUT_LEN),
                     .ADDR_WIDTH          (PKT_ADDR_W),
                     .BNDRY_WIDTH         (PKT_BURSTWRAP_W),
                     .BURSTSIZE_WIDTH     (PKT_BURST_SIZE_W),
                     .IN_NARROW_SIZE      (0), // not support narrow as this is INCR avalon slave
                     .NUM_SYMBOLS         (NUM_SYMBOLS),
                     .PURELY_INCR_AVL_SYS (INCR_AVALON_SYS)
                    )
                    the_converter_for_avalon_incr_slave
                    (
                     .clk                (clk),
                     .reset              (reset),
                     .enable             (enable_incr_converter),
                     .in_len             (d0_in_len),
                     .in_sop             (d0_in_sop),
                     .in_burstwrap_reg   (d1_in_burstwrap),
                     .in_size_t          (d0_in_size),
                     .in_size_reg        (d1_in_size),
                     .in_addr            (d0_in_aligned_addr),
                     .in_addr_reg        (d1_in_aligned_addr),
                     .is_write           (is_write),
                     .out_len            (incr_out_len),
                     .uncompr_out_len    (incr_uncompr_out_len),
                     .out_addr           (incr_out_addr),
                     .new_burst_export   (incr_new_burst)
                    );
  
                    // --------------------------------------------------
                    // The default converter
                    // --------------------------------------------------
                    altera_default_burst_converter
                    #(
                     .PKT_BURST_TYPE_W    (PKT_BURST_TYPE_W),
                     .PKT_ADDR_W          (PKT_ADDR_W),
                     .PKT_BURSTWRAP_W     (PKT_BURSTWRAP_W),
                     .PKT_BURST_SIZE_W    (PKT_BURST_SIZE_W),
                     .LEN_W               (IN_LEN_W),
                     .IS_AXI_SLAVE        (AXI_SLAVE)
                    )
                    the_default_burst_converter
                    (
                     .clk                       (clk),
                     .reset                     (reset),
                     .enable                    (enable_fixed_converter), // turn on if a fixed
                     .in_addr                   (d0_in_aligned_addr),
                     .in_addr_reg               (d1_in_aligned_addr),
                     .in_bursttype              (d0_in_bursttype),
                     .in_burstwrap_reg          (d1_in_burstwrap),
                     .in_burstwrap_value        (d0_in_burstwrap_value),
                     .in_len                    (d0_in_len),
                     .in_size_value             (d0_in_size_value),
                     .in_is_write               (is_write),
                     .out_len                   (fixed_out_len),
                     .out_addr                  (fixed_out_addr),
                     .new_burst                 (fixed_new_burst)
                    );
                end
                else begin : wrap_incr_slave_conveter_sel
                    altera_wrap_burst_converter
                    #(
                     .MAX_IN_LEN              (MAX_IN_LEN),
                     .MAX_OUT_LEN             (MAX_OUT_LEN),
                     .ADDR_WIDTH              (PKT_ADDR_W),
                     .BNDRY_WIDTH             (PKT_BURSTWRAP_W),
                     .NUM_SYMBOLS             (NUM_SYMBOLS),
                     .AXI_SLAVE               (AXI_SLAVE),
                     .OPTIMIZE_WRITE_BURST    (0)
                    )
                    the_converter_for_avalon_wrap_slave
                    (
                     .clk                               (clk),
                     .reset                             (reset),
                     .enable_read                       (enable_read_wrap_converter),
                     .enable_write                      (enable_write_wrap_converter),
                     .in_len                            (d0_in_len),
                     .first_len                         (d0_first_len),
                     .in_sop                            (d0_in_sop),
                     .in_burstwrap                      (d0_in_burstwrap),
                     .in_burstwrap_reg                  (d1_in_burstwrap),
                     .in_boundary                       (in_boundary),
                     .in_addr                           (d0_in_aligned_addr),
                     .in_addr_reg                       (d1_in_aligned_addr),
                     .out_len                           (wrap_out_len),
                     .uncompr_out_len                   (wrap_uncompr_out_len),
                     .out_addr                          (wrap_out_addr),
                     .new_burst_export                  (wrap_new_burst)
                    );

                    altera_incr_burst_converter
                    #(
                     .MAX_IN_LEN          (MAX_IN_LEN),
                     .MAX_OUT_LEN         (MAX_OUT_LEN),
                     .ADDR_WIDTH          (PKT_ADDR_W),
                     .BNDRY_WIDTH         (PKT_BURSTWRAP_W),
                     .BURSTSIZE_WIDTH     (PKT_BURST_SIZE_W),
                     .IN_NARROW_SIZE      (IN_NARROW_SIZE),
                     .NUM_SYMBOLS         (NUM_SYMBOLS),
                     .PURELY_INCR_AVL_SYS (INCR_AVALON_SYS)
                    )
                    the_converter_for_avalon_incr_slave
                    (
                     .clk                     (clk),
                     .reset                   (reset),
                     .enable                  (enable_incr_converter),
                     .in_len                  (d0_in_len),
                     .in_sop                  (d0_in_sop),
                     .in_burstwrap_reg        (d1_in_burstwrap),
                     .in_size_t               (d0_in_size),
                     .in_size_reg             (d1_in_size),
                     .in_addr                 (d0_in_aligned_addr),
                     .in_addr_reg             (d1_in_aligned_addr),
                     .is_write                (is_write),
                     .out_len                 (incr_out_len),
                     .uncompr_out_len         (incr_uncompr_out_len),
                     .out_addr                (incr_out_addr),
                     .new_burst_export        (incr_new_burst)
                    );
                    
                    // --------------------------------------------------
                    // The fixed burst converter module
                    // --------------------------------------------------
                    altera_default_burst_converter
                    #(
                     .PKT_BURST_TYPE_W    (PKT_BURST_TYPE_W),
                     .PKT_ADDR_W          (PKT_ADDR_W),
                     .PKT_BURSTWRAP_W     (PKT_BURSTWRAP_W),
                     .PKT_BURST_SIZE_W    (PKT_BURST_SIZE_W),
                     .LEN_W               (IN_LEN_W),
                     .IS_AXI_SLAVE        (AXI_SLAVE)
                    )
                    the_default_burst_converter
                    (
                     .clk                       (clk),
                     .reset                     (reset),
                     .enable                    (enable_fixed_converter), // turn on if a fixed
                     .in_addr                   (d0_in_aligned_addr),
                     .in_addr_reg               (d1_in_aligned_addr),
                     .in_bursttype              (d0_in_bursttype),
                     .in_burstwrap_reg          (d1_in_burstwrap),
                     .in_burstwrap_value        (d0_in_burstwrap_value),
                     .in_len                    (d0_in_len),
                     .in_size_value             (d0_in_size_value),
                     .in_is_write               (is_write),
                     .out_len                   (fixed_out_len),
                     .out_addr                  (fixed_out_addr),
                     .new_burst                 (fixed_new_burst)
                    );
                end
            end
        end
    endgenerate

    // --------------------------------------------------
    // 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

    // ---------------------------------------------------
    // Mapping of output signals.
    // ---------------------------------------------------
    wire load_next_output_pck  = source0_ready | !source0_valid;
    always_ff @(posedge clk or posedge reset) begin
        if (reset) begin
            uncompr_out_addr <= '0;
        end
        else if (load_next_output_pck) begin
            uncompr_out_addr <= d0_in_addr;
        end

    end

    // ---------------------------------------------------
    // Out burstype
    // ---------------------------------------------------
    // If AXI slave, out_bursttype = INCR if either of the following 2 conditions is met:
    //  1) in_passthru (i.e. the input burst count < 16).
    //  2) input packet has bursttype == REP_WRAP (Repeated Wrap).
    // Else, out_bursttype = in_bursttype.
    // For all other slaves, change the bursttype to INCR.
    wire [PKT_BURST_TYPE_W - 1 : 0] out_bursttype;
    generate
        if (AXI_SLAVE) begin : AXI_SLAVE_out_bursttype
            assign out_bursttype = (!d1_in_passthru || d1_in_bursttype == REP_WRAP) ? INCR : d1_in_bursttype;
        end
        else begin : others_slave_out_bursttype
           assign out_bursttype =  INCR;
        end
    endgenerate

    // At source0_startofpacket, out_addr_read is the in_addr.
    wire [PKT_ADDR_W - 1 : 0] out_addr_read;
    assign out_addr_read = source0_startofpacket_reg ? uncompr_out_addr : out_addr;

    // Choose between uncompressed or compressed trans address.
    wire [PKT_ADDR_W - 1 : 0] out_addr_assigned_to_packet;
    assign out_addr_assigned_to_packet = (d1_in_write || d1_in_uncompressed_read) ?  uncompr_out_addr : out_addr_read;

    // ---------------------------------------------------
    // Byteenable Generation.
    // Passthrough unless compressed transaction.
    // ---------------------------------------------------
    reg  [PKT_BYTEEN_W - 1 : 0 ]     out_byteen;
    reg  [ADDR_MASK_SEL - 1 : 0 ]    out_addr_masked;
    wire [511:0] initial_byteen = set_byteenable_based_on_size(d1_in_size); // To fix quartus integration error. Unused bits are expected to be synthesized away

    // Unaligned address changes.
    // 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_comb begin
        // Addresses from the converters (out_addr) are always aligned.
        out_addr_masked = out_addr[ADDR_MASK_SEL-1:0];
    end

    always_comb begin
    if (BYTEENABLE_SYNTHESIS == 1 && d1_in_narrow == 1 && (state == ST_COMP_TRANS))
        out_byteen     = initial_byteen[NUM_SYMBOLS-1:0] << out_addr_masked;
    else
        out_byteen  = d1_in_byteen;
    end
    // -- End of Byteenable Generation --

    always_comb begin : source0_out_assignments
        source0_data                                       = d1_in_data;
        source0_channel                                    = d1_in_channel;
        // Override fields the component is aware of.
        source0_data[PKT_BURST_TYPE_H : PKT_BURST_TYPE_L]  = out_bursttype;
        source0_data[PKT_BYTE_CNT_H   : PKT_BYTE_CNT_L  ]  = out_byte_cnt;
        source0_data[PKT_ADDR_H       : PKT_ADDR_L      ]  = out_addr_assigned_to_packet;
        source0_data[PKT_BYTEEN_H     : PKT_BYTEEN_L    ]  = out_byteen;
    end

    //----------------------------------------------------
    // "min" operation on burstwrap values is a bitwise AND.
    //----------------------------------------------------
    function [PKT_BURSTWRAP_W - 1 : 0] altera_merlin_burst_adapter_burstwrap_min;
        input [PKT_BURSTWRAP_W - 1 : 0] a, b;
        begin
            altera_merlin_burst_adapter_burstwrap_min  = a & b;
        end
    endfunction

    //----------------------------------------------------
    // AXSIZE encoding: run-time  size of the transaction.
    // ---------------------------------------------------
    function reg[511:0] set_byteenable_based_on_size;
        input [3:0] axsize;
        begin
            case (axsize)
                4'b0000: set_byteenable_based_on_size = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;
                4'b0001: set_byteenable_based_on_size = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003;
                4'b0010: set_byteenable_based_on_size = 512'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F;
                4'b0011: set_byteenable_based_on_size = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF;
                4'b0100: set_byteenable_based_on_size = 512'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF;
                4'b0101: set_byteenable_based_on_size = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFF;
                4'b0110: set_byteenable_based_on_size = 512'h0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFF;
                4'b0111: set_byteenable_based_on_size = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                4'b1000: set_byteenable_based_on_size = 512'h0000000000000000000000000000000000000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                4'b1001: set_byteenable_based_on_size = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
                default: set_byteenable_based_on_size = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;
            endcase
        end
    endfunction

endmodule

