2. RAW图像数据打包模块

任务说明

本案例实现一个RAW Bayer图像数据打包模块,将传感器输出的RAW数据按指定格式(如RAW8/RAW10/RAW12)组织成字节流,供后续ISP流水线处理。模块需支持可配置的位宽转换与行缓冲输出,确保数据流格式与下游模块接口匹配。

核心实现

module raw_packer #(
    parameter int RAW_WIDTH    = 10,        // RAW数据位宽: 8/10/12
    parameter int PIX_PER_LINE = 128,       // 每行像素数
    parameter int LINES        = 64         // 总行数
)(
    input  logic                        clk,
    input  logic                        rst_n,
    // 输入: RAW像素流
    input  logic                        px_valid,
    input  logic [RAW_WIDTH-1:0]        px_data,
    // 输出: 打包字节流
    output logic                        out_valid,
    output logic [7:0]                  out_data,
    output logic                        out_eol,    // 行结束标志
    output logic                        out_eof     // 帧结束标志
);

    // 像素计数与行计数
    logic [15:0] px_cnt;
    logic [15:0] line_cnt;

    // 打包状态机
    typedef enum logic [1:0] {IDLE, PACK, DONE} state_t;
    state_t state;

    // 移位寄存器: 按位宽累积像素
    logic [23:0] shift_reg;
    logic [4:0]  bit_cnt;   // 已累积有效位数

    // 输出缓冲
    logic [7:0]  out_buf;
    logic        buf_valid;

    // 像素计数与行计数
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            px_cnt   <= 0;
            line_cnt <= 0;
        end else if (px_valid) begin
            if (px_cnt == PIX_PER_LINE-1) begin
                px_cnt   <= 0;
                line_cnt <= (line_cnt == LINES-1) ? 0 : line_cnt + 1;
            end else begin
                px_cnt <= px_cnt + 1;
            end
        end
    end

    // 打包逻辑: 将RAW_WIDTH位像素打包为8位字节流
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            shift_reg <= 0;
            bit_cnt   <= 0;
            out_buf   <= 0;
            buf_valid <= 0;
            state     <= IDLE;
        end else begin
            // 默认输出无效
            buf_valid <= 0;

            case (state)
                IDLE: begin
                    if (px_valid) begin
                        // 将像素移入移位寄存器
                        shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
                        bit_cnt   <= bit_cnt + RAW_WIDTH;
                        state     <= PACK;
                    end
                end

                PACK: begin
                    // 当累积位数≥8时输出字节
                    if (bit_cnt >= 8) begin
                        out_buf   <= shift_reg[bit_cnt-1 -: 8];
                        shift_reg <= shift_reg << 8;
                        bit_cnt   <= bit_cnt - 8;
                        buf_valid <= 1;
                        // 若还有像素且移位寄存器空间足够,继续接收
                        if (px_valid && bit_cnt + RAW_WIDTH <= 24) begin
                            shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
                            bit_cnt   <= bit_cnt + RAW_WIDTH;
                        end
                    end else if (px_valid) begin
                        // 不足8位且有新像素到达
                        shift_reg <= (shift_reg << RAW_WIDTH) | px_data;
                        bit_cnt   <= bit_cnt + RAW_WIDTH;
                    end

                    // 行结束处理
                    if (px_cnt == PIX_PER_LINE-1 && !px_valid) begin
                        // 行内像素已收完,清空剩余位(不足8位补零)
                        if (bit_cnt > 0) begin
                            out_buf   <= shift_reg << (8 - bit_cnt);
                            buf_valid <= 1;
                        end
                        state <= DONE;
                    end
                end

                DONE: begin
                    state <= IDLE;
                end
            endcase
        end
    end

    // 输出赋值
    assign out_valid = buf_valid;
    assign out_data  = out_buf;
    assign out_eol   = (px_cnt == PIX_PER_LINE-1) && buf_valid;
    assign out_eof   = (line_cnt == LINES-1) && (px_cnt == PIX_PER_LINE-1) && buf_valid;

endmodule

运行与验证

环境依赖:Verilog仿真工具(如Vivado XSim、ModelSim、Icarus Verilog)。

仿真测试平台:

module tb_raw_packer;
    logic clk = 0;
    logic rst_n = 0;
    logic px_valid = 0;
    logic [9:0] px_data;
    logic out_valid, out_eol, out_eof;
    logic [7:0] out_data;

    raw_packer #(.RAW_WIDTH(10), .PIX_PER_LINE(8), .LINES(2)) dut (
        .clk(clk), .rst_n(rst_n),
        .px_valid(px_valid), .px_data(px_data),
        .out_valid(out_valid), .out_data(out_data),
        .out_eol(out_eol), .out_eof(out_eof)
    );

    always #5 clk = ~clk;

    initial begin
        // 复位
        #20 rst_n = 1;
        // 输入2行,每行8个10bit像素: 值依次为0~7, 8~15
        for (int line = 0; line < 2; line++) begin
            for (int i = 0; i < 8; i++) begin
                @(posedge clk);
                px_valid = 1;
                px_data  = line*8 + i;
            end
            @(posedge clk);
            px_valid = 0;
        end
        #50 $finish;
    end

    // 监控输出
    always @(posedge clk) begin
        if (out_valid)
            $display("T=%0t out=%02h eol=%b eof=%b", $time, out_data, out_eol, out_eof);
    end
endmodule

验证方法:

  1. 运行仿真,观察输出字节流。
  2. 通过条件:对于RAW10格式,每4个像素(40bit)应打包为5个字节;行末不足8bit时补零输出。测试平台中每行8个10bit像素共80bit,应输出10字节。检查输出数据与输入像素按位拼接结果一致,且out_eol在行末字节处拉高,out_eof在末行末字节处拉高。

关键说明

  • 模块通过移位寄存器累积像素位,达到8bit即输出一个字节,实现任意RAW位宽到字节流的转换。
  • 行末不足8bit的残余数据左移补零输出,保证每行输出字节数为ceil(PIX_PER_LINE * RAW_WIDTH / 8)。
  • 参数RAW_WIDTH可配置为8/10/12,PIX_PER_LINE与LINES按实际传感器分辨率设置。