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

Verilog 4位并行输入极值检测代码仿真异常问题排查

分析你的Verilog代码问题:峰峰值检测仿真异常

嘿,我来帮你拆解这段代码里的几个关键问题,这些正是导致你仿真时pk_low始终为0、pk_high和pp_voltage处于未知态(X)的原因:

1. 组合逻辑错误使用非阻塞赋值(<=)

你在always @(*)这个组合逻辑块里,给pk_low和pk_high用了非阻塞赋值<=——这是Verilog开发里的典型错误!

非阻塞赋值<=是专门用于时序逻辑(带时钟沿触发的always块)的,它会在时钟沿到来后才完成赋值更新;而组合逻辑块里必须用阻塞赋值=,否则会导致信号更新延迟、竞争,甚至始终保持初始的未知态或错误值。你的pk_high一直是X,很大程度上就是这个原因导致的。

修改后的组合逻辑块应该是这样:

always @(*) begin
    case (state)
        st0: begin
            pk_low = pk_low;
            pk_high = pk_high;
        end
        st1: begin
            pk_low = pk_low;
            pk_high = parallel_in;
        end
        st2: begin
            pk_low = parallel_in;
            pk_high = pk_high;
        end
    endcase
end

2. 初始化方式的问题(仿真与硬件实现的差异)

你用initial块来初始化state、pk_high和pk_low,这里存在两个致命问题:

  • 仿真启动时,parallel_in的初始值通常是未知态(X),所以pk_high <= parallel_in;和pk_low <= parallel_in;会直接把这两个寄存器初始化为X,后续的比较逻辑自然全部出错。
  • 在实际FPGA硬件中,initial块的行为是不确定的(多数FPGA不支持用initial初始化寄存器,或需要特殊工具配置),正确的做法是用复位信号(比如同步复位)来完成初始化。

建议添加复位端口,改用时钟沿触发的块做初始化:

module peak_voltage (clk, rst_n, parallel_in, pk_high, pk_low, pp_voltage);
    input clk;
    input rst_n; // 低电平复位
    input wire [3:0] parallel_in;
    output reg [3:0] pk_high;
    output reg [3:0] pk_low;
    output wire [3:0] pp_voltage;
    reg state;
    parameter st0 = 'd0;
    parameter st1 = 'd1;
    parameter st2 = 'd2;

    always @ (posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            state <= st0;
            pk_high <= parallel_in; // 复位时用当前输入初始化,也可固定为4'hF/4'h0
            pk_low <= parallel_in;
        end else begin
            if (parallel_in > pk_high)begin
                state <= st1;
            end else if (parallel_in < pk_low) begin
                state <= st2;
            end else begin
                state <= st0;
            end
        end
    end

    // 组合逻辑用阻塞赋值
    always @(*) begin
        case (state)
            st0: begin
                pk_low = pk_low;
                pk_high = pk_high;
            end
            st1: begin
                pk_low = pk_low;
                pk_high = parallel_in;
            end
            st2: begin
                pk_low = parallel_in;
                pk_high = pk_high;
            end
        endcase
    end

    assign pp_voltage = pk_high - pk_low;
endmodule

如果想让仿真初始值不是X,可以在测试台里给parallel_in设置初始值,比如initial parallel_in = 4'h0;。

3. 状态机逻辑的冗余与优化空间

你的状态机把“更新最大值”“更新最小值”“保持不变”拆成了三个状态,其实完全可以去掉状态机,直接在时钟沿的时序块里完成最值更新,逻辑更简洁,也避免了组合逻辑的潜在问题:

always @ (posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        pk_high <= parallel_in;
        pk_low <= parallel_in;
    end else begin
        if (parallel_in > pk_high) begin
            pk_high <= parallel_in;
        end
        if (parallel_in < pk_low) begin
            pk_low <= parallel_in;
        end
        // 输入既不是新最大值也不是新最小值时,保持原值
    end
end

这种方式直接在时序逻辑里完成更新,符合Verilog最佳实践,出错概率更低。

4. 关于pk_low始终为0的猜测

如果你的仿真中parallel_in初始值是0,且后续输入都是4位无符号数(范围0-15),那么parallel_in < pk_low的条件永远不成立,state不会走到st2,pk_low就会一直保持初始的0。但只要修复了组合逻辑的赋值问题,后续如果有更小的输入(当然4位无符号数最小就是0),逻辑就能正常响应。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:06:36