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

Процедурные блоки языка Verilog

Модели поведения описываются внутри процедурных блоков, но есть исключение:

  • initial : выполняются только в начальный момент времени симуляции.
  • always : выполняются в бесконечном цикле [буквально "всегда"].

Мы рассмотрим их подробно в дальнейшем.

Пример - initial

Verilog Code:
  1. module initial_example();
  2. reg clk,reset,enable,data;
  3.  
  4. initial begin
  5. clk = 0;
  6. reset = 0;
  7. enable = 0;
  8. data = 0;
  9. end
  10.  
  11. endmodule

В примере выше, блоки initial и always начинают выполняться в момент времени 0. Блок always ожидает события положительного фронта тактового сигнала, а блок initial ничего не ожидает, выполняясь однократно в начальный момент.

Пример - always

Verilog Code:
  1. module always_example();
  2. reg clk,reset,enable,q_in,data;
  3.  
  4. always @ (posedge clk)
  5. if (reset) begin
  6. data <= 0;
  7. end else if (enable) begin
  8. data <= q_in;
  9. end
  10.  
  11. endmodule

В блоке always, при наступлении триггерного события, выполняется код внутри begin ... end и затем этот блок ожидает очередного события ­ переднего фронта тактового сигнала. Процесс ожидания и выполнения продолжается все время, до конца симуляции.

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

  • В процедурах присваивание производится регистровым типам, целым или вещественным числам, или переменной времени. Не допускается присваивание "проводниковым" типам данных, например wire.
  • Можно присваивать регистрам значения типа wire, постоянных, других регистров или указывать отдельные значения.

Пример ­ неверное присваивание

Verilog Code:
  1. module initial_bad();
  2. reg clk,reset;
  3. wire enable,data;
  4.  
  5. initial begin
  6. clk = 0;
  7. reset = 0;
  8. enable = 0;
  9. data = 0;
  10. end
  11.  
  12. endmodule

Пример ­ правильное присваивание

Verilog Code:
  1. module initial_good();
  2. reg clk,reset,enable,data;
  3.  
  4. initial begin
  5. clk = 0;
  6. reset = 0;
  7. enable = 0;
  8. data = 0;
  9. end
  10.  
  11. endmodule

Группы присваивания в процедурах

Если процедурный блок содержит более одной инструкции, их можно заключить в блоки:

  • Последовательный begin − end.
  • Параллельный fork − join.

При использовании begin−end, можно задать имя. Такие блоки являются именованными.

Пример ­ begin - end

Verilog Code:
  1. module initial_begin_end();
  2. reg clk,reset,enable,data;
  3.  
  4. initial begin
  5. $monitor("%g clk=%b reset=%b enable=%b data=%b",
  6. $time, clk, reset, enable, data);
  7. #1 clk = 0;
  8. #10 reset = 0;
  9. #5 enable = 0;
  10. #3 data = 0;
  11. #1 $finish;
  12. end
  13.  
  14. endmodule

Begin: clk = 0 когда time = 1, reset = 0 через интервал 11 единиц времени, enable = 0 через 16 единиц времени, data через 19 единиц. Все инструкции выполняются последовательно.

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

Code:
  1. 0 clk=x reset=x enable=x data=x
  2. 1 clk=0 reset=x enable=x data=x
  3. 11 clk=0 reset=0 enable=x data=x
  4. 16 clk=0 reset=0 enable=0 data=x
  5. 19 clk=0 reset=0 enable=0 data=0

Пример ­ fork - join

Verilog Code:
  1. module initial_fork_join();
  2. reg clk,reset,enable,data;
  3.  
  4. initial begin
  5. $monitor("%g clk=%b reset=%b enable=%b data=%b",
  6. $time, clk, reset, enable, data);
  7. fork
  8. #1 clk = 0;
  9. #10 reset = 0;
  10. #5 enable = 0;
  11. #3 data = 0;
  12. join
  13. #1 $display ("%g Terminating simulation", $time);
  14. $finish;
  15. end
  16.  
  17. endmodule

Fork: clk получает значение через 1 ед. времени, reset ­ через 10, enable ­ через 5, data ­ через 3 с момента старта. Все инструкции выполняются параллельно.

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

Ключевые слова begin − end:

  • Группируют вместе несколько инструкций.
  • Предписывают последовательное выполнение (по одной инструкции).
    1. Любой тайминг в пределах группы относится к предыдущей инструкции.
    2. Задержки последовательно накапливаются (суммируются)
    3. Блок завершается его последней инструкцией.

Пример ­ sequential

