module jelly_linear_interpolation
        #(
            parameter   USER_WIDTH    = 0,
            parameter   RATE_WIDTH    = 4,
            parameter   COMPONENT_NUM = 3,
            parameter   DATA_WIDTH    = 8,
            parameter   DATA_SIGNED   = 1,
            parameter   ROUNDING      = 0,
            parameter   COMPACT       = 0,
            parameter   BLENDING      = 0,      // αブレンド用(rate のmaxを 1.0扱いする)
            
            // local
            parameter   USER_BITS     = USER_WIDTH > 0 ? USER_WIDTH : 1
        )
        (
            input   wire                                    reset,
            input   wire                                    clk,
            input   wire                                    cke,
            
            input   wire    [USER_BITS-1:0]                 s_user,
            input   wire    [RATE_WIDTH-1:0]                s_rate,
            input   wire    [COMPONENT_NUM*DATA_WIDTH-1:0]  s_data0,
            input   wire    [COMPONENT_NUM*DATA_WIDTH-1:0]  s_data1,
            input   wire                                    s_valid,
            
            output  wire    [USER_BITS-1:0]                 m_user,
            output  wire    [COMPONENT_NUM*DATA_WIDTH-1:0]  m_data,
            output  wire                                    m_valid
        );
    
    localparam      DATA_BITS       = COMPACT ? DATA_WIDTH : DATA_WIDTH + RATE_WIDTH;
    localparam      ROUNDING_OFFSET = !COMPACT && ROUNDING ? (1 << (RATE_WIDTH-1)) : 0;
    
    genvar          i;
    
    // パイプライン構成
    wire    [(RATE_WIDTH+1)*USER_BITS-1:0]                  pipeline_user;
    wire    [(RATE_WIDTH+1)*RATE_WIDTH-1:0]                 pipeline_rate;
    wire    [(RATE_WIDTH+1)*COMPONENT_NUM*DATA_BITS-1:0]    pipeline_data0;
    wire    [(RATE_WIDTH+1)*COMPONENT_NUM*DATA_BITS-1:0]    pipeline_data1;
    wire    [(RATE_WIDTH+1)-1:0]                            pipeline_valid;
    
    assign pipeline_user [USER_BITS-1:0]  = USER_WIDTH > 0 ? s_user : 1'bx;
    assign pipeline_rate [RATE_WIDTH-1:0] = s_rate;
    assign pipeline_valid[0]              = s_valid;
    
    // 符号拡張
    jelly_data_expand
            #(
                .NUM                (COMPONENT_NUM),
                .IN_DATA_WIDTH      (DATA_WIDTH),
                .OUT_DATA_WIDTH     (DATA_BITS),
                .DATA_SIGNED        (DATA_SIGNED),
                .OFFSET             (0),
                .RSHIFT             (0),
                .LSHIFT             (0)
            )
        i_data_expand_s0
            (
                .din                (s_data0),
                .dout               (pipeline_data0[COMPONENT_NUM*DATA_BITS-1:0])
            );
    
    jelly_data_expand
            #(
                .NUM                (COMPONENT_NUM),
                .IN_DATA_WIDTH      (DATA_WIDTH),
                .OUT_DATA_WIDTH     (DATA_BITS),
                .DATA_SIGNED        (DATA_SIGNED),
                .OFFSET             (0),
                .RSHIFT             (0),
                .LSHIFT             (0)
            )
        i_data_expand_s1
            (
                .din                (s_data1),
                .dout               (pipeline_data1[COMPONENT_NUM*DATA_BITS-1:0])
            );
    
    // パイプライン演算
    generate
    for ( i = 0; i < RATE_WIDTH; i = i+1 ) begin : loop_rate
        jelly_linear_interpolation_unit
                #(
                    .USER_WIDTH     (USER_BITS),
                    .RATE_WIDTH     (RATE_WIDTH),
                    .COMPONENT_NUM  (COMPONENT_NUM),
                    .DATA_WIDTH     (DATA_BITS),
                    .DATA_SIGNED    (DATA_SIGNED),
                    .COMPACT        (COMPACT),
                    .BLENDING       (BLENDING)
                )
            i_linear_interpolation_unit
                (
                    .reset          (reset),
                    .clk            (clk),
                    .cke            (cke),
                    
                    .s_user         (pipeline_user [i*USER_BITS               +: USER_BITS]),
                    .s_rate         (pipeline_rate [i*RATE_WIDTH              +: RATE_WIDTH]),
                    .s_data0        (pipeline_data0[i*COMPONENT_NUM*DATA_BITS +: COMPONENT_NUM*DATA_BITS]),
                    .s_data1        (pipeline_data1[i*COMPONENT_NUM*DATA_BITS +: COMPONENT_NUM*DATA_BITS]),
                    .s_valid        (pipeline_valid[i]),
                                     
                    .m_user         (pipeline_user [(i+1)*USER_BITS               +: USER_BITS]),
                    .m_rate         (pipeline_rate [(i+1)*RATE_WIDTH              +: RATE_WIDTH]),
                    .m_data0        (pipeline_data0[(i+1)*COMPONENT_NUM*DATA_BITS +: COMPONENT_NUM*DATA_BITS]),
                    .m_data1        (pipeline_data1[(i+1)*COMPONENT_NUM*DATA_BITS +: COMPONENT_NUM*DATA_BITS]),
                    .m_valid        (pipeline_valid[(i+1)])
                );
    end
    endgenerate
    
    // 丸め
    jelly_data_expand
            #(
                .NUM                (COMPONENT_NUM),
                .IN_DATA_WIDTH      (DATA_BITS),
                .OUT_DATA_WIDTH     (DATA_WIDTH),
                .DATA_SIGNED        (DATA_SIGNED),
                .OFFSET             (ROUNDING_OFFSET),
                .RSHIFT             (COMPACT ? 0 : RATE_WIDTH),
                .LSHIFT             (0)
            )
        i_data_expand_m
            (
                .din                (pipeline_data0[RATE_WIDTH*COMPONENT_NUM*DATA_BITS +: COMPONENT_NUM*DATA_BITS]),
                .dout               (m_data)
            );
    
    assign m_user  = USER_WIDTH > 0 ? pipeline_user [RATE_WIDTH*USER_BITS +: USER_BITS] : 1'bx;
    assign m_valid = pipeline_valid[RATE_WIDTH];
    
endmodule