为什么我的D触发器不等待时钟的正边缘?

时间:2012-07-26 15:01:36

标签: verilog

据我所知,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触发器就像这里的组合电路一样。

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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