Verilog Code:
  1. module sequential();
  2.  
  3. reg a;
  4.  
  5. initial begin
  6. $monitor ("%g a = %b", $time, a);
  7. #10 a = 0;
  8. #11 a = 1;
  9. #12 a = 0;
  10. #13 a = 1;
  11. #14 $finish;
  12. end
  13.  
  14. endmodule

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

Code:
  1. 0 a = x
  2. 10 a = 0
  3. 21 a = 1
  4. 33 a = 0
  5. 46 a = 1

Параллельные группы инструкций

Ключевые слова fork − join:

  • Группируют вместе несколько инструкций.
  • Предписывают паралльное выполнение (всех одновременно).
    1. Тайминг в параллельных группах для всех инструкций привязан к началу времени блока.
    2. Блок завершается после выполнения последней по времени инструкции (инструкция с наибольшей задержкой, даже если она первая в блоке).

Пример ­ parallel

Verilog Code:
  1. module parallel();
  2.  
  3. reg a;
  4.  
  5. initial
  6. fork
  7. $monitor ("%g a = %b", $time, a);
  8. #10 a = 0;
  9. #11 a = 1;
  10. #12 a = 0;
  11. #13 a = 1;
  12. #14 $finish;
  13. join
  14.  
  15. endmodule

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

Code:
  1. 0 a = x
  2. 10 a = 0
  3. 11 a = 1
  4. 12 a = 0
  5. 13 a = 1

Пример − begin−end и fork − join

Verilog Code:
  1. module fork_join();
  2.  
  3. reg clk,reset,enable,data;
  4.  
  5. initial begin
  6. $display ("Starting simulation");
  7. $monitor("%g clk=%b reset=%b enable=%b data=%b",
  8. $time, clk, reset, enable, data);
  9. fork : FORK_VAL
  10. #1 clk = 0;
  11. #5 reset = 0;
  12. #5 enable = 0;
  13. #2 data = 0;
  14. join
  15. #10 $display ("%g Terminating simulation", $time);
  16. $finish;
  17. end
  18.  
  19. endmodule

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

Code:
  1. 0 clk=x reset=x enable=x data=x
  2. 1 clk=0 reset=x enable=x data=x
  3. 2 clk=0 reset=x enable=x data=0
  4. 5 clk=0 reset=0 enable=0 data=0
  5. 15 Terminating simulation

Блокирующие и неблокирующие присваивания

Блокирующие присваивания выполняются в том порядке, в каком записан их код. Таким образом, это последовательные присваивания. Поскольку они блокируют выполнение очередной инструкции на время выполнения текущей, они называются блокирующими. Присваивания записываются при помощи символа "=". Пример: a = b;

Неблокирующие присваивания выполняются параллельно. Поскольку блокирования следующей инструкции во время выполнения текущей не происходит, они называются неблокирующими. Это присваивание записывается при помощи символа "<=". Пример: a <= b;

Пример − блокирующие и неблокирующие инструкции

Verilog Code:
  1. module blocking_nonblocking();
  2.  
  3. reg a,b,c,d;
  4. // Blocking Assignment
  5. initial begin
  6. #10 a = 0;
  7. #11 a = 1;
  8. #12 a = 0;
  9. #13 a = 1;
  10. end
  11.  
  12. initial begin
  13. #10 b <= 0;
  14. #11 b <= 1;
  15. #12 b <= 0;
  16. #13 b <= 1;
  17. end
  18.  
  19. initial begin
  20. c = #10 0;
  21. c = #11 1;
  22. c = #12 0;
  23. c = #13 1;
  24. end
  25.  
  26. initial begin
  27. d <= #10 0;
  28. d <= #11 1;
  29. d <= #12 0;
  30. d <= #13 1;
  31. end
  32.  
  33. initial begin
  34. $monitor("TIME = %g A = %b B = %b C = %b D = %b",$time, a, b, c, d);
  35. #50 $finish;
  36. end
  37.  
  38. endmodule

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

Code:
  1. TIME = 0 A = x B = x C = x D = x
  2. TIME = 10 A = 0 B = 0 C = 0 D = 0
  3. TIME = 11 A = 0 B = 0 C = 0 D = 1
  4. TIME = 12 A = 0 B = 0 C = 0 D = 0
  5. TIME = 13 A = 0 B = 0 C = 0 D = 1
  6. TIME = 21 A = 1 B = 1 C = 1 D = 1
  7. TIME = 33 A = 0 B = 0 C = 0 D = 1
  8. TIME = 46 A = 1 B = 1 C = 1 D = 1

Изображения сигналов к примеру выше

Операторы assign и deassign

Процедурные операторы назначения и отмены назначения позволяют помещать непрерывные назначения в регистры на контролируемые периоды времени. Процедурный оператор assign отменяет процедурные назначения регистру. Процедурный оператор deassign завершает непрерывное присвоение регистру.

