You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Verilog 3x3图像模糊模块可综合性、正确性及赋值规则咨询

Verilog图像模糊模块的综合性、测试用例与赋值疑问解答

我是软件开发出身,编写了一个通过3x3像素滑动窗口计算平均值实现光栅图像模糊的Verilog模块。输入图像为按行从下到上(类似位图)存储的RGB像素字节流,模块在时钟上升沿选择并输出3x3窗口的平均值,时钟下降沿移动窗口,处理完成后拉高DONE信号。

目前仅使用Icarus Verilog测试代码,不确定测试用例是否正确,也不清楚代码是否具备可综合性,希望得到相关反馈。同时对何时/为何使用阻塞赋值(=)与非阻塞赋值(<=)存在疑问,虽了解=用于组合逻辑、<=用于时序逻辑,但不确定何时该使用组合逻辑或时序逻辑。

附上我的Verilog代码:

module blur
    #(parameter
        WIDTH  = 640,   // Image width
        HEIGHT  = 426,   // Image height
        INPUTBYTES = WIDTH*HEIGHT*3
    )
    (
      input CLK,          // clock     
      input RST,         // Reset (active low)
      input wire [7 : 0] input_memory [0 : INPUTBYTES-1],// memory to store  8-bit data image
      output reg [7 : 0] output_memory [0 : INPUTBYTES-1],// memory to store  8-bit data image
      output wire DONE     // Done flag
    );

    integer row = 0; // row index of the image
    integer col = 0; // col index of the image
    integer counter = 0;

    reg [7:0]  DATA_R = 0;  // 8 bit Red data
    reg [7:0]  DATA_G = 0;  // 8 bit Green data
    reg [7:0]  DATA_B = 0;  // 8 bit Blue data

    assign DONE = (counter > INPUTBYTES-1);

    always@(negedge CLK) begin

        if (col == WIDTH-3) begin
            col <= 0;
            row <= row+1;
        end
        else begin
            col <= col+1;
        end

        counter <= counter+3;
    end


    always@(posedge CLK) begin
        integer i;
        integer j;

        // Sum up all the R, G, B values of the 3x3 square
        for(i=0; i<3; i=i+1) begin
            for(j=0; j<3; j=j+1) begin
                DATA_R = DATA_R + input_memory[3*(WIDTH*(row+i)+(col+j))+0];
                DATA_G = DATA_G + input_memory[3*(WIDTH*(row+i)+(col+j))+1];
                DATA_B = DATA_B + input_memory[3*(WIDTH*(row+i)+(col+j))+2];
            end
        end

        // Output is the averaged RGB values
        output_memory[counter+0] = DATA_R/9;
        output_memory[counter+1] = DATA_G/9;
        output_memory[counter+2] = DATA_B/9;
    end
endmodule

一、代码可综合性问题

  • 数组端口兼容性:多数FPGA综合工具不支持将多维数组(input_memory、output_memory)直接作为模块端口,这类结构通常需要替换为单端口RAM接口(地址线+数据线),或者用扁平总线配合地址控制实现,否则会触发综合报错。
  • 缺失复位逻辑:row、col、counter这些integer变量没有复位分支,复位时无法回到初始值,会导致综合后的电路出现未知状态,必须在时钟触发的always块中添加RST分支来初始化这些变量。
  • 双时钟沿触发风险:同时使用上升沿和下降沿触发always块,虽然语法合法,但会大幅增加布线难度,且多数FPGA厂商不推荐这种设计,容易引发时序违规。建议统一使用上升沿触发,将窗口移动逻辑整合到同一个always块中。
  • 累加变量未清零:上升沿块中DATA_R/G/B的累加操作未在每次计算前清零,会导致每次时钟沿都累积之前的计算值,最终输出完全错误。必须在循环累加前将DATA_R/G/B重置为0。
  • 循环变量兼容性:always块内的integer i,j属于自动变量,部分老版本综合工具可能不兼容,建议声明为reg类型,或者直接展开3x3的加法(因为循环次数固定,硬编码更稳定)。
  • 除法资源优化:/9整数除法会让综合工具生成除法器,占用大量逻辑资源。可以用近似计算替代,比如乘以118后右移10位(1/9≈0.1111,118/1024≈0.115,误差极小),或者用查找表实现除法,减少资源消耗。

二、测试用例建议

  • 小尺寸图像验证:用3x3的极小图像测试,比如输入所有像素RGB均为255,预期输出也为255;或者输入梯度图像,手动计算模糊结果后对比模块输出,快速验证计算逻辑正确性。
  • 边界场景测试:重点测试图像边缘(row=0、row=HEIGHT-3、col=0、col=WIDTH-3),确保窗口不会越界访问input_memory(当前代码未做边界判断,边缘像素需直接输出原像素或做边缘扩展处理)。
  • 复位功能验证:在测试中触发RST信号,确认row、col、counter回到初始值,DONE信号同步拉低。
  • DONE信号验证:当counter达到INPUTBYTES时,确认DONE信号拉高,且模块不再输出新数据。

三、阻塞/非阻塞赋值使用场景

  • 非阻塞赋值(<=):专门用于时序逻辑,也就是需要将值存储到触发器(寄存器)的场景。比如时钟沿触发的always块中,更新row、col、counter这类状态寄存器,或者向output_memory写入数据。非阻塞赋值会在时钟沿完成后更新值,避免竞争条件,保证时序逻辑的正确性。
  • 阻塞赋值(=):用于组合逻辑,也就是不需要存储,仅根据输入实时计算输出的场景。比如组合逻辑always块(@*触发)中的中间值计算,或者时序逻辑块内的临时变量(如循环累加的中间值、临时地址计算)。注意:同一时序always块内不要混合使用阻塞和非阻塞赋值,否则极易引发时序错误。
  • 你的代码中的问题:
    • 上升沿块中DATA_R = DATA_R + ...的阻塞赋值本身没问题,但必须在累加前清零DATA_R/G/B,否则会累积历史值;
    • 下降沿块中使用非阻塞赋值是正确的,但建议将窗口移动逻辑整合到上升沿块,避免双沿触发的风险。

内容的提问来源于stack exchange,提问作者chris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 09:10:36