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

OVM/OVM методология/Механика OVM

Материал из Wiki
Перейти к: навигация, поиск
Проект Диплом

Вебинары
Литература

* OVM *

Содержание


Механика OVM

Библиотека OVM предоставляет много возможностей для построения testbenches. В этой главе мы ознакомимся с наиболее важными возможностями, которые вы будете использовать почти во всех ваши testbenches.

Компоненты и иерархия

Первичная структура для создания элементов testbench является компонента. Компонента в OVM – это аналогия модулю в Verilog. Компонента OVM сконструирована на основе класса, который обеспечивает ему различные характеристики, чем модуль Verilog и имеет различные использования импликаций. Среди таких характеристик является то, что классы создаются во время выполнения, а не во время разработки, как модули. Таким образом, OVM отвечает за создание компонента и сборки их в иерархии.

69.png

Рисунок 4-1 иллюстрирует простую иерархию компонент. После мы покажем, как построить эту иерархию с помощью средств OVM для создания компонент и объединения их в иерархии:


Самый верхний узел, ENV, является корнем. Корень отличается тем, что он не имеет предка. Все остальные узлы имеют только одного предка. Каждый узел имеет имя. Расположение каждого узла в иерархии может быть идентифицировано уникальным full_name (путем), который строится на нанизывании имен всех узлов между корнем и узлов в запросе, разделяя их сепаратором иерархии, точкой (.). Например, путь к компоненту, второго потомка с2 - top.c2.child2.

Компонент в ОВМ является классом, производным от ovm_component. Простейшая компоненты - листья, те, которые не имеют потомков.


57 class child extends ovm_component; 58 59 function new(string name, ovm_component parent); 60 super.new(name, parent); 61 endfunction 62 63 endclass file: 04_OVM_mechanics/01_hierarchy/top.sv


Конструктор имеет два параметра, имя компоненты и указатель на его предка. Название - простое имя, а не иерархический путь. Предок предоставляет место для подключения новой компоненты в иерархии. Полный путь потомка создается путем объединения имени потомка с полным именем предка, разделенный точкой (.).OVM предоставляет методы для получения и имени и полного пути компоненты:


string get_name(); string get_full_name();


Подчиненные компоненты создаются в функции build(), которая вызывается на этапе сборки (фазы объясняется далее в этой главе). Создание экземпляра компонента включает вызов new() для выделения памяти для нее и передачи соответствующих параметров в конструктор. В компоненте, показанной ниже, мы создаем две подчиненные компоненты, и child1 child2.


71 class component extends ovm_component; 72 73 child child1; 74 child child2; 75 76 function new(string name, ovm_component parent); 77 super.new(name, parent); 78 endfunction 79 80 function void build(); 81 child1 = new(“child1”, this); 82 child2 = new(“child2”, this); 83 endfunction 84 85 endclass file: 04_OVM_mechanics/01_hierarchy/top.sv


Как component, ENV также создает экземпляры двух подчиненных компонент, c1 и c2. Вся иерархия с корнем в модуле, называемым top в нашем проекте.(??)


131 module top; 132 133 env e; 134 135 initial begin 136 e = new(“env”); 137 run_test(); 138 end 139 140 endmodule file: 04_OVM_mechanics/01_hierarchy/top.sv

Вызов new() создает верхний уровень окружающей среды. run_test () начинает выполнение testbench.

В SystemVerilog, модули, интерфейсы и программные блоки создаются во время разработки, в то время как классы создаются после разработки, во время выполнения. Таким образом, чтобы создать иерархию классов, мы должны иметь интерфейс, модуль или программу, который содержит начальный блок, который начинает процесс создание компонент иерархии, основанных на классах. Интерфейсы предназначены для использования в качестве средства связи между двумя модулями и не очень хорошо подходят для использования в качестве корня иерархии классов. Программные блоки или модули могут быть использованы как корень (??). Для нашей простой иерархии, это не имеет значения. Позже, когда мы подключаем класс-компонент для модуля на основе аппаратных средств, мы увидим, что использование модуля предпочтительнее программным блокам.

Перемещение по иерархии

Мы можем исследовать структуры данных, используемые для реализации компонента иерархии с некоторыми методами, предусмотренными в ovm_component. Потомки компоненты хранятся в ассоциативном массиве. Этот массив напрямую не доступен, но он может быть доступен через иерархию API. Этот API-интерфейс похож на встроенные методы SystemVerilog, предназначенные для ассоциативных массивов.

int get_first_child(ref string name); int get_next_child(ref string name); ovm_component get_child(string name); int get_num_children();


get_first_child () и get_next_child () работают вместе для перебора множества потомков, содержащихся в компоненте. get_first_child () извлекает имя первого ребенка в списке. Он возвращает имя в качестве ссылки. get_next_child () возвращает имя следующего ребенка в списке. Он возвращает 1, если имеется следующая имя потомка и 0, если был достигнут конец списка. get_child () преобразует имя в ссылку компоненты.

Используя эти функции, мы можем пройти по компонентам иерархии.


73 function void depth_first(ovm_component node, 74 int unsigned level = 0); 75 76 string name; 77 78 if(node == null) 79 return; 80 81 visit(node, level); 82 83 if(node.get_first_child(name)) 84 do begin 85 depth_first(node.get_child(name), level+1); 86 end while(node.get_next_child(name)); 87 88 endfunction file: 04_OVM_mechanics/utils/traverse.svh


Эта функция будет осуществляющая обход в глубину иерархии, называя visit(). Мы используем get_first_child () и get_next_child () для перебора списка каждого потомка в каждом узле. Для каждого итерации мы вызываем depth_first () рекурсивно. Для нашего маленького проекта, результат будет следующий:


+ env | + env.c1 | | env.c1.child1 | | env.c1.child2 | + env.c2 | | env.c2.child1 | | env.c2.child2


Функция visit() использует глубину узла и определяет является ли он конечным для печати строки каждого узла.