Почему мой D-флип-флоп не ждет положительного перевеса часов?

Как я знаю, D flipflop производит выборку своего входного значения на каждом положительном фронте тактовой частоты.

Таким образом, будет произведена задержка в 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

без задержки

Мой D-триггер здесь работает как комбинационная схема.

2 ответа

Решение

Симулятор, вероятно, делает что-то вроде этого:

       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

Поскольку событие часов происходит последним на каждом шаге по времени от вашего стенда, похоже, что флоп назначается немедленно. Вероятно, вы хотите, чтобы ваш тестовый стенд был полностью подчинен, поэтому предложение Марти об использовании @(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

Вы столкнулись с тонкостями планирования событий симулятора 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
Другие вопросы по тегам