Класс Environment

Класс Environment

Класс  Environment  описан в файле  Environment .sv. В нем описываются методы, определяющие архитектуру тестового окружения и управляющие процессом симуляции:

  • new() – конструктор, в котором виртуальные интерфейсы, переданные из программного блока, присваиваются виртуальным интерфейсам, объявленным в классе  Environment . Сам по себе виртуальный интерфейс является неким абстрактным дескриптором физического интерфейса (указатель на физический интерфейс). Напомню, что физические интерфейсы объявлены в модуле tb_top. Метод new() связывает виртуальный интерфейс с физическим (см. рис. 10).
  • Рис. 10. Привязка виртуального интерфейса к физическому

    Рис. 10. Привязка виртуального интерфейса к физическому

  • build() – в этом методе создаются компоненты тестового окружения, а точнее экземпляры классов Driver, Scoreboard и по 2 экземпляра почтового ящика mailbox и класса Receiver.
  • reset() – этот метод посылает сигнал сброса на тестируемое устройство. В схеме вычисления адресов операндов этого сигнала нет, поэтому этот метод просто устанавливает начальное состояние всех входных сигналов в 0.
  • cfg_dut() – с помощью этого метода конфигурируются тестируемые устройства. Для рассматриваемой схемы это не требуется.
  • start() – этот метод активирует работу компонентов тестового окружения. В блоке fork-join_any начинают параллельно выполняться 4 метода start() созданных компонентов тестового окружения. Выход из блока осуществляется при завершении любого из этих методов.
  • wait_for_end() – этот метод вносит дополнительную задержку для корректного завершения симуляции. Метод start() завершает свою работу при остановке любого компонента тестового окружения, а метод wait_for_end() ждет, пока остальные компоненты завершат свою работу.
  • report() – этот метод выводит информацию о количестве ошибок, возникших при симуляции. Для этого анализируется содержимое вектора ошибок errors, объявленного в классе Transaction.
  • run() – в этом методе в определенном порядке вызываются все описанные выше методы (за исключением метода new(), который вызывается в программном блоке testcase) (см. рис. 11).
  • Рис. 11. Порядок вызова методов класса Environment

    Рис. 11. Порядок вызова методов класса  Environment 

