Класс Environment
Класс
- new() – конструктор, в котором виртуальные интерфейсы, переданные из программного блока, присваиваются виртуальным интерфейсам, объявленным в классе
Environment . Сам по себе виртуальный интерфейс является неким абстрактным дескриптором физического интерфейса (указатель на физический интерфейс). Напомню, что физические интерфейсы объявлены в модуле tb_top. Метод new() связывает виртуальный интерфейс с физическим (см. рис. 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).
Рис. 10. Привязка виртуального интерфейса к физическому
При неизменном составе тестового окружения от тестируемых схем зависит только содержимое методов reset() и cfg_dut().
Перед объявлением класса
- `include "Transaction.sv"
- `include "Coverage.sv"
- `include "Driver.sv"
- `include "Receiver.sv"
- `include "Scoreboard.sv"
Это делает класс
В начале описания класса
- virtual input_interface.input_prt input_intf ;
- virtual output_interface.output_prt output_intf[2] ;
, к которым потом в конструкторе подсоединяются интерфейсы, переданные из программного блока testcase:
- function new(virtual input_interface.input_prt input_intf_new ,
- virtual output_interface.output_prt output_intf_new[2] );
- this.input_intf = input_intf_new ;
- this.output_intf = output_intf_new ;
- ...
Далее объявляются компоненты тестового окружения:
- Driver drvr;
- Receiver rcvr[2];
- Scoreboard sb;
- mailbox #(Transaction) rcvr2sb[2];
Как видите, экземпляры классов и почтовых ящиков можно объявлять массивами, как это мы делали с экземплярами выходного интерфейса.
Примечание
В SystemVerilog есть обычные почтовые ящики:
- mailbox rcvr2sb[2];
и параметризированные:
- mailbox #(Transaction) rcvr2sb[2];
Обычные почтовые ящики позволяют передавать данные различных типов, а параметризированные – только одного (в нашем случае типа Transaction). Симулятор VCS разрешает использование почтовых ящиков любого типа, а вот ModelSim – только параметризированные. Во многих случаях использование параметризированных почтовых ящиков спасает от ошибки несоответствия типов (type mismatch). Для того, чтобы наше IP-ядро не было чувствительно к симулятору, будем использовать только параметризированные почтовые ящики.
Рассмотрим подробнее метод build():
1) В цикле foreach создаются почтовые ящики:
- foreach(rcvr2sb[i])
- rcvr2sb[i] = new();
2) Создается драйвер:
- drvr= new(input_intf);
, которому передается входной интерфейс.
3) Создается блок сравнения:
- sb = new(rcvr2sb);
Несмотря на то, что он подключен к двум почтовым ящикам, в конструктор передается только одно название без индекса.
4) В цикле foreach создается 2 приемника:
- foreach(rcvr[i])
- rcvr[i] = new(output_intf[i], rcvr2sb[i]);
Каждому приемнику передается свой интерфейс и почтовый ящик.
Исходный код класса
- `ifndef _
ENVIRONMENT _- `define _
ENVIRONMENT _- `include "Transaction.sv"
- `include "Coverage.sv"
- `include "Driver.sv"
- `include "Receiver.sv"
- `include "Scoreboard.sv"
- class
Environment ;- virtual input_interface.input_prt input_intf ;
- virtual output_interface.output_prt output_intf[2] ;
- Driver drvr;
- Receiver rcvr[2];
- Scoreboard sb;
- mailbox #(Transaction) rcvr2sb[2];
- function new(virtual input_interface.input_prt input_intf_new ,
- virtual output_interface.output_prt output_intf_new[2] );
- this.input_intf = input_intf_new ;
- this.output_intf = output_intf_new ;
- $display(" %0d :
Environment : constructor created env object",$time);- endfunction : new
- function void build();
- $display(" %0d :
Environment : start of build() method",$time);- foreach(rcvr2sb[i])
- rcvr2sb[i] = new();
- drvr = new(input_intf);
- sb = new(rcvr2sb);
- foreach(rcvr[i])
- rcvr[i]= new(output_intf[i], rcvr2sb[i]);
- $display(" %0d :
Environment : end of build() method",$time);- endfunction : build
- task reset();
- $display(" %0d :
Environment : start of reset() method",$time);- // Drive all DUT inputs to a known state
- input_intf.cb.a <= 0;
- input_intf.cb.b <= 0;
- input_intf.cb.c <= 0;
- input_intf.cb.d <= 0;
- /*// Reset the DUT
- input_intf.reset <= 1;
- repeat (4) @input_intf.clock;
- input_intf.reset <= 0;
- */
- $display(" %0d :
Environment : end of reset() method",$time);- endtask : reset
- task cfg_dut();
- $display(" %0d :
Environment : start of cfg_dut() method",$time);- //empty
- $display(" %0d :
Environment : end of cfg_dut() method",$time);- endtask : cfg_dut
- task start();
- $display(" %0d :
Environment : start of start() method",$time);- fork
- drvr.start();
- rcvr[0].start();
- rcvr[1].start();
- sb.start();
- join_any
- $display(" %0d :
Environment : end of start() method",$time);- endtask : start
- task wait_for_end();
- $display(" %0d :
Environment : start of wait_for_end() method",$time);- repeat(100) @(input_intf.clock);
- $display(" %0d :
Environment : end of wait_for_end() method",$time);- endtask : wait_for_end
- task report();
- Transaction trans;
- $display(" %0d :
Environment : start of report() method",$time);- $display("=====================================");
- if (trans.errors == 1)
- $display(" Test completed with 1 error");
- else if (trans.errors)
- $display(" Test completed with %d errors", trans.errors);
- else
- $display(" Test completed without errors");
- $display("=====================================");
- $display(" %0d :
Environment : end of report() method",$time);- endtask : report
- task run();
- $display(" %0d :
Environment : start of run() method",$time);- build();
- reset();
- cfg_dut();
- start();
- wait_for_end();
- report();
- $display(" %0d :
Environment : end of run() method",$time);- endtask : run
- endclass
- `endif