异步重置神秘地设置输出寄存器

Asynchronous reset mysteriously setting up output reg

我有以下代码:

module timer(
    input clk,
    input reset,
    output reg signal // <--- PROBLEMATIC SIGNAL
);

    always@(posedge clk or posedge reset)
    begin
    if(reset)
        signal <= 1;
    else
        signal <= 0;
    end
endmodule

和这个在 modelsim 上执行的测试平台:

`timescale 1ns / 1ps
`define PERIOD 20

module timer_tb;
    logic clk;
    logic reset;
    logic signal;

    timer inst(
        .clk(clk),
        .reset(reset),
        .signal(signal)
    );

    initial
    begin
        clk = 0;
        forever clk = #(`PERIOD/2) ~clk;
    end

    initial
    begin
        reset = 0; //<--- RESET STARTS CLEANED. 
        #(`PERIOD)
        reset = 1;
        #(`PERIOD)
        reset = 0;
        #(`PERIOD*3)
        reset = 1;
        #(`PERIOD)
        reset = 0;

        #(`PERIOD*3)
        $display("End of the simulation");
        $stop;
    end
endmodule

输出 reg signal 开始为 HIGH,但在代码中,此 reg 取决于 reset,而 reset 开始为 DOWN。我不明白为什么 signal 寄存器在模拟开始时为高电平,因为 reset 肯定开始向下。

我需要 signal 开始 DOWN 并且仅在 reset 转到 1 时设置(条件 posedge reset 就像我的代码一样)。

请查看 this print of the waveform 以便清楚地了解我的问题。

signal 没有初始值,所以它在时间 0 的值是未定义的。有的模拟器初始化为0,有的初始化为1,有的模拟器初始化为X。

使用初始块将 signal 初始化为 0。

module timer(
    input clk,
    input reset,
    output wire signal
);

    reg rsignal;
    assign signal = rsignal;

    initial begin
      rsignal = 1'b0;
    end

    always@(posedge clk or posedge reset)
    begin
    if(reset)
        rsignal <= 1;
    else
        rsignal <= 0;
    end
endmodule

reg 的默认值为 'x' 或未定义,wire 的默认值为 'Hi-Z' ,因此在这种情况下,您的输出(信号)是 reg 类型,因此模拟器采用相应的默认值,以获取默认值'0' SystemVerilog(IEEE1800-2012) 带有位数据类型,您可以尝试在输出中使用位,如下所示

 module timer(
    input clk,
    input reset,
    output bit signal 
);

    always@(posedge clk or posedge reset)
    begin
    if(reset)
        signal <= 1;
    else
        signal <= 0;
    end
endmodule

编辑:我不确定 quartus,但反过来你可以尝试通过这种方法在输出端将值初始化为 0 或 1,它应该在 Verilog 中工作

module timer(
    input clk,
    input reset,
    output reg signal=0
);

    always@(posedge clk or posedge reset)
    begin
    if(reset)
        signal <= 1;
    else
        signal <= 0;
    end
endmodule

您的波形有时钟到 q 延迟,但您的 RTL 模型没有任何延迟。这意味着您不是 运行 RTL 仿真。相反,您是 运行 综合门级模拟或从 FPGA 获取输出。

需要考虑的是,在测试台中,clkreset 以 X 而不是 0 开始。在时间为零时变为 0。 Verilog 允许并行进程的不确定顺序,无论其敏感度列表如何,都可以选择在时间为零时执行 always 块,并且用于比较的 X 评估为真。根据供应商如何实施模拟器,always 块可能首先执行。 reset being X 求值为真,将signal赋值为1。然后clkreset赋值为0。所有这些都发生在时间0,在波形中看不到.

这种允许的不可预测性是现实的无意片段。当您第一次给电路上电时,您最初得到的结果可能是不可预测的(这是由于工艺变化、物理布线、电源上升时的毛刺等)。您使用重置使设计进入已知状态。

如果你想阻止 clkreset 从 X 开始,然后将测试平台中的数据类型从 logic 更改为 bit (注意:bitlogic 是 SystemVerilog)。另一个应该有效的选项(不是 100% 保证)是在声明的同一行中初始化 clkreset

logic clk = 1'b0;
logic reset = 1'b0;

假设您是 运行 模拟,这应该可以工作。如果您 运行 在 FPGA 上,您无法保证这次通过更改测试平台实现零行为。

最干净的解决方案是从启用 reset 开始。您不应该关心在零时间重置之前的值是什么。