При неизменном составе тестового окружения от тестируемых схем зависит только содержимое методов reset() и cfg_dut().
Перед объявлением класса  Environment  в него включаются файлы, в которых описаны компоненты тестового окружения:

  1. `include "Transaction.sv"
  2. `include "Coverage.sv"
  3. `include "Driver.sv"
  4. `include "Receiver.sv"
  5. `include "Scoreboard.sv"

Это делает класс  Environment  независимым от порядка компиляции.
В начале описания класса  Environment  объявляются виртуальные интерфейсы:

  1. virtual input_interface.input_prt input_intf ;
  2. virtual output_interface.output_prt output_intf[2] ;

, к которым потом в конструкторе подсоединяются интерфейсы, переданные из программного блока testcase:

  1. function new(virtual input_interface.input_prt input_intf_new ,
  2. virtual output_interface.output_prt output_intf_new[2] );
  3.  
  4. this.input_intf = input_intf_new ;
  5. this.output_intf = output_intf_new ;
  6. ...

Далее объявляются компоненты тестового окружения:

  1. Driver drvr;
  2. Receiver rcvr[2];
  3. Scoreboard sb;
  4. mailbox #(Transaction) rcvr2sb[2];

Как видите, экземпляры классов и почтовых ящиков можно объявлять массивами, как это мы делали с экземплярами выходного интерфейса.

Примечание

В SystemVerilog есть обычные почтовые ящики:

  1. mailbox rcvr2sb[2];

и параметризированные:

  1. mailbox #(Transaction) rcvr2sb[2];

Обычные почтовые ящики позволяют передавать данные различных типов, а параметризированные – только одного (в нашем случае типа Transaction). Симулятор VCS разрешает использование почтовых ящиков любого типа, а вот ModelSim – только параметризированные. Во многих случаях использование параметризированных почтовых ящиков спасает от ошибки несоответствия типов (type mismatch). Для того, чтобы наше IP-ядро не было чувствительно к симулятору, будем использовать только параметризированные почтовые ящики.

Рассмотрим подробнее метод build():
1) В цикле foreach создаются почтовые ящики:

  1. foreach(rcvr2sb[i])
  2. rcvr2sb[i] = new();

2) Создается драйвер:

  1. drvr= new(input_intf);

, которому передается входной интерфейс.
3) Создается блок сравнения:

  1. sb = new(rcvr2sb);

Несмотря на то, что он подключен к двум почтовым ящикам, в конструктор передается только одно название без индекса.
4) В цикле foreach создается 2 приемника:

  1. foreach(rcvr[i])
  2. rcvr[i] = new(output_intf[i], rcvr2sb[i]);

Каждому приемнику передается свой интерфейс и почтовый ящик.
Исходный код класса  Environment :

  1. `ifndef _ ENVIRONMENT _
  2. `define _ ENVIRONMENT _
  3.  
  4. `include "Transaction.sv"
  5. `include "Coverage.sv"
  6. `include "Driver.sv"
  7. `include "Receiver.sv"
  8. `include "Scoreboard.sv"
  9.  
  10. class  Environment  ;
  11.  
  12. virtual input_interface.input_prt input_intf ;
  13. virtual output_interface.output_prt output_intf[2] ;
  14.  
  15. Driver drvr;
  16. Receiver rcvr[2];
  17. Scoreboard sb;
  18. mailbox #(Transaction) rcvr2sb[2];
  19.  
  20. function new(virtual input_interface.input_prt input_intf_new ,
  21. virtual output_interface.output_prt output_intf_new[2] );
  22.  
  23. this.input_intf = input_intf_new ;
  24. this.output_intf = output_intf_new ;
  25.  
  26. $display(" %0d :  Environment  : constructor created env object",$time);
  27. endfunction : new
  28.  
  29. function void build();
  30. $display(" %0d :  Environment  : start of build() method",$time);
  31. foreach(rcvr2sb[i])
  32. rcvr2sb[i] = new();
  33. drvr = new(input_intf);
  34. sb = new(rcvr2sb);
  35. foreach(rcvr[i])
  36. rcvr[i]= new(output_intf[i], rcvr2sb[i]);
  37. $display(" %0d :  Environment  : end of build() method",$time);
  38. endfunction : build
  39.  
  40. task reset();
  41. $display(" %0d :  Environment  : start of reset() method",$time);
  42. // Drive all DUT inputs to a known state
  43. input_intf.cb.a <= 0;
  44. input_intf.cb.b <= 0;
  45. input_intf.cb.c <= 0;
  46. input_intf.cb.d <= 0;
  47.  
  48. /*// Reset the DUT
  49. input_intf.reset <= 1;
  50. repeat (4) @input_intf.clock;
  51. input_intf.reset <= 0;
  52. */
  53. $display(" %0d :  Environment  : end of reset() method",$time);
  54. endtask : reset
  55. task cfg_dut();
  56. $display(" %0d :  Environment  : start of cfg_dut() method",$time);
  57. //empty
  58. $display(" %0d :  Environment  : end of cfg_dut() method",$time);
  59. endtask : cfg_dut
  60.  
  61. task start();
  62. $display(" %0d :  Environment  : start of start() method",$time);
  63. fork
  64. drvr.start();
  65. rcvr[0].start();
  66. rcvr[1].start();
  67. sb.start();
  68. join_any
  69. $display(" %0d :  Environment  : end of start() method",$time);
  70. endtask : start
  71.  
  72. task wait_for_end();
  73. $display(" %0d :  Environment  : start of wait_for_end() method",$time);
  74. repeat(100) @(input_intf.clock);
  75. $display(" %0d :  Environment  : end of wait_for_end() method",$time);
  76. endtask : wait_for_end
  77.  
  78. task report();
  79.  
  80. Transaction trans;
  81.  
  82. $display(" %0d :  Environment  : start of report() method",$time);
  83.  
  84. $display("=====================================");
  85. if (trans.errors == 1)
  86. $display(" Test completed with 1 error");
  87. else if (trans.errors)
  88. $display(" Test completed with %d errors", trans.errors);
  89. else
  90. $display(" Test completed without errors");
  91. $display("=====================================");
  92.  
  93. $display(" %0d :  Environment  : end of report() method",$time);
  94. endtask : report
  95.  
  96. task run();
  97. $display(" %0d :  Environment  : start of run() method",$time);
  98. build();
  99. reset();
  100. cfg_dut();
  101. start();
  102. wait_for_end();
  103. report();
  104. $display(" %0d :  Environment  : end of run() method",$time);
  105. endtask : run
  106.  
  107. endclass
  108.  
  109. `endif

Share this post