module rle_encoder (
    input  wire       clk,
    input  wire       rst,
    input  wire       in_valid,
    input  wire [7:0] in_data,
    input  wire       in_last,
    output reg        out_valid,
    output reg [15:0] out_data,
    output reg        out_last
);
    reg       have_run;
    reg       pending_flush;
    reg [7:0] run_value;
    reg [7:0] run_count;

    always @(posedge clk) begin
        if (rst) begin
            have_run <= 1'b0;
            pending_flush <= 1'b0;
            run_value <= 8'h00;
            run_count <= 8'h00;
            out_valid <= 1'b0;
            out_data <= 16'h0000;
            out_last <= 1'b0;
        end else begin
            out_valid <= 1'b0;
            out_last <= 1'b0;

            if (pending_flush) begin
                out_valid <= 1'b1;
                out_data <= {run_count, run_value};
                out_last <= 1'b1;
                have_run <= 1'b0;
                pending_flush <= 1'b0;
                run_value <= 8'h00;
                run_count <= 8'h00;
            end else if (!have_run) begin
                if (in_valid) begin
                    if (in_last) begin
                        out_valid <= 1'b1;
                        out_data <= {8'd1, in_data};
                        out_last <= 1'b1;
                    end else begin
                        have_run <= 1'b1;
                        run_value <= in_data;
                        run_count <= 8'd1;
                    end
                end
            end else begin
                if (in_valid) begin
                    if (in_data == run_value) begin
                        if (run_count == 8'd254) begin
                            out_valid <= 1'b1;
                            out_data <= {8'd255, run_value};
                            out_last <= in_last;
                            have_run <= 1'b0;
                            pending_flush <= 1'b0;
                            run_value <= 8'h00;
                            run_count <= 8'h00;
                        end else if (in_last) begin
                            out_valid <= 1'b1;
                            out_data <= {run_count + 8'd1, run_value};
                            out_last <= 1'b1;
                            have_run <= 1'b0;
                            pending_flush <= 1'b0;
                            run_value <= 8'h00;
                            run_count <= 8'h00;
                        end else begin
                            run_count <= run_count + 8'd1;
                        end
                    end else begin
                        out_valid <= 1'b1;
                        out_data <= {run_count, run_value};
                        out_last <= 1'b0;
                        have_run <= 1'b1;
                        run_value <= in_data;
                        run_count <= 8'd1;
                        pending_flush <= in_last;
                    end
                end
            end
        end
    end
endmodule
