Визуальная электроника

Управление процедурными блоками

Процедурные блоки активируются в начальный момент симуляции. Выполнением процедур управляют перепады сигналов.

Verilog Code:
  1. module dlatch_using_always();
  2. reg q;
  3.  
  4. reg d, enable;
  5.  
  6. always @ (d or enable)
  7. if (enable) begin
  8. q = d;
  9. end
  10.  
  11. initial begin
  12. $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q);
  13. #1 enable = 0;
  14. #1 d = 1;
  15. #1 enable = 1;
  16. #1 d = 0;
  17. #1 d = 1;
  18. #1 d = 0;
  19. #1 enable = 0;
  20. #10 $finish;
  21. end
  22.  
  23. endmodule

Задержка в начале процедуры, любое изменение d или enable позволяет инструкциям процедуры выполняться. Процедура реагирует на любое изменение d или enable.

Вывод симулятора

Code:
  1. ENABLE = x D = x Q = x
  2. ENABLE = 0 D = x Q = x
  3. ENABLE = 0 D = 1 Q = x
  4. ENABLE = 1 D = 1 Q = 1
  5. ENABLE = 1 D = 0 Q = 0
  6. ENABLE = 1 D = 1 Q = 1
  7. ENABLE = 1 D = 0 Q = 0
  8. ENABLE = 0 D = 0 Q = 0

Комбинационная логика в процедурах

Для моделирования комбинационных схем, процедурные блоки должны быть чувствительны к любым изменениям на входах. Существует важное правило, которому необходимо следовать при моделировании комбнационной логики. Если используются условные операторы if, то с ними должна идти в паре ветвь else. Ее отсутствие приведет к защелкиванию. Если вы не хотите использовать else, то необходимо инициализировать все переменные в комбинационной части нулями сразу при их объявлении.

Пример ­ одноразрядный сумматор

Verilog Code:
  1. module adder_using_always ();
  2. reg a, b;
  3. reg sum, carry;
  4.  
  5. always @ (a or b)
  6. begin
  7. {carry,sum} = a + b;
  8. end
  9.  
  10. initial begin
  11. $monitor (" A = %b B = %b CARRY = %b SUM = %b",a,b,carry,sum);
  12. #10 a = 0;
  13. b = 0;
  14. #10 a = 1;
  15. #10 b = 1;
  16. #10 a = 0;
  17. #10 b = 0;
  18. #10 $finish;
  19. end
  20.  
  21. endmodule

Инструкции в процедурном блоке работают одновременно с векторами.

Пример ­ четырехразрядный сумматор

Verilog Code:
  1. module adder_4_bit_using_always ();
  2. reg[3:0] a, b;
  3. reg [3:0] sum;
  4. reg carry;
  5.  
  6. always @ (a or b)
  7. begin
  8. {carry,sum} = a + b;
  9. end
  10.  
  11. initial begin
  12. $monitor (" A = %b B = %b CARRY = %b SUM = %b",a,b,carry,sum);
  13. #10 a = 8;
  14. b = 7;
  15. #10 a = 10;
  16. #10 b = 15;
  17. #10 a = 0;
  18. #10 b = 0;
  19. #10 $finish;
  20. end
  21.  
  22. endmodule

Пример ­ устранение защелкивания учетом всех случаев

Verilog Code:
  1. module avoid_latch_else ();
  2.  
  3. reg q;
  4. reg enable, d;
  5.  
  6. always @ (enable or d)
  7. if (enable) begin
  8. q = d;
  9. end else begin
  10. q = 0;
  11. end
  12.  
  13. initial begin
  14. $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q);
  15. #1 enable = 0;
  16. #1 d = 0;
  17. #1 enable = 1;
  18. #1 d = 1;
  19. #1 d = 0;
  20. #1 d = 1;
  21. #1 d = 0;
  22. #1 d = 1;
  23. #1 enable = 0;
  24. #1 $finish;
  25. end
  26.  
  27. endmodule

Пример ­ устранение защелкивания обнулением переменных

Verilog Code:
  1. module avoid_latch_init ();
  2.  
  3. reg q;
  4. reg enable, d;
  5.  
  6. always @ (enable or d)
  7. begin
  8. q = 0;
  9. if (enable) begin
  10. q = d;
  11. end
  12. end
  13.  
  14. initial begin
  15. $monitor (" ENABLE = %b D = %b Q = %b",enable,d,q);
  16. #1 enable = 0;
  17. #1 d = 0;
  18. #1 enable = 1;
  19. #1 d = 1;
  20. #1 d = 0;
  21. #1 d = 1;
  22. #1 d = 0;
  23. #1 d = 1;
  24. #1 enable = 0;
  25. #1 $finish;
  26. end
  27.  
  28. endmodule

Последовательная логика в процедурах

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

Иногда есть желание иметь несколько переменных для фронта сигналов, это хорошо для симуляции. Но для синтеза это не имеет смысла, ­ физически триггеры могут иметь только один тактовый сигнал, один сброс и одну предустановку (т.е. posedge clk или posedge reset или posedge preset).

