5

正如我所知,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 没有延迟

我的 D 触发器在这里就像一个组合电路。

4

2 回答 2

6

您遇到了 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
于 2012-07-26T15:47:23.613 回答
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
于 2012-07-26T20:51:27.020 回答