Пример − assign и deassign

Verilog Code:
  1. module assign_deassign ();
  2.  
  3. reg clk,rst,d,preset;
  4. wire q;
  5.  
  6. initial begin
  7. $monitor("@%g clk %b rst %b preset %b d %b q %b",
  8. $time, clk, rst, preset, d, q);
  9. clk = 0;
  10. rst = 0;
  11. d = 0;
  12. preset = 0;
  13. #10 rst = 1;
  14. #10 rst = 0;
  15. repeat (10) begin
  16. @ (posedge clk);
  17. d <= $random;
  18. @ (negedge clk) ;
  19. preset <= ~preset;
  20. end
  21. #1 $finish;
  22. end
  23. // Clock generator
  24. always #1 clk = ~clk;
  25.  
  26. // assign and deassign q of flip flop module
  27. always @(preset)
  28. if (preset) begin
  29. assign U.q = 1; // assign procedural statement
  30. end else begin
  31. deassign U.q; // deassign procedural statement
  32. end
  33.  
  34. d_ff U (clk,rst,d,q);
  35.  
  36. endmodule
  37.  
  38. // D Flip-Flop model
  39. module d_ff (clk,rst,d,q);
  40. input clk,rst,d;
  41. output q;
  42. reg q;
  43.  
  44. always @ (posedge clk)
  45. if (rst) begin
  46. q <= 0;
  47. end else begin
  48. q <= d;
  49. end
  50.  
  51. endmodule

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

Code:
  1. @0 clk 0 rst 0 preset 0 d 0 q x
  2. @1 clk 1 rst 0 preset 0 d 0 q 0
  3. @2 clk 0 rst 0 preset 0 d 0 q 0
  4. @3 clk 1 rst 0 preset 0 d 0 q 0
  5. @4 clk 0 rst 0 preset 0 d 0 q 0
  6. @5 clk 1 rst 0 preset 0 d 0 q 0
  7. @6 clk 0 rst 0 preset 0 d 0 q 0
  8. @7 clk 1 rst 0 preset 0 d 0 q 0
  9. @8 clk 0 rst 0 preset 0 d 0 q 0
  10. @9 clk 1 rst 0 preset 0 d 0 q 0
  11. @10 clk 0 rst 1 preset 0 d 0 q 0
  12. @11 clk 1 rst 1 preset 0 d 0 q 0
  13. @12 clk 0 rst 1 preset 0 d 0 q 0
  14. @13 clk 1 rst 1 preset 0 d 0 q 0
  15. @14 clk 0 rst 1 preset 0 d 0 q 0
  16. @15 clk 1 rst 1 preset 0 d 0 q 0
  17. @16 clk 0 rst 1 preset 0 d 0 q 0
  18. @17 clk 1 rst 1 preset 0 d 0 q 0
  19. @18 clk 0 rst 1 preset 0 d 0 q 0
  20. @19 clk 1 rst 1 preset 0 d 0 q 0
  21. @20 clk 0 rst 0 preset 0 d 0 q 0
  22. @21 clk 1 rst 0 preset 0 d 0 q 0
  23. @22 clk 0 rst 0 preset 1 d 0 q 1
  24. @23 clk 1 rst 0 preset 1 d 1 q 1
  25. @24 clk 0 rst 0 preset 0 d 1 q 1
  26. @25 clk 1 rst 0 preset 0 d 1 q 1
  27. @26 clk 0 rst 0 preset 1 d 1 q 1
  28. @27 clk 1 rst 0 preset 1 d 1 q 1
  29. @28 clk 0 rst 0 preset 0 d 1 q 1
  30. @29 clk 1 rst 0 preset 0 d 1 q 1
  31. @30 clk 0 rst 0 preset 1 d 1 q 1
  32. @31 clk 1 rst 0 preset 1 d 1 q 1
  33. @32 clk 0 rst 0 preset 0 d 1 q 1
  34. @33 clk 1 rst 0 preset 0 d 1 q 1
  35. @34 clk 0 rst 0 preset 1 d 1 q 1
  36. @35 clk 1 rst 0 preset 1 d 0 q 1
  37. @36 clk 0 rst 0 preset 0 d 0 q 1
  38. @37 clk 1 rst 0 preset 0 d 1 q 0
  39. @38 clk 0 rst 0 preset 1 d 1 q 1
  40. @39 clk 1 rst 0 preset 1 d 1 q 1
  41. @40 clk 0 rst 0 preset 0 d 1 q 1

Операторы force и release

Другая форма процедурного непрерывного присвоения обеспечивается процедурными заявлениями о принуждении и освобождении. Эти операторы имеют аналогичный эффект для пары assign-deassign, но принудительное действие может быть применено как к цепям, так и к регистрам.