Одной из частых ошибок начинающих является назначение тактового сигнала на разрешающий вход триггеров. Это хорошо для симуляции, но для синтеза не годится.

Пример ­ неверный код ­ два тактовых сигнала

Verilog Code:
  1. module wrong_seq();
  2.  
  3. reg q;
  4. reg clk1, clk2, d1, d2;
  5.  
  6. always @ (posedge clk1 or posedge clk2)
  7. if (clk1) begin
  8. q <= d1;
  9. end else if (clk2) begin
  10. q <= d2;
  11. end
  12.  
  13. initial begin
  14. $monitor ("CLK1 = %b CLK2 = %b D1 = %b D2 %b Q = %b",
  15. clk1, clk2, d1, d2, q);
  16. clk1 = 0;
  17. clk2 = 0;
  18. d1 = 0;
  19. d2 = 1;
  20. #10 $finish;
  21. end
  22.  
  23. always
  24. #1 clk1 = ~clk1;
  25.  
  26. always
  27. #1.9 clk2 = ~clk2;
  28.  
  29. endmodule

Пример ­ D­триггер с асинхронным сбросом и предустановкой

Verilog Code:
  1. module dff_async_reset_async_preset();
  2.  
  3. reg clk,reset,preset,d;
  4. reg q;
  5.  
  6. always @ (posedge clk or posedge reset or posedge preset)
  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

Пример ­ D­триггер с синхронным сбросом и предустановкой

Verilog Code:
  1. module dff_sync_reset_sync_preset();
  2.  
  3. reg clk,reset,preset,d;
  4. reg q;
  5.  
  6. 6 always @ (posedge clk)
  7. 7 if (reset) begin
  8. 8 q <= 0;
  9. 9 end else if (preset) begin
  10. 10 q <= 1;
  11. 11 end else begin
  12. 12 q <= d;
  13. 13 end
  14. 14
  15. 15 // Testbench code here
  16. 16 initial begin
  17. 17 $monitor("CLK = %b RESET = %b PRESET = %b D = %b Q = %b",
  18. 18 clk,reset,preset,d,q);
  19. 19 clk = 0;
  20. 20 #1 reset = 0;
  21. 21 preset = 0;
  22. 22 d = 0;
  23. 23 #1 reset = 1;
  24. 24 #2 reset = 0;
  25. 25 #2 preset = 1;
  26. 26 #2 preset = 0;
  27. 27 repeat (4) begin
  28. 28 #2 d = ~d;
  29. 29 end
  30. 30 #2 $finish;
  31. 31 end
  32. 32
  33. 33 always
  34. 34 #1 clk = ~clk;
  35. 35
  36. 36 endmodule

Процедуры не могут запускать сами себя

Невозможно воздействовать на процедуру при помощи переменной, которой в блоке присваивается значение.

Verilog Code:
  1. module trigger_itself();
  2.  
  3. reg clk;
  4.  
  5. always @ (clk)
  6. #5 clk = ! clk;
  7.  
  8. // Testbench code here
  9. initial begin
  10. $monitor("TIME = %d CLK = %b",$time,clk);
  11. clk = 0;
  12. #500 $display("TIME = %d CLK = %b",$time,clk);
  13. $finish;
  14. end
  15.  
  16. endmodule

Конкуренция в процедурных блоках

Если в пределах одного модуля есть несколько блоков, то все они (always и initial) начинают выполняться в момент времени 0 и будут выполняться конкурентным образом. Иногда это приводит к явлению "гонки", если кодирование делалось неправильно.

Verilog Code:
  1. module multiple_blocks ();
  2. reg a,b;
  3. reg c,d;
  4. reg clk,reset;
  5. // Combo Logic
  6. always @ ( c)
  7. begin
  8. a = c;
  9. end
  10. // Seq Logic
  11. always @ (posedge clk)
  12. if (reset) begin
  13. b <= 0;
  14. end else begin
  15. b <= a & d;
  16. end
  17.  
  18. // Testbench code here
  19. initial begin
  20. $monitor("TIME = %d CLK = %b C = %b D = %b A = %b B = %b",
  21. $time, clk,c,d,a,b);
  22. clk = 0;
  23. reset = 0;
  24. c = 0;
  25. d = 0;
  26. #2 reset = 1;
  27. #2 reset = 0;
  28. #2 c = 1;
  29. #2 d = 1;
  30. #2 c = 0;
  31. #5 $finish;
  32. end
  33. // Clock generator
  34. always
  35. #1 clk = ~clk;
  36.  
  37. endmodule

Условия гонки

Verilog Code:
  1. module race_condition();
  2. reg b;
  3.  
  4. initial begin
  5. b = 0;
  6. end
  7.  
  8. initial begin
  9. b = 1;
  10. end
  11.  
  12. endmodule

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