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

Verilog定点加减法器负零异常问题排查求助

定点加法器负零问题的排查与修复

首先,咱们先明确核心问题:你遇到的**负零(-0)**是因为手动处理符号位和绝对值时,相等情况的逻辑覆盖不够严谨,或者说虽然代码里有处理,但可能在某些场景下没触发(比如你测试的1-1场景)。咱们一步步拆解:

问题根源分析

你的代码采用手动分离符号位和绝对值的方式实现定点加减,但在处理符号不同的两个数时,仅用了>和else分支,把相等的情况归到了else里。虽然你在else里加了if (res[N-2:0] == 0) res[N-1] = 0;来避免负零,但可能存在仿真工具的位宽匹配问题,或者逻辑分支的优先级导致判断没生效。

另外,代码里的注释有误导性(比如subtracts a-b实际是计算a + b,因为b是负数),这也容易让自己调试时混淆逻辑。

修复方案

方案1:优化手动逻辑,明确处理相等场景

把绝对值相等的情况单独拎出来处理,避免依赖else分支里的后续判断,这样逻辑更清晰,也能确保负零被彻底消除:

`timescale 1ns/1ps
module adder #(
    parameter Q = 27,
    parameter N = 32
) (
    input [N-1:0] a,
    input [N-1:0] b,
    output [N-1:0] c
);
reg [N-1:0] res;
assign c = res;

// 用@*代替@(a,b),自动包含所有敏感信号,更安全
always @* begin
    if(a[N-1] == b[N-1]) begin
        // 同符号:绝对值相加,符号不变
        res[N-2:0] = a[N-2:0] + b[N-2:0];
        res[N-1] = a[N-1];
    end
    else if(a[N-1] == 0 && b[N-1] == 1) begin
        // 正+负 = 正 - |负|
        if( a[N-2:0] > b[N-2:0] ) begin
            res[N-2:0] = a[N-2:0] - b[N-2:0];
            res[N-1] = 0;
        end
        else if( a[N-2:0] == b[N-2:0] ) begin
            // 绝对值相等,结果为0
            res = {1'b0, {N-1{1'b0}}};
        end
        else begin
            res[N-2:0] = b[N-2:0] - a[N-2:0];
            res[N-1] = 1;
        end
    end
    else begin
        // 负+正 = |正| - |负|
        if( a[N-2:0] > b[N-2:0] ) begin
            res[N-2:0] = a[N-2:0] - b[N-2:0];
            res[N-1] = 1;
        end
        else if( a[N-2:0] == b[N-2:0] ) begin
            res = {1'b0, {N-1{1'b0}}};
        end
        else begin
            res[N-2:0] = b[N-2:0] - a[N-2:0];
            res[N-1] = 0;
        end
    end
end
endmodule

方案2:利用Verilogsigned类型简化实现

手动处理符号位很容易出错,Verilog支持带符号数运算,直接用signed类型让工具自动处理2's补码运算,不仅代码简洁,还从根源上避免负零(2's补码中没有负零,全0就是唯一的0):

`timescale 1ns/1ps
module adder #(
    parameter Q = 27,
    parameter N = 32
) (
    input  signed [N-1:0] a,
    input  signed [N-1:0] b,
    output signed [N-1:0] c
);
    // 直接用带符号数加法,工具自动处理所有符号场景
    assign c = a + b;
endmodule

对应的测试平台也要把信号声明为signed,方便直观赋值和观察:

`timescale 1ns/1ps
module tb_adder ();
reg clk;
reg signed [31:0] a;
reg signed [31:0] b;
wire signed [31:0] c;

adder adder_i (
    .a(a),
    .b(b),
    .c(c)
);

parameter CLKPERIODE = 100;
initial clk = 1'b1;
always #(CLKPERIODE/2) clk = !clk;

initial begin
    $monitor ("a=%0d, b=%0d, result=%0d", a/(2**27), b/(2**27), c/(2**27));
    #1 a = 32'sh08000000; // +1.0(Q=27,2^27对应1.0)
    b = 32'shF8000000; // -1.0
    #(CLKPERIODE) $finish();
end
endmodule

调试建议

  1. 添加更详细的监控:在测试平台里打印a、b的十进制值(转换为定点数的实际数值,比如除以2^Q),方便直观判断运算是否正确,而不是只看十六进制。
  2. 覆盖更多测试场景:测试正+正、负+负、正+负(正绝对值大、负绝对值大、绝对值相等)、负+正的所有情况,确保逻辑全覆盖。
  3. 仿真时观察信号波形:用波形工具查看a、b的符号位和绝对值,以及res的每一位变化,定位哪一步逻辑不符合预期。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:57:07