【问题标题】:Verilog: Why the register synchroinized the input data in the same clock cycle?Verilog:为什么寄存器在同一个时钟周期内同步输入数据?
【发布时间】:2021-07-30 13:27:05
【问题描述】:

我正在创建一个简单的寄存器来缓冲输入数据。输入数据和寄存器都是由clk同步的。

always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        reg1 <= 0;
    end
    else begin
        reg1 <= in1;
    end
end

预计 reg1 的值应该等于前一个 clk 周期的 in1。例如

cc     0    1     2     3     4

in1    00   01    02    03   ...

reg1   00   00    01    02   ...

在仿真中,结果显示reg1在每个时钟周期都等于in1

cc     0    1     2     3     4

in1    00   01    02    03   ...

reg1   00   01    02    03   ...

这是什么原因?如何修改代码或测试台以生成预期结果?

这里给出了最小的、可重现的例子

//buffer.v
module buffer(
    input
          clk,
          rst_n,
          [7:0] in1,
    output reg
          [7:0] out1
);
always  @(posedge clk or negedge rst_n)begin
    if(rst_n==1'b0)begin
        out1 <= 0;
    end
    else begin
        out1 <= in1;
    end
end
endmodule

//buffer_tb.v
`timescale 1 ns/10 ps

module buffer_tb;

reg clk,rst_n;
reg [7:0] in1;
wire [7:0] out1;

localparam period = 20;
buffer bf0(
      .clk  ( clk    ),
      .rst_n( rst_n  ),
      .in1  ( in1    ),
      .out1 ( out1   )
);

//clk,rst_n generation
initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    #20  //
    rst_n = 1'b1;
end
always #10 clk = ~clk;

//Data generation
always @(posedge clk)
begin
    in1 = 8'd0;
    #period
    in1 = 8'd1;
    #period
    in1 = 8'd2;
    #period
    in1 = 8'd3;
    #period
    in1 = 8'd0;
end

endmodule

# run.do
# Fortsätt köra trots rapporterade fel:
set BreakOnAssertion 3

# Definiera design (både entity och filer):
set design buffer

# Kompilera koden:
vlib work
vlog -93 ${design}.v
vlog -93 ${design}_tb.v

# Ladda in koden i simulatorn:
vsim -voptargs=+acc ${design}_tb

add wave -position insertpoint  \\
sim:/buffer_tb/clk \\
sim:/buffer_tb/in1 \\
sim:/buffer_tb/out1

# Kör tills det inte finns något kvar att simulera:
run 160ns

# Zooma wave-fönstret så att allt syns:
wave zoom full

【问题讨论】:

    标签: verilog


    【解决方案1】:

    主要问题是您在 posedge 时钟的同一时间戳上对 in1 使用阻塞分配 (=)。

    首选的解决方案是在in1 上使用非阻塞赋值(&lt;=)。这会将更新后的值推迟到in1,以便在时钟边沿对其更新前的值进行采样。

    由于您有时钟,我建议在时钟事件上更新in1,而不是匹配周期的# 延迟。如果数字不完全匹配,或者存在舍入误差,或者开始对时钟抖动/频率变化进行建模,或者使用 PLL 等。那么您的计时事件将不会对齐并且可能开始漂移到样本点错过了。相反,最好将时钟事件用作主要延迟。

    你应该改变这个:

    always @(posedge clk)
    begin
        in1 = 8'd0;
        #period
        in1 = 8'd1;
        #period
        in1 = 8'd2;
        #period
        in1 = 8'd3;
        #period
        in1 = 8'd0;
    end
    

    到这个(或类似的):

    initial begin
      repeat(4) begin
        @(posedge clk)  in1 <= 8'd0;
        @(posedge clk)  in1 <= 8'd1;
        @(posedge clk)  in1 <= 8'd2;
        @(posedge clk)  in1 <= 8'd3;
        @(posedge clk)  in1 <= 8'd0;
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-24
      • 1970-01-01
      • 2017-02-23
      • 2016-12-31
      • 1970-01-01
      • 1970-01-01
      • 2020-04-29
      • 1970-01-01
      相关资源
      最近更新 更多