Можно использовать force и release при моделировании на вентильном уровне, чтобы обойти проблемы со сбросом соединения. Также можно использовать вставку одиночных и двойных битовых ошибок в данные, считанные из памяти.

Пример − force и release

Verilog Code:
  1. module force_release ();
  2.  
  3. reg clk,rst,d,preset;
  4. wire q;
  5.  
  6. initial begin
  7. $monitor("@%g clk %b rst %b preset %b d %b q %b",
  8. $time, clk, rst, preset, d, q);
  9. clk = 0;
  10. rst = 0;
  11. d = 0;
  12. preset = 0;
  13. #10 rst = 1;
  14. #10 rst = 0;
  15. repeat (10) begin
  16. @ (posedge clk);
  17. d <= $random;
  18. @ (negedge clk) ;
  19. preset <= ~preset;
  20. end
  21. #1 $finish;
  22. end
  23. // Clock generator
  24. always #1 clk = ~clk;
  25.  
  26. // force and release of flip flop module
  27. always @(preset)
  28. if (preset) begin
  29. force U.q = preset; // force procedural statement
  30. end else begin
  31. release U.q; // release procedural statement
  32. end
  33.  
  34. d_ff U (clk,rst,d,q);
  35.  
  36. endmodule
  37.  
  38. // D Flip-Flop model
  39. module d_ff (clk,rst,d,q);
  40. input clk,rst,d;
  41. output q;
  42. wire q;
  43. reg q_reg;
  44.  
  45. assign q = q_reg;
  46.  
  47. always @ (posedge clk)
  48. if (rst) begin
  49. q_reg <= 0;
  50. end else begin
  51. q_reg <= d;
  52. end
  53.  
  54. endmodule

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

Code:
  1. @0 clk 0 rst 0 preset 0 d 0 q x
  2. @1 clk 1 rst 0 preset 0 d 0 q 0
  3. @2 clk 0 rst 0 preset 0 d 0 q 0
  4. @3 clk 1 rst 0 preset 0 d 0 q 0
  5. @4 clk 0 rst 0 preset 0 d 0 q 0
  6. @5 clk 1 rst 0 preset 0 d 0 q 0
  7. @6 clk 0 rst 0 preset 0 d 0 q 0
  8. @7 clk 1 rst 0 preset 0 d 0 q 0
  9. @8 clk 0 rst 0 preset 0 d 0 q 0
  10. @9 clk 1 rst 0 preset 0 d 0 q 0
  11. @10 clk 0 rst 1 preset 0 d 0 q 0
  12. @11 clk 1 rst 1 preset 0 d 0 q 0
  13. @12 clk 0 rst 1 preset 0 d 0 q 0
  14. @13 clk 1 rst 1 preset 0 d 0 q 0
  15. @14 clk 0 rst 1 preset 0 d 0 q 0
  16. @15 clk 1 rst 1 preset 0 d 0 q 0
  17. @16 clk 0 rst 1 preset 0 d 0 q 0
  18. @17 clk 1 rst 1 preset 0 d 0 q 0
  19. @18 clk 0 rst 1 preset 0 d 0 q 0
  20. @19 clk 1 rst 1 preset 0 d 0 q 0
  21. @20 clk 0 rst 0 preset 0 d 0 q 0
  22. @21 clk 1 rst 0 preset 0 d 0 q 0
  23. @22 clk 0 rst 0 preset 1 d 0 q 1
  24. @23 clk 1 rst 0 preset 1 d 1 q 1
  25. @24 clk 0 rst 0 preset 0 d 1 q 0
  26. @25 clk 1 rst 0 preset 0 d 1 q 1
  27. @26 clk 0 rst 0 preset 1 d 1 q 1
  28. @27 clk 1 rst 0 preset 1 d 1 q 1
  29. @28 clk 0 rst 0 preset 0 d 1 q 1
  30. @29 clk 1 rst 0 preset 0 d 1 q 1
  31. @30 clk 0 rst 0 preset 1 d 1 q 1
  32. @31 clk 1 rst 0 preset 1 d 1 q 1
  33. @32 clk 0 rst 0 preset 0 d 1 q 1
  34. @33 clk 1 rst 0 preset 0 d 1 q 1
  35. @34 clk 0 rst 0 preset 1 d 1 q 1
  36. @35 clk 1 rst 0 preset 1 d 0 q 1
  37. @36 clk 0 rst 0 preset 0 d 0 q 1
  38. @37 clk 1 rst 0 preset 0 d 1 q 0
  39. @38 clk 0 rst 0 preset 1 d 1 q 1
  40. @39 clk 1 rst 0 preset 1 d 1 q 1
  41. @40 clk 0 rst 0 preset 0 d 1 q 1