4. 单通道3x3卷积计算单元

任务目标

实现一个单通道3x3卷积计算单元,对输入的3x3图像窗口与3x3卷积核执行乘累加运算,输出单个像素的卷积结果。本案例聚焦于卷积运算的核心计算逻辑,不涉及图像缓存、行缓冲或滑动窗口控制。

接口定义

信号方向位宽说明
clkinput1时钟
rst_ninput1异步复位,低有效
window_datainput9×8=723x3窗口像素,按行优先排列,每像素8bit无符号
kernel_datainput9×8=723x3卷积核系数,按行优先排列,每系数8bit有符号(补码)
valid_ininput1输入有效标志
pixel_outoutput16卷积结果,有符号补码
valid_outoutput1输出有效标志,延迟1拍

核心实现

采用两级流水线:第一级完成9个像素与系数的并行乘法,第二级将9个部分积相加得到最终结果。像素为无符号8bit,系数为有符号8bit,乘积为有符号16bit,9个乘积累加后最大位宽为16+4=20bit,但实际输出截断为16bit有符号数。

module conv3x3_single_channel (
    input               clk,
    input               rst_n,
    input  [71:0]       window_data,  // 9×8bit,行优先
    input  [71:0]       kernel_data,  // 9×8bit,有符号系数
    input               valid_in,
    output reg [15:0]   pixel_out,
    output reg          valid_out
);

    // 拆分输入为9个独立像素和系数
    wire [7:0] w [0:8];
    wire [7:0] k [0:8];
    genvar i;
    generate
        for (i = 0; i < 9; i = i + 1) begin : split_io
            assign w[i] = window_data[i*8 +: 8];
            assign k[i] = kernel_data[i*8 +: 8];
        end
    endgenerate

    // 第一级:乘法
    reg signed [15:0] mul_result [0:8];
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            for (int j = 0; j < 9; j = j + 1)
                mul_result[j] <= 16'sd0;
        end else if (valid_in) begin
            for (int j = 0; j < 9; j = j + 1)
                mul_result[j] <= $signed({1'b0, w[j]}) * $signed(k[j]);
        end
    end

    // 第二级:累加
    reg signed [19:0] sum_result;
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            sum_result <= 20'sd0;
            valid_out <= 1'b0;
        end else begin
            sum_result <= mul_result[0] + mul_result[1] + mul_result[2] +
                          mul_result[3] + mul_result[4] + mul_result[5] +
                          mul_result[6] + mul_result[7] + mul_result[8];
            valid_out <= valid_in;
        end
    end

    // 输出截断为16bit有符号
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n)
            pixel_out <= 16'sd0;
        else
            pixel_out <= sum_result[15:0];
    end

endmodule

运行与验证

Testbench要点:构造一个已知窗口和卷积核,手动计算期望结果,对比模块输出。

// 示例:3x3窗口全为1,卷积核全为1,期望结果=9
// 窗口数据:72'h01_01_01_01_01_01_01_01_01
// 核数据:  72'h01_01_01_01_01_01_01_01_01
// 期望输出:16'sd9

仿真步骤:

  1. 使用Vivado/ModelSim/Verilator等工具编译conv3x3_single_channel.v和对应testbench;
  2. 拉高valid_in一个周期,输入上述窗口和核数据;
  3. 观察valid_out拉高时pixel_out的值。

通过条件:valid_out为高时,pixel_out等于16'sd9。可进一步用随机窗口和核数据,在testbench中计算期望值并自动比对,若所有测试向量均匹配则验证通过。

注意事项

  • 像素按无符号处理,在乘法前扩展1位0符号位;卷积核按有符号补码处理,支持负系数;
  • 输出截断为16bit,若累加结果超出16bit范围会发生溢出,实际应用中需根据数据范围调整输出位宽或增加饱和处理;
  • 流水线延迟为2个时钟周期(乘法1拍+累加1拍),valid_out与pixel_out同步对齐。