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

SystemVerilog电梯控制器Testbench编译正常但GTKWave波形显示异常的问题求助

解决电梯控制器仿真波形异常与逻辑问题

嘿,我来帮你一步步排查这个问题——先搞定GTKWave里的波形显示异常,再修复控制器代码里的隐藏逻辑错误:

一、Testbench导致的波形异常问题

1. x0信号的“周期性”假象

看你Testbench的initial块最后一行:

x0=1; x0=0; #10;

这两个赋值是在同一时间步执行的,x0会直接被覆盖成0,相当于这行代码根本没产生有效的x0脉冲。另外,你所有的输入信号变化都是在时钟半周期时触发(#10),而时钟周期是20ns,这会导致输入变化和时钟边沿不同步,在GTKWave里看起来就像是“周期性”异常,但本质是Testbench的赋值时机不对。

给你改个更合理的Testbench输入部分:

initial begin
    $dumpfile("ascx.vcd");
    $dumpvars(0, tst_ascx); // 明确dump顶层所有信号
    reset=1; x0=0; x1=0; x2=0; #20; // 等一个完整时钟周期再释放复位
    reset=0; #20;
    x0=1; #20; // 每个状态保持一个完整时钟周期,对齐时钟边沿
    x0=0; x1=1; #20;
    x1=0; x2=1; #20;
    x2=0; x0=1; #20;
    x0=0; x2=1; #20;
    x2=0; x1=1; #20;
    x1=0; x0=1; #20; // 单独的x0脉冲,持续一个周期
    x0=0; #20;
    $finish; // 主动结束仿真
end

这样每个输入信号的变化都对齐时钟边沿,每个状态保持一个完整周期,GTKWave里就能看到清晰的单脉冲或持续状态,不会再出现奇怪的周期性。

2. 时钟波形显示问题

你写的时钟生成代码本身是对的:

always begin
    clk=0; #10; clk=1; #10;
end

如果GTKWave里显示异常,大概率是显示缩放的问题——试试用滚轮放大波形,直到能看到完整的高低电平切换;另外检查$dumpvars是否包含了clk信号,我上面改的代码里用$dumpvars(0, tst_ascx)能确保顶层所有信号都被dump,包括clk。

二、电梯控制器模块的致命逻辑错误(即使波形正常也会功能异常)

你的控制器代码有两个严重问题,这才是仿真结果不符合预期的核心原因:

1. 过程块里用assign是非法操作

在always @(*)过程块里,你用了assign y = fermo;这种连续赋值语句,这在SystemVerilog里是绝对不允许的。过程块内部应该用阻塞赋值(=)或者非阻塞赋值(<=),assign是用于过程块外的连续赋值的。编译器可能没报错,但仿真器会产生完全不可预测的行为。

赶紧把所有assign y = ...改成直接赋值,还要把多个if改成else if,避免多个条件同时满足时后面的赋值覆盖前面的:

always @(*) begin
    case(pianoatt)
        pianoterra: begin
            if(x0) y = fermo;
            else if(x1) y = sale;
            else if(x2) y = sale2;
            else y = fermo; // 处理无输入的情况
        end
        primopiano: begin
            if(x0) y = scende;
            else if(x1) y = fermo;
            else if(x2) y = sale;
            else y = fermo;
        end
        secondopiano: begin
            if(x0) y = scende2;
            else if(x1) y = scende;
            else if(x2) y = fermo;
            else y = fermo;
        end
        default: y = fermo;
    endcase
end

2. pianoprox的赋值逻辑完全不符合电梯运行逻辑

当前的always_comb块里,pianoprox的优先级是x1 > x0 > x2——意思是不管当前在哪个楼层,只要x1被按下,就直接去一楼(primopiano),这显然不对(比如在二楼时按下x0,应该直接去一楼,而不是先绕去一楼)。而且这个逻辑完全没考虑当前楼层和目标楼层的关系,也没处理多个按钮同时按下的场景。

给你一个简化的修正版本,你可以根据需求再调整:

always_comb begin
    pianoprox = pianoatt; // 默认停在当前楼层
    // 优先响应目标楼层的呼叫,这里简化为直接响应按下的按钮
    if(x0) begin
        pianoprox = pianoterra;
    end else if(x2) begin
        pianoprox = secondopiano;
    end else if(x1 && pianoatt != primopiano) begin
        pianoprox = primopiano;
    end
    // 你可以改成更复杂的逻辑,比如同方向优先、最近楼层优先等
end

3. 枚举类型定义的小问题

你把motore枚举定义在了模块外面,这会变成全局可见的类型,建议移到模块内部,或者用typedef封装:

module ascx (input logic x0, x1, x2, clk, reset, output logic [4:0] y);
    typedef enum logic [4:0] {fermo, sale, sale2, scende, scende2} motore_t;
    typedef enum logic [1:0] {pianoterra, primopiano, secondopiano} piani_t;
    piani_t pianoatt, pianoprox;
    // 剩余代码...
endmodule

这样更符合模块化编程的规范。

三、验证步骤

  1. 先修正Testbench的输入逻辑,重新编译仿真,检查GTKWave里的clk和x0等信号是否显示正常。
  2. 修复控制器里的assign语句问题,再仿真,看看y信号是否能正确响应输入和当前楼层。
  3. 调整pianoprox的赋值逻辑,逐步验证每个场景(比如一楼→二楼、二楼→一楼、中间楼层呼叫等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 06:42:32