6. Класс Environment
Класс Environment описан в файле Environment.sv. В нем описываются методы, определяющие архитектуру тестового окружения и управляющие процессом симуляции:
- 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. Привязка виртуального интерфейса к физическому
Рис. 11. Порядок вызова методов класса Environment
При неизменном составе тестового окружения от тестируемых схем зависит только содержимое методов reset() и cfg_dut().
Перед объявлением класса Environment в него включаются файлы, в которых описаны компоненты тестового окружения:
`include "Transaction.sv" `include "Coverage.sv" `include "Driver.sv" `include "Receiver.sv" `include "Scoreboard.sv"
Это делает класс Environment независимым от порядка компиляции.
В начале описания класса Environment объявляются виртуальные интерфейсы:
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]);
Каждому приемнику передается свой интерфейс и почтовый ящик.
Исходный код класса Environment:
`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

Комментарии (0)