порядок выполнения начального блока в verilog - PullRequest
0 голосов
/ 30 сентября 2018

Я сделал модуль счетчика, и я не могу понять порядок выполнения начального блока для модуля счетчика и модуля testbench.

Насколько я знаю, я думал в verilog, Первоначальный блок всегда будет выполняться первым.

В этом случае я буду выполнять модуль testbench, и я предполагаю, что блок initial для testbench_counter будет выполнен первым.

Далее, я думал, что модуль счетчика C будет выполнен и значение для x_in будет обновлено до temp без необходимости задержки #1 в модуле C.

Но без #1 или без initial на always@(x_in) Я вижу красная линия .

Так что вопрос

  1. будет ли initial блок для модуля счетчика C выполняться первым даже перед блоком initial для тестового стенда?

  2. Почему это работает, если я использую always@(x_in)?

Заранее спасибо.

Код для счетчика

`timescale 1ns/1ns
module counter(x_in,clk,y_out);
    input [31:0] x_in;
    input clk;
    output [31:0] y_out;
    reg [31:0] y_out;
    reg [31:0] temp;

    initial begin
        #1 temp=x_in;
    end

    always@(posedge clk) begin
        temp<=temp+1;   
        y_out<=temp;
    end
endmodule

код для испытательного стенда

`timescale 1ns/1ns

module testbench_conter();
    wire [31:0]y_out;
    wire [31:0]temp;
    reg [31:0]x_in;
    reg clk;

    counter C(x_in,clk,y_out);

    always begin
        #5 clk=~clk;
    end

    initial begin
        clk=1'b0; 
        x_in=32'd0;
        #0
        #10000
        $stop;
    end
endmodule

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Отвечая на ваш вопрос 1: между initial блоками абсолютно гарантированный порядок выполнения.Verilog симуляция запускает их в произвольном непредсказуемом порядке.Единственный способ синхронизации - это #delays и другие операторы wait и delay.

Verilog гарантирует, что выполнение любого процедурного блока (который включает в себя начальные и всегда блоки) остановится в состоянии ожидания, пока не будет удовлетворено.

Verilog также гарантирует, что все начальные блоки начинаются до любого всегда блока.

Любой сигнал, указанный в блоке всегдасписок чувствительности играет роль оператора 'delay', заставляя блок Always ждать, пока не изменится какое-либо значение сигнала.Это продолжит выполнение блока позже.

Итак, отвечая на ваш второй вопрос, always@(x_in) будет ожидать изменения значения сигнала.

так, в вашем случае:

 initial begin    << will start execution at time '0' before any always block
    clk=1'b0;     << change value of clk from 'x' -> '1' 
    x_in=32'd0;   << change value of x_in 'x' -> '0'
    #0            << makes absolutely no sense here. It is a special statement
    #10000        << pauses execution for 10000 time units
    $stop;        << stopps execution
end

, в то время как вышеуказанный начальный блок дает, остальные блоки начинают выполнение.

initial begin     << starts execution at time 0, befor or after the block above
    #1 temp=x_in; << pauses for 1 time unit, then assigns temp
end 

Вышеприведенное присваивание происходит, когда первый начальный блок ожидает # 10000.

, если вы используете блок Always

always @(x_in)
   temp = x_in;

, он будет выполнять assignemt при изменении x_inи первый начальный блок начинает ждать.Этот блок всегда будет выполняться в том же цикле «0», когда сигнал будет изменен.Это отличается от # 1, который вы использовали.В ваших случаях изменение произойдет в цикле «1».

0 голосов
/ 30 сентября 2018

Далее, я думал, что модуль счетчика C будет выполнен ...

Основной недостаток вашего мышления заключается в том, что начальная инструкция в счетчике выполняется, когда счетчик "выполняется".».Это не вариант. Все начальные операторы запускаются при запуске программы и только один раз.Таким образом, ваши два начальных утверждения формируют состояние гонки.

Используя # 1 или always@(x_in), вы задерживаете присваивание `temp1 до тех пор, пока не определен x_in.

Гораздо лучше было бы добавить сигнал 'load' к вашему счетчику, который поднимаетзначение x_in при активации.

Также ваш y_out задерживается на другой тактовый цикл.

Обычно загружаемый счетчик будет выглядеть так:

always@(posedge clk)
begin
   if (load)
      y_out <= x_in;
   else
      y_out <= y_out + 1;   
end
...