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

为何Verilog 4位行波进位加法器输入非X却输出X?

4位行波进位加法器半加器always块未触发问题分析

尝试基于两个半加器构建全加器,进而搭建4位行波进位加法器。半加器和全加器单独测试正常,但级联为4位加法器后,测试时出现异常:当输入a=0、b=0、cin=0时,5ns时刻第二个全加器(f1)的第二个半加器(h1)输入均为0,但内部temp寄存器及输出仍为X,对应的always块未执行更新。

各模块代码如下:

半加器代码

module HA (input a, b,
    output reg cout,
    output reg sum);

    reg [1:0] temp;

    always @ (a or b) begin
        temp = a + b;
        #2 cout = temp[1];
        #1 sum = temp[0];
    end
endmodule

全加器代码

module FA(input a, b, cin,
    output cout, sum);
    wire c1, c2;
    wire s; 
    HA h0 (.a(a), .b(b), .cout(c1), .sum(s));
    HA h1 (.a(s), .b(cin), .cout(c2), .sum(sum));
    or o1 (cout, c1, c2);
endmodule

4位行波进位加法器代码

module PAdder(input [3:0] a,
        input [3:0] b,
        input cin,
        output [3:0] sum,
        output cout);

wire [2:0] c;
FA f0 (a[0], b[0], cin, c[0], sum[0]);
FA f1 (a[1], b[1], c[0], c[1], sum[1]);
FA f2 (a[2], b[2], c[1], c[2], sum[2]);
FA f3 (a[3], b[3], c[2], cout, sum[3]);

endmodule

测试平台代码

module PAddertb;
    reg [3:0] a;
    reg [3:0] b;
    reg cin;
    wire [3:0] sum;
    wire cout;
    integer i;

    PAdder p0(a, b, cin, sum, cout);
    
    initial begin
        
        $monitor("a=%d(%0b) b=%d(%0b) cin=%0b cout=%0b sum=%d(%0b)", a, a, b, b, cin, cout, sum, sum);
        for (i = 0; i < 1; i = i + 1) begin
            {a, b, cin} = i;
            #20;
        end
    end
endmodule

问题原因分析

  1. 带延迟的always块导致时序叠加与事件阻塞:
    半加器使用带固定延迟(#2、#1)的always块实现输出赋值,这种写法仅适用于单模块行为仿真,级联时会引发事件触发的时序冲突。以f1的h1为例:

    • 0ns时测试平台完成赋值,f1的h0输入触发always块,其输出s在1ns从X变为0,f0的进位c[0]在2ns从X变为0。
    • h1的always块在1ns(s变化)时第一次触发,此时c[0]仍为X,计算得到temp=0+X=X,随后进入延迟等待,直到4ns才完成本次always块执行。
    • 2ns时c[0]变为0,触发h1的always块新事件,但该事件会被当前正在执行的always块阻塞,需等到4ns后才会再次触发。因此在5ns时刻,第二次always块执行尚未完成temp的赋值,导致temp和输出仍为X。
  2. reg类型输出的初始值问题:
    半加器的cout、sum及内部temp均为reg类型,初始值默认是X。若always块未及时触发更新,这些寄存器会保持X状态,直到触发完成赋值。

解决方案

将半加器改为连续赋值的组合逻辑实现,避免使用带延迟的always块,这样输入变化时输出会立即更新,不会出现事件阻塞和时序延迟问题:

module HA (input a, b,
    output cout,
    output sum);

    // 用连续赋值实现半加器逻辑,无延迟
    assign sum = a ^ b;       // 异或实现和
    assign cout = a & b;      // 与实现进位
endmodule

这种写法符合组合逻辑的Verilog规范,级联时不会出现时序冲突,能保证输入稳定后输出及时更新,彻底解决X值问题。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 16:24:53