Процедурные блоки языка Verilog
Модели поведения описываются внутри процедурных блоков, но есть исключение:
- initial : выполняются только в начальный момент времени симуляции.
- always : выполняются в бесконечном цикле [буквально "всегда"].
Мы рассмотрим их подробно в дальнейшем.
Пример - initial
Verilog Code:
module initial_example(); reg clk,reset,enable,data; initial begin clk = 0; reset = 0; enable = 0; data = 0; end endmodule
В примере выше, блоки initial и always начинают выполняться в момент времени 0. Блок always ожидает события положительного фронта тактового сигнала, а блок initial ничего не ожидает, выполняясь однократно в начальный момент.
Пример - always
Verilog Code:
module always_example(); reg clk,reset,enable,q_in,data; always @ (posedge clk) if (reset) begin data <= 0; end else if (enable) begin data <= q_in; end endmodule
В блоке always, при наступлении триггерного события, выполняется код внутри begin ... end и затем этот блок ожидает очередного события переднего фронта тактового сигнала. Процесс ожидания и выполнения продолжается все время, до конца симуляции.
Присваивание в процедурных блоках
- В процедурах присваивание производится регистровым типам, целым или вещественным числам, или переменной времени. Не допускается присваивание "проводниковым" типам данных, например wire.
- Можно присваивать регистрам значения типа wire, постоянных, других регистров или указывать отдельные значения.
Пример неверное присваивание
Verilog Code:
module initial_bad(); reg clk,reset; wire enable,data; initial begin clk = 0; reset = 0; enable = 0; data = 0; end endmodule
Пример правильное присваивание
Verilog Code:
module initial_good(); reg clk,reset,enable,data; initial begin clk = 0; reset = 0; enable = 0; data = 0; end endmodule
Группы присваивания в процедурах
Если процедурный блок содержит более одной инструкции, их можно заключить в блоки:
- Последовательный begin − end.
- Параллельный fork − join.
При использовании begin−end, можно задать имя. Такие блоки являются именованными.
Пример begin - end
Verilog Code:
module initial_begin_end(); reg clk,reset,enable,data; initial begin $monitor("%g clk=%b reset=%b enable=%b data=%b", $time, clk, reset, enable, data); #1 clk = 0; #10 reset = 0; #5 enable = 0; #3 data = 0; #1 $finish; end endmodule
Begin: clk = 0 когда time = 1, reset = 0 через интервал 11 единиц времени, enable = 0 через 16 единиц времени, data через 19 единиц. Все инструкции выполняются последовательно.
Вывод симулятора
Code:
0 clk=x reset=x enable=x data=x 1 clk=0 reset=x enable=x data=x 11 clk=0 reset=0 enable=x data=x 16 clk=0 reset=0 enable=0 data=x 19 clk=0 reset=0 enable=0 data=0
Пример fork - join
Verilog Code:
module initial_fork_join(); reg clk,reset,enable,data; initial begin $monitor("%g clk=%b reset=%b enable=%b data=%b", $time, clk, reset, enable, data); fork #1 clk = 0; #10 reset = 0; #5 enable = 0; #3 data = 0; join #1 $display ("%g Terminating simulation", $time); $finish; end endmodule
Fork: clk получает значение через 1 ед. времени, reset через 10, enable через 5, data через 3 с момента старта. Все инструкции выполняются параллельно.
Последовательные группы инструкций
Ключевые слова begin − end:
- Группируют вместе несколько инструкций.
- Предписывают последовательное выполнение (по одной инструкции).
- Любой тайминг в пределах группы относится к предыдущей инструкции.
- Задержки последовательно накапливаются (суммируются)
- Блок завершается его последней инструкцией.
Пример sequential
Verilog Code:
module sequential(); reg a; initial begin $monitor ("%g a = %b", $time, a); #10 a = 0; #11 a = 1; #12 a = 0; #13 a = 1; #14 $finish; end endmodule
Вывод симулятора
Code:
0 a = x 10 a = 0 21 a = 1 33 a = 0 46 a = 1
Параллельные группы инструкций
Ключевые слова fork − join:
- Группируют вместе несколько инструкций.
- Предписывают паралльное выполнение (всех одновременно).
- Тайминг в параллельных группах для всех инструкций привязан к началу времени блока.
- Блок завершается после выполнения последней по времени инструкции (инструкция с наибольшей задержкой, даже если она первая в блоке).
Пример parallel
Verilog Code:
module parallel(); reg a; initial fork $monitor ("%g a = %b", $time, a); #10 a = 0; #11 a = 1; #12 a = 0; #13 a = 1; #14 $finish; join endmodule
Вывод симулятора
Code:
0 a = x 10 a = 0 11 a = 1 12 a = 0 13 a = 1
Пример − begin−end и fork − join
Verilog Code:
module fork_join(); reg clk,reset,enable,data; initial begin $display ("Starting simulation"); $monitor("%g clk=%b reset=%b enable=%b data=%b", $time, clk, reset, enable, data); fork : FORK_VAL #1 clk = 0; #5 reset = 0; #5 enable = 0; #2 data = 0; join #10 $display ("%g Terminating simulation", $time); $finish; end endmodule
Вывод симулятора
Code:
0 clk=x reset=x enable=x data=x 1 clk=0 reset=x enable=x data=x 2 clk=0 reset=x enable=x data=0 5 clk=0 reset=0 enable=0 data=0 15 Terminating simulation
Блокирующие и неблокирующие присваивания
Блокирующие присваивания выполняются в том порядке, в каком записан их код. Таким образом, это последовательные присваивания. Поскольку они блокируют выполнение очередной инструкции на время выполнения текущей, они называются блокирующими. Присваивания записываются при помощи символа "=". Пример: a = b;
Неблокирующие присваивания выполняются параллельно. Поскольку блокирования следующей инструкции во время выполнения текущей не происходит, они называются неблокирующими. Это присваивание записывается при помощи символа "<=". Пример: a <= b;
Пример − блокирующие и неблокирующие инструкции
Verilog Code:
module blocking_nonblocking(); reg a,b,c,d; // Blocking Assignment initial begin #10 a = 0; #11 a = 1; #12 a = 0; #13 a = 1; end initial begin #10 b <= 0; #11 b <= 1; #12 b <= 0; #13 b <= 1; end initial begin c = #10 0; c = #11 1; c = #12 0; c = #13 1; end initial begin d <= #10 0; d <= #11 1; d <= #12 0; d <= #13 1; end initial begin $monitor("TIME = %g A = %b B = %b C = %b D = %b",$time, a, b, c, d); #50 $finish; end endmodule
Вывод симулятора
Code:
TIME = 0 A = x B = x C = x D = x TIME = 10 A = 0 B = 0 C = 0 D = 0 TIME = 11 A = 0 B = 0 C = 0 D = 1 TIME = 12 A = 0 B = 0 C = 0 D = 0 TIME = 13 A = 0 B = 0 C = 0 D = 1 TIME = 21 A = 1 B = 1 C = 1 D = 1 TIME = 33 A = 0 B = 0 C = 0 D = 1 TIME = 46 A = 1 B = 1 C = 1 D = 1
Изображения сигналов к примеру выше
Операторы assign и deassign
Процедурные операторы назначения и отмены назначения позволяют помещать непрерывные назначения в регистры на контролируемые периоды времени. Процедурный оператор assign отменяет процедурные назначения регистру. Процедурный оператор deassign завершает непрерывное присвоение регистру.
Пример − assign и deassign
Verilog Code:
module assign_deassign (); reg clk,rst,d,preset; wire q; initial begin $monitor("@%g clk %b rst %b preset %b d %b q %b", $time, clk, rst, preset, d, q); clk = 0; rst = 0; d = 0; preset = 0; #10 rst = 1; #10 rst = 0; repeat (10) begin @ (posedge clk); d <= $random; @ (negedge clk) ; preset <= ~preset; end #1 $finish; end // Clock generator always #1 clk = ~clk; // assign and deassign q of flip flop module always @(preset) if (preset) begin assign U.q = 1; // assign procedural statement end else begin deassign U.q; // deassign procedural statement end d_ff U (clk,rst,d,q); endmodule // D Flip-Flop model module d_ff (clk,rst,d,q); input clk,rst,d; output q; reg q; always @ (posedge clk) if (rst) begin q <= 0; end else begin q <= d; end endmodule
Вывод симулятора
Code:
@0 clk 0 rst 0 preset 0 d 0 q x @1 clk 1 rst 0 preset 0 d 0 q 0 @2 clk 0 rst 0 preset 0 d 0 q 0 @3 clk 1 rst 0 preset 0 d 0 q 0 @4 clk 0 rst 0 preset 0 d 0 q 0 @5 clk 1 rst 0 preset 0 d 0 q 0 @6 clk 0 rst 0 preset 0 d 0 q 0 @7 clk 1 rst 0 preset 0 d 0 q 0 @8 clk 0 rst 0 preset 0 d 0 q 0 @9 clk 1 rst 0 preset 0 d 0 q 0 @10 clk 0 rst 1 preset 0 d 0 q 0 @11 clk 1 rst 1 preset 0 d 0 q 0 @12 clk 0 rst 1 preset 0 d 0 q 0 @13 clk 1 rst 1 preset 0 d 0 q 0 @14 clk 0 rst 1 preset 0 d 0 q 0 @15 clk 1 rst 1 preset 0 d 0 q 0 @16 clk 0 rst 1 preset 0 d 0 q 0 @17 clk 1 rst 1 preset 0 d 0 q 0 @18 clk 0 rst 1 preset 0 d 0 q 0 @19 clk 1 rst 1 preset 0 d 0 q 0 @20 clk 0 rst 0 preset 0 d 0 q 0 @21 clk 1 rst 0 preset 0 d 0 q 0 @22 clk 0 rst 0 preset 1 d 0 q 1 @23 clk 1 rst 0 preset 1 d 1 q 1 @24 clk 0 rst 0 preset 0 d 1 q 1 @25 clk 1 rst 0 preset 0 d 1 q 1 @26 clk 0 rst 0 preset 1 d 1 q 1 @27 clk 1 rst 0 preset 1 d 1 q 1 @28 clk 0 rst 0 preset 0 d 1 q 1 @29 clk 1 rst 0 preset 0 d 1 q 1 @30 clk 0 rst 0 preset 1 d 1 q 1 @31 clk 1 rst 0 preset 1 d 1 q 1 @32 clk 0 rst 0 preset 0 d 1 q 1 @33 clk 1 rst 0 preset 0 d 1 q 1 @34 clk 0 rst 0 preset 1 d 1 q 1 @35 clk 1 rst 0 preset 1 d 0 q 1 @36 clk 0 rst 0 preset 0 d 0 q 1 @37 clk 1 rst 0 preset 0 d 1 q 0 @38 clk 0 rst 0 preset 1 d 1 q 1 @39 clk 1 rst 0 preset 1 d 1 q 1 @40 clk 0 rst 0 preset 0 d 1 q 1
Операторы force и release
Другая форма процедурного непрерывного присвоения обеспечивается процедурными заявлениями о принуждении и освобождении. Эти операторы имеют аналогичный эффект для пары assign-deassign, но принудительное действие может быть применено как к цепям, так и к регистрам.
Можно использовать force и release при моделировании на вентильном уровне, чтобы обойти проблемы со сбросом соединения. Также можно использовать вставку одиночных и двойных битовых ошибок в данные, считанные из памяти.
Пример − force и release
Verilog Code:
module force_release (); reg clk,rst,d,preset; wire q; initial begin $monitor("@%g clk %b rst %b preset %b d %b q %b", $time, clk, rst, preset, d, q); clk = 0; rst = 0; d = 0; preset = 0; #10 rst = 1; #10 rst = 0; repeat (10) begin @ (posedge clk); d <= $random; @ (negedge clk) ; preset <= ~preset; end #1 $finish; end // Clock generator always #1 clk = ~clk; // force and release of flip flop module always @(preset) if (preset) begin force U.q = preset; // force procedural statement end else begin release U.q; // release procedural statement end d_ff U (clk,rst,d,q); endmodule // D Flip-Flop model module d_ff (clk,rst,d,q); input clk,rst,d; output q; wire q; reg q_reg; assign q = q_reg; always @ (posedge clk) if (rst) begin q_reg <= 0; end else begin q_reg <= d; end endmodule
Вывод симулятора
Code:
@0 clk 0 rst 0 preset 0 d 0 q x @1 clk 1 rst 0 preset 0 d 0 q 0 @2 clk 0 rst 0 preset 0 d 0 q 0 @3 clk 1 rst 0 preset 0 d 0 q 0 @4 clk 0 rst 0 preset 0 d 0 q 0 @5 clk 1 rst 0 preset 0 d 0 q 0 @6 clk 0 rst 0 preset 0 d 0 q 0 @7 clk 1 rst 0 preset 0 d 0 q 0 @8 clk 0 rst 0 preset 0 d 0 q 0 @9 clk 1 rst 0 preset 0 d 0 q 0 @10 clk 0 rst 1 preset 0 d 0 q 0 @11 clk 1 rst 1 preset 0 d 0 q 0 @12 clk 0 rst 1 preset 0 d 0 q 0 @13 clk 1 rst 1 preset 0 d 0 q 0 @14 clk 0 rst 1 preset 0 d 0 q 0 @15 clk 1 rst 1 preset 0 d 0 q 0 @16 clk 0 rst 1 preset 0 d 0 q 0 @17 clk 1 rst 1 preset 0 d 0 q 0 @18 clk 0 rst 1 preset 0 d 0 q 0 @19 clk 1 rst 1 preset 0 d 0 q 0 @20 clk 0 rst 0 preset 0 d 0 q 0 @21 clk 1 rst 0 preset 0 d 0 q 0 @22 clk 0 rst 0 preset 1 d 0 q 1 @23 clk 1 rst 0 preset 1 d 1 q 1 @24 clk 0 rst 0 preset 0 d 1 q 0 @25 clk 1 rst 0 preset 0 d 1 q 1 @26 clk 0 rst 0 preset 1 d 1 q 1 @27 clk 1 rst 0 preset 1 d 1 q 1 @28 clk 0 rst 0 preset 0 d 1 q 1 @29 clk 1 rst 0 preset 0 d 1 q 1 @30 clk 0 rst 0 preset 1 d 1 q 1 @31 clk 1 rst 0 preset 1 d 1 q 1 @32 clk 0 rst 0 preset 0 d 1 q 1 @33 clk 1 rst 0 preset 0 d 1 q 1 @34 clk 0 rst 0 preset 1 d 1 q 1 @35 clk 1 rst 0 preset 1 d 0 q 1 @36 clk 0 rst 0 preset 0 d 0 q 1 @37 clk 1 rst 0 preset 0 d 1 q 0 @38 clk 0 rst 0 preset 1 d 1 q 1 @39 clk 1 rst 0 preset 1 d 1 q 1 @40 clk 0 rst 0 preset 0 d 1 q 1