Управление процедурными блоками
Процедурные блоки активируются в начальный момент симуляции. Выполнением процедур управляют перепады сигналов.
Verilog Code:
module dlatch_using_always(); reg q; reg d, enable; always @ (d or enable) if (enable) begin q = d; end initial begin $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q); #1 enable = 0; #1 d = 1; #1 enable = 1; #1 d = 0; #1 d = 1; #1 d = 0; #1 enable = 0; #10 $finish; end endmodule
Задержка в начале процедуры, любое изменение d или enable позволяет инструкциям процедуры выполняться. Процедура реагирует на любое изменение d или enable.
Вывод симулятора
Code:
ENABLE = x D = x Q = x ENABLE = 0 D = x Q = x ENABLE = 0 D = 1 Q = x ENABLE = 1 D = 1 Q = 1 ENABLE = 1 D = 0 Q = 0 ENABLE = 1 D = 1 Q = 1 ENABLE = 1 D = 0 Q = 0 ENABLE = 0 D = 0 Q = 0
Комбинационная логика в процедурах
Для моделирования комбинационных схем, процедурные блоки должны быть чувствительны к любым изменениям на входах. Существует важное правило, которому необходимо следовать при моделировании комбнационной логики. Если используются условные операторы if, то с ними должна идти в паре ветвь else. Ее отсутствие приведет к защелкиванию. Если вы не хотите использовать else, то необходимо инициализировать все переменные в комбинационной части нулями сразу при их объявлении.
Пример одноразрядный сумматор
Verilog Code:
module adder_using_always (); reg a, b; reg sum, carry; always @ (a or b) begin {carry,sum} = a + b; end initial begin $monitor (" A = %b B = %b CARRY = %b SUM = %b",a,b,carry,sum); #10 a = 0; b = 0; #10 a = 1; #10 b = 1; #10 a = 0; #10 b = 0; #10 $finish; end endmodule
Инструкции в процедурном блоке работают одновременно с векторами.
Пример четырехразрядный сумматор
Verilog Code:
module adder_4_bit_using_always (); reg[3:0] a, b; reg [3:0] sum; reg carry; always @ (a or b) begin {carry,sum} = a + b; end initial begin $monitor (" A = %b B = %b CARRY = %b SUM = %b",a,b,carry,sum); #10 a = 8; b = 7; #10 a = 10; #10 b = 15; #10 a = 0; #10 b = 0; #10 $finish; end endmodule
Пример устранение защелкивания учетом всех случаев
Verilog Code:
module avoid_latch_else (); reg q; reg enable, d; always @ (enable or d) if (enable) begin q = d; end else begin q = 0; end initial begin $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q); #1 enable = 0; #1 d = 0; #1 enable = 1; #1 d = 1; #1 d = 0; #1 d = 1; #1 d = 0; #1 d = 1; #1 enable = 0; #1 $finish; end endmodule
Пример устранение защелкивания обнулением переменных
Verilog Code:
module avoid_latch_init (); reg q; reg enable, d; always @ (enable or d) begin q = 0; if (enable) begin q = d; end end initial begin $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q); #1 enable = 0; #1 d = 0; #1 enable = 1; #1 d = 1; #1 d = 0; #1 d = 1; #1 d = 0; #1 d = 1; #1 enable = 0; #1 $finish; end endmodule
Последовательная логика в процедурах
Для моделирования последовательной логики, процедурный блок должен быть чувствительным к положительному или отрицательному перепаду тактового импульса (фронту). Для моделирования асинхронного сброса, он должен быть чувствителен как к фронтам тактов, так и сбросу. Все присваивания в последовательной логике должны быть неблокирующими.
Иногда есть желание иметь несколько переменных для фронта сигналов, это хорошо для симуляции. Но для синтеза это не имеет смысла, физически триггеры могут иметь только один тактовый сигнал, один сброс и одну предустановку (т.е. posedge clk или posedge reset или posedge preset).
Одной из частых ошибок начинающих является назначение тактового сигнала на разрешающий вход триггеров. Это хорошо для симуляции, но для синтеза не годится.
Пример неверный код два тактовых сигнала
Verilog Code:
module wrong_seq(); reg q; reg clk1, clk2, d1, d2; always @ (posedge clk1 or posedge clk2) if (clk1) begin q <= d1; end else if (clk2) begin q <= d2; end initial begin $monitor ("CLK1 = %b CLK2 = %b D1 = %b D2 %b Q = %b", clk1, clk2, d1, d2, q); clk1 = 0; clk2 = 0; d1 = 0; d2 = 1; #10 $finish; end always #1 clk1 = ~clk1; always #1.9 clk2 = ~clk2; endmodule
Пример Dтриггер с асинхронным сбросом и предустановкой
Verilog Code:
module dff_async_reset_async_preset(); reg clk,reset,preset,d; reg q; always @ (posedge clk or posedge reset or posedge preset) if (reset) begin q <= 0; end else if (preset) begin q <= 1; end else begin q <= d; end // Testbench code here initial begin $monitor("CLK = %b RESET = %b PRESET = %b D = %b Q = %b", clk,reset,preset,d,q); clk = 0; #1 reset = 0; preset = 0; d = 0; #1 reset = 1; #2 reset = 0; #2 preset = 1; #2 preset = 0; repeat (4) begin #2 d = ~d; end #2 $finish; end always #1 clk = ~clk; endmodule
Пример Dтриггер с синхронным сбросом и предустановкой
Verilog Code:
module dff_sync_reset_sync_preset(); reg clk,reset,preset,d; reg q; 6 always @ (posedge clk) 7 if (reset) begin 8 q <= 0; 9 end else if (preset) begin 10 q <= 1; 11 end else begin 12 q <= d; 13 end 14 15 // Testbench code here 16 initial begin 17 $monitor("CLK = %b RESET = %b PRESET = %b D = %b Q = %b", 18 clk,reset,preset,d,q); 19 clk = 0; 20 #1 reset = 0; 21 preset = 0; 22 d = 0; 23 #1 reset = 1; 24 #2 reset = 0; 25 #2 preset = 1; 26 #2 preset = 0; 27 repeat (4) begin 28 #2 d = ~d; 29 end 30 #2 $finish; 31 end 32 33 always 34 #1 clk = ~clk; 35 36 endmodule
Процедуры не могут запускать сами себя
Невозможно воздействовать на процедуру при помощи переменной, которой в блоке присваивается значение.
Verilog Code:
module trigger_itself(); reg clk; always @ (clk) #5 clk = ! clk; // Testbench code here initial begin $monitor("TIME = %d CLK = %b",$time,clk); clk = 0; #500 $display("TIME = %d CLK = %b",$time,clk); $finish; end endmodule
Конкуренция в процедурных блоках
Если в пределах одного модуля есть несколько блоков, то все они (always и initial) начинают выполняться в момент времени 0 и будут выполняться конкурентным образом. Иногда это приводит к явлению "гонки", если кодирование делалось неправильно.
Verilog Code:
module multiple_blocks (); reg a,b; reg c,d; reg clk,reset; // Combo Logic always @ ( c) begin a = c; end // Seq Logic always @ (posedge clk) if (reset) begin b <= 0; end else begin b <= a & d; end // Testbench code here initial begin $monitor("TIME = %d CLK = %b C = %b D = %b A = %b B = %b", $time, clk,c,d,a,b); clk = 0; reset = 0; c = 0; d = 0; #2 reset = 1; #2 reset = 0; #2 c = 1; #2 d = 1; #2 c = 0; #5 $finish; end // Clock generator always #1 clk = ~clk; endmodule
Условия гонки
Verilog Code:
module race_condition(); reg b; initial begin b = 0; end initial begin b = 1; end endmodule
В примере выше трудно сказать чтонибудь о значении b, поскольку оба блока выполняются одновременно. В Verilog приходится все время следить за тем, чтобы подобных условий не возникало.