module jelly_img_line_buf_unit
        #(
            parameter   N          = 1,
            parameter   USER_WIDTH = 0,
            parameter   DATA_WIDTH = 8,
            parameter   ADDR_WIDTH = 10,
            parameter   MEM_SIZE   = (1 << ADDR_WIDTH),
            parameter   RAM_TYPE   = "block",
            
            parameter   USER_BITS  = USER_WIDTH > 0 ? USER_WIDTH : 1
        )
        (
            input   wire                                reset,
            input   wire                                clk,
            input   wire                                cke,
            
            input   wire    [N-1:0]                     s_line_first,
            input   wire    [N-1:0]                     s_line_last,
            input   wire                                s_pixel_first,
            input   wire                                s_pixel_last,
            input   wire    [N-1:0]                     s_de,
            input   wire    [N*USER_BITS-1:0]           s_user,
            input   wire    [N*DATA_WIDTH-1:0]          s_data,
            input   wire    [ADDR_WIDTH-1:0]            s_addr,
            input   wire                                s_valid,
            
            output  wire    [N-1:0]                     m_line_first,
            output  wire    [N-1:0]                     m_line_last,
            output  wire                                m_pixel_first,
            output  wire                                m_pixel_last,
            output  wire    [N-1:0]                     m_de,
            output  wire    [N*USER_BITS-1:0]           m_user,
            output  wire    [N*DATA_WIDTH-1:0]          m_data,
            output  wire    [ADDR_WIDTH-1:0]            m_addr,
            output  wire                                m_valid
        );
    
    
    // -------------------------------------
    //  line buffer meory
    // -------------------------------------
    
    // data
    wire                                    mem_we;
    wire    [ADDR_WIDTH-1:0]                mem_addr;
    wire    [USER_WIDTH+DATA_WIDTH-1:0]     mem_wdata;
    wire    [USER_WIDTH+DATA_WIDTH-1:0]     mem_rdata;
    
    jelly_ram_singleport
            #(
                .ADDR_WIDTH     (ADDR_WIDTH),
                .DATA_WIDTH     (USER_WIDTH+DATA_WIDTH),
                .MEM_SIZE       (MEM_SIZE),
                .RAM_TYPE       (RAM_TYPE),
                .DOUT_REGS      (1),
                .MODE           ("READ_FIRST")
            )
        i_ram_singleport
            (
                .clk            (clk),
                .en             (cke),
                .regcke         (cke),
                .we             (mem_we),
                .addr           (mem_addr),
                .din            (mem_wdata),
                .dout           (mem_rdata)
            );
    
    assign mem_we    = s_de[0];
    assign mem_addr  = s_addr;
    assign mem_wdata = {s_user[USER_BITS-1:0], s_data[DATA_WIDTH-1:0]};
    
    wire    [USER_BITS-1:0]     mem_read_user;
    wire    [DATA_WIDTH-1:0]    mem_read_data;
    assign {mem_read_user, mem_read_data} = mem_rdata;
    
    
    // -------------------------------------
    //  pixel pipeline
    // -------------------------------------
    
    reg     [N-2:0]                 st0_line_first;
    reg     [N-2:0]                 st0_line_last;
    reg     [N-2:0]                 st0_pixel_first;
    reg     [N-2:0]                 st0_pixel_last;
    reg     [N-2:0]                 st0_de;
    reg     [(N-1)*USER_BITS-1:0]   st0_user;
    reg     [(N-1)*DATA_WIDTH-1:0]  st0_data;
    reg     [ADDR_WIDTH-1:0]        st0_addr;
    reg                             st0_valid;
    
    reg     [N-2:0]                 st1_line_first;
    reg     [N-2:0]                 st1_line_last;
    reg     [N-2:0]                 st1_pixel_first;
    reg     [N-2:0]                 st1_pixel_last;
    reg     [N-2:0]                 st1_de;
    reg     [(N-1)*USER_BITS-1:0]   st1_user;
    reg     [(N-1)*DATA_WIDTH-1:0]  st1_data;
    reg     [ADDR_WIDTH-1:0]        st1_addr;
    reg                             st1_valid;
    
    always @(posedge clk) begin
        if ( reset ) begin
            st0_line_first  <= {(N-1){1'bx}};
            st0_line_last   <= {(N-1){1'bx}};
            st0_pixel_first <= 1'bx;
            st0_pixel_last  <= 1'bx;
            st0_de          <= {(N-1){1'bx}};
            st0_user        <= {((N-1)*USER_BITS){1'bx}};
            st0_data        <= {((N-1)*DATA_WIDTH){1'bx}};
            st0_addr        <= {ADDR_WIDTH{1'bx}};
            st0_valid       <= 1'b0;
            
            st1_line_first  <= {(N-1){1'bx}};
            st1_line_last   <= {(N-1){1'bx}};
            st1_pixel_first <= 1'bx;
            st1_pixel_last  <= 1'bx;
            st1_de          <= {(N-1){1'bx}};
            st1_user        <= {((N-1)*USER_BITS){1'bx}};
            st1_data        <= {((N-1)*DATA_WIDTH){1'bx}};
            st1_addr        <= {ADDR_WIDTH{1'bx}};
            st1_valid       <= 1'b0;
        end
        if ( cke ) begin
            st0_line_first  <= s_line_first;
            st0_line_last   <= s_line_last;
            st0_de          <= s_de;
            st0_pixel_first <= s_pixel_first;
            st0_pixel_last  <= s_pixel_last;
            st0_user        <= s_user;
            st0_data        <= s_data;
            st0_addr        <= s_addr;
            st0_valid       <= s_valid;
            
            st1_line_first  <= st0_line_first;
            st1_line_last   <= st0_line_last;
            st1_pixel_first <= st0_pixel_first;
            st1_pixel_last  <= st0_pixel_last;
            st1_de          <= st0_de;
            st1_user        <= st0_user;
            st1_data        <= st0_data;
            st1_addr        <= st0_addr;
            st1_valid       <= st0_valid;
        end
    end
    
    reg                         mem_line_first;
    reg                         mem_line_last;
    reg                         mem_de;
    always @(posedge clk) begin
        if ( reset ) begin
            mem_line_first <= 1'b0;
            mem_line_last  <= 1'b0;
            mem_de         <= 1'b0;
        end
        if ( cke ) begin
            if ( st1_valid && st1_pixel_last[0] ) begin
                mem_line_first <= st1_line_first[0];
                mem_line_last  <= st1_line_last[0];
                mem_de         <= st1_de[0];
            end
        end
    end
    
    assign m_line_first  = {st1_line_first, mem_line_first};
    assign m_line_last   = {st1_line_last , mem_line_last };
    assign m_pixel_first = st1_pixel_first;
    assign m_pixel_last  = st1_pixel_last;
    assign m_de          = {st1_de,         mem_de        };
    assign m_user        = {st1_user,       mem_read_user };
    assign m_data        = {st1_data,       mem_read_data };
    assign m_addr        = st1_addr;
    assign m_valid       = st1_valid;
    
//  assign m_line_first  = {mem_line_first, st1_line_first};
//  assign m_line_last   = {mem_line_last , st1_line_last };
//  assign m_pixel_first = st1_pixel_first;
//  assign m_pixel_last  = st1_pixel_last;
//  assign m_de          = {mem_de,         st1_de        };
//  assign m_user        = {mem_read_user,  st1_user      };
//  assign m_data        = {mem_read_data,  st1_data      };
//  assign m_addr        = st1_addr;
//  assign m_valid       = st1_valid;
    
endmodule