2012-07-26 27 views
5

如我所知,D触发器在时钟的每个正沿 处对其输入值进行采样。为什么我的D触发器不等待时钟的正边缘?

因此,它会产生1个周期的延迟。对?

但是,为什么我的D触发器不会产生1个周期的延迟?

  module flipflop(
      input clk, 
      input rstn, 
      input [7:0] i_data, 
      output reg [7:0] o_data 
     ); 

      always @(posedge clk) begin 
        if (~rstn) begin 
          o_data <= 0; 
        end 
        else begin 
          o_data <= i_data; 
        end 
      end 
     endmodule 

     module test; 
      reg clk; 
      reg [7:0] i_data; 
      reg rstn; 
      wire [7:0] o_data; 

      initial begin 
        clk = 0; 
        rstn = 1; 
        i_data = 0; 
        #20; 
        rstn = 0; 

        #30; 
        rstn = 1; 
        #20; 
        i_data = 8'hFA; 
        #20; 
        i_data = 8'hF0; 
        #20 
        i_data = 8'hF1; 
        #20 
        #10 $finish; 
      end 

      always #10 clk = !clk; 

      flipflop flipflop(
        .clk (clk), 
        .rstn(rstn), 
        .i_data(i_data), 
        .o_data(o_data) 
      ); 

      initial begin 
        $dumpfile("flipflop.vcd"); 
        $dumpvars(); 
      end 
     endmodule 

dff no delay

我的d触发器的功能,如在这里组合电路。

回答

5

该模拟器可能做这样的事情:

 initial begin 
       clk = 0; 
       rstn = 1; 
       i_data = 0; 
       #10; 
       clk = !clk; 
       #10; 
       rstn = 0; 
       clk = !clk; 

       #10; 
       clk = !clk; 
       #10; 
       clk = !clk; 
       #10; 
       rstn = 1; 
       clk = !clk; 
       #10; 
       clk = !clk; 
       #10 
       i_data = 8'hFA; //Input updated 
       clk = !clk;  //Clock event 
           //o_data assigned here 
       #10; 
       clk = !clk; 
       #10; 
       i_data = 8'hF0; 
       clk = !clk; 
       #20 
       i_data = 8'hF1; 
       #20 
       #10 $finish; 
     end 

由于时钟事件最后从每个时间段出现在您的测试平台,它看起来像翻牌正在分配。你可能希望你的测试平台不受时间限制,所以Marty建议使用@(posedge ...)来达到这个目的。你也可以简单地在一开始就延迟一次任务:

 initial begin 
       clk = 0; 
       #1; 
       rstn = 1; 
       i_data = 0; 
       #20; 
       rstn = 0; 

       #30; 
       rstn = 1; 
       #20; 
       i_data = 8'hFA; 
       #20; 
       i_data = 8'hF0; 
       #20 
       i_data = 8'hF1; 
       #20 
       #10 $finish; 
     end 
+0

这是阐明问题的好方法。 – Marty 2012-07-26 21:39:15

5

你已经运行了反对Verilog模拟器事件调度的微妙之处!更改数据分配以使用非阻塞分配可能是最简单的解决方法。

#20; 
i_data <= 8'hFA; 
#20; 
i_data <= 8'hF0; 
#20 
i_data <= 8'hF1; 
#20 

原始版本中发生的情况是,时钟和输入数据被安排在同一时间发生。由于模拟器一次只能做一件事,所以必须先决定它是否会改变时钟或数据。它首先改变了数据,所以当时钟边缘出现时,输入数据已经改变为下一个值,因此看起来数据正在通过FF滑动。

无阻塞分配(<=)计划在所有阻塞分配(=)完成后发生。因此,使数据分配非阻塞可确保它们在分块分配的时钟沿之后发生。

另一种方式来重写东西的工作将是:

initial begin 
    @(posedge clk) i_data = 8'hFA; 
    @(posedge clk) i_data = 8'hF0; 
    @(posedge clk) i_data = 8'hF1; 
end 
+0

马蒂,你能回顾一下你最后的建议吗?它认为它应该是@ @(posedge clk)i_data <= 8'hFA;'(非阻塞)。这样,在时钟更新后,我们有2 @(posedge clk)。两者都使用非阻塞赋值,因此无论执行顺序如何,结果都是相同的:触发器将注册一个旧值,并且'i_data'将被更新为新值。 但是,如果我们对'i_data'进行阻塞赋值并对'o_data'进行非阻塞,则输出将取决于仿真调度。在Cadence的irun上测试我得到了错误的结果,与OP最初的问题相同。 – RaZ 2018-01-07 13:14:54

相关问题