Verilog - путаница с неблокирующими заявлениями - PullRequest
0 голосов
/ 30 августа 2018

Я всегда думал, что с неблокирующими операторами все они происходят параллельно в конце блока Always.

Но рассмотрим пример, который я нашел:

https://www.nandland.com/articles/blocking-nonblocking-verilog.html

always @(posedge i_clock)
begin
  r_Test_1 <= 1'b1;
  r_Test_2 <= r_Test_1;
  r_Test_3 <= r_Test_2;
end

Это говорит о том, что «Блок всегда в коде Verilog выше использует Назначение неблокирования, что означает, что потребуется 1 3 такта для распространения значения 1 от r_Test_1 к r_Test_3.»

Это не имеет никакого смысла. Если для распространения значения требуется 3 такта, то, конечно же, это происходит последовательно, а не параллельно?

1 Ответ

0 голосов
/ 30 августа 2018

Неблокирующие операторы выполняются параллельно каждый раз, когда выполняется блок Always. Однако каждое назначение использует предыдущее значение правой стороны при назначении. Если мы смоделируем дизайн, мы увидим это поведение:

enter image description here

Первоначально все сигналы имеют значение 0, однако на первом переднем фронте r_Test_1 принимает значение 1, в то время как два других регистра остаются равными 0. Это потому, что r_Test_2 присвоено значение r_Test_1 только перед фронтом тактового сигнала, а r_Test_1 равно 0 непосредственно перед нарастающим фронтом.

Подобное поведение происходит на втором переднем фронте, на этот раз с r_Test_2 и r_Test_3. r_Test_2 становится 1 на втором переднем фронте, потому что на этот раз r_Test_1 имел значение 1 непосредственно перед фронтом часов, а потому что r_Test_2 был все еще 0 перед этим фронтом, r_Test_3 остается 0.

Давайте сопоставим это с поведением этого кода:

always @(posedge i_clock)
begin
    r_Test_1 = 1'b1;
    r_Test_2 = r_Test_1;
    r_Test_3 = r_Test_2;
end

enter image description here

Поскольку я использовал здесь блокирующие назначения, каждому регистру присваивается значение немедленно, а не назначение откладывается до конца блока Always. Из-за этого, когда присваивается r_Test_2, r_Test_1 уже имеет значение 1, а также с r_Test_3 и r_Test_2, поэтому все 3 сигнала принимают значение 1 в первом цикле.

Теперь, когда я использую блокирующие назначения, порядок стал важным. Поэтому, если я переставлю код так, чтобы он выглядел так:

always @(posedge i_clock)
begin
    r_Test_1 = 1'b1;
    r_Test_3 = r_Test_2;
    r_Test_2 = r_Test_1;
end

Затем я получаю другой результат из второго моделирования: enter image description here

Задача: почему это так?

Полный тестовый стенд:

`timescale 1ns/1ps
module test;
    reg i_clock = 0;

    reg r_Test_1 = 0;
    reg r_Test_2 = 0;
    reg r_Test_3 = 0;

    initial begin
        $dumpfile("dump.vcd");
        $dumpvars;
        #100 $finish;
    end

    always #5 i_clock <= ~i_clock;

    always @(posedge i_clock)
    begin
        r_Test_1 <= 1'b1;
        r_Test_2 <= r_Test_1;
        r_Test_3 <= r_Test_2;
    end
endmodule
...