«Бог не меняет того, что (происходит) с людьми, пока они сами не изменят своих помыслов.» Коран, Сура 12:13

OVM/Basic OVM/Session5 - Connecting Components

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

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

* OVM *

Module basic ovm session5 connecting components jaynsley.pdf

Здравствуйте, я Джон Эйнли из компании Дулос.

Это пятое занятие по основам OVM. Его тема - соединение компонентов.

Мы познакомимся с тем, как создавать

несколько компонентов OVM в окружении верификации

и как собирать их воедино. Также мы

подробнее рассмотрим архитектуру отдельного компонента.

На предыдущем занятии я говорил,


что типичный компонент OVM


состоит из контроллера, драйвера и монитора.

Идея в том, чтобы использовать компонент как стандартный строительный блок

в окружении верификации OVM.

Такая конфигурация компонентов называется агентом.

Эта структура не является единственно возможной.

Вы не обязаны строить окружение верификации

исключительно из агентов с такой структурой,

однако это неплохая отправная точка, позволяющая обеспечить стандартизацию

и согласованность между компонентами верификации из различных источников.

Поэтому при обсуждении создания и соединения компонентов будет

разумно использовать описанную структуру агентов в качестве примера, отправной точки.

И именно так мы сейчас и поступим.

Я уже неоднократно упоминал компоненты OVM,

и теперь самое время взглянуть на формальную иерархию классов OVM.

Здесь мы вступаем на территорию объектно-ориентированного программирования.

На слайде представлена диаграмма иерархии классов

в обозначениях, немного напоминающих язык UML.

Классы, изображенные ниже, расширяют, или наследуют тем,

что изображены выше.

Внутри широкой рамки в нижней части диаграммы

показаны все виды компонентов OVM.

Они применяются для описания структуры. В OVM имеется много классов,

причем все они наследуют единственному базовому классу ovm_component, который

в свою очередь является производным от класса ovm_report_object, а тот - от класса ovm_object,

с которым мы встречались на предыдущем занятии.

В нижней части диаграммы мы видим различные компоненты OVM,

в частности ovm_env для уже знакомого нам ovm_test,

а также такие компоненты, как ovm_agent и ovm_driver.

Позже мы узнаем, что некоторые из компонентов полностью взаимозаменяемы

и отличаются только названиями.

Но есть также компоненты с уникальными свойствами,

присущими только им.

Во многих случаях у вас есть выбор.

Например, можно воспользоваться как ovm_env, так и ovm component.

А это означает, что выбор того или иного компонента OVM -

вопрос стиля кодирования и единообразия, а не технической необходимости.

Тем не менее, на данном занятии

я буду выбирать подходящий тип компонента

исходя из той роли, которую он играет.

Стало быть, в данном случае мы возьмем компонент ovm_agent.

Итак, создадим определенный пользователем компонент верификации,

расширив базовый класс ovm_agent.

Однако подчеркну еще раз: я мог бы расширить ovm_component,

или даже ovm_monitor или ovm_env, и в данном случае получился бы

точно такой же результат.

Итак, в строке 2 мы регистрируем my_agent как ovm_component.

Это стандартный код, который следует включать обязательно.

Впоследствии агент будет создавать экземпляры контроллера и драйвера,

поэтому мы объявляем в классе два описателя: my_sequencer_h и

my_driver_h.

Далее следует метод new, конструктор класса,

и стандартные методы, build и connect.

С методом build мы уже встречались ранее, а метод connect для нас внове.

Он служит для соединения дочерних компонентов,

и чуть позже я подробнее объясню, как он работает.

Однако начнем с расширения метода build.

Сначала метод build, как обычно, вызывает метод базового класса super.build,

а затем создает экземпляры контроллера и драйвера,

с помощью волшебного заклинания type_id::create.

Передаваемые методу create аргументы очень важны.

Первый аргумент, как и раньше, это имя экземпляра,

которое должно совпадать с именем переменной.

Второй аргумент – родитель, мы всегда будем использовать в этом качестве "this",

встроенную в SystemVerilog переменную, которая обозначает текущий объект,

с которым мы работаем.

В объектно-ориентированной терминологии метод create называется фабричным. Фабричные методы -

это один из так называемых паттернов объектно-ориентированного программирования,

то есть заведомо хороших способов решить определенную задачу.

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

и в то же время переопределить тип объекта,

создаваемого где-то в другом месте.

На первый взгляд кажется, что здесь мы создаем

объекты типа my_sequencer и my_driver,

и по умолчанию так оно и есть.

Однако имеется возможность переопределить типы компонентов, создаваемых

этими фабричными методами.

Так, в каком-то конкретном тесте, не изменяя исходный код

данного конкретного агента ни на йоту,

мы могли бы переопределить поведение фабричных методов,

заставив их создавать иные компоненты, последовательности или драйверы.

С помощью этого механизма мы можем настраивать поведение

того или иного компонента верификации в конкретном тесте:

А. не изменяя ни единой строки кода

и Б. не заставляя автора компонента верификации

предвидеть все возможные модификации. Ему достаточно просто

воспользоваться фабричным методом.

Так что это весьма полезный механизм.

Мы рассмотрели метод build, применяемый для конструирования

компонентов в окружении верификации.

Далее идет метод connect,

который служит для соединения компонентов более низкого уровня между собой.

В данном случае соединяются драйвер и контроллер.

Как видите, метод connect агента вызывает метод connect драйвера,

чтобы соединить оба компонента нижнего уровня.

Сам код соединения – это обычный исполняемый код.

Технически его можно было бы включить в метод build,

и все работало бы точно так же.

Однако стилистически правильнее и настоятельно рекомендуется

размещать код соединения компонентов нижнего уровня

в теле метода connect, хотя бы из соображений единообразия.

Взглянув на код метода connect более пристально,

вы увидите ссылки на два выделенных жирным шрифтом компонента:

sequence_item_port и sequence_item_export.

Понятия порта и экспортера - выходцы из мира моделирования на уровне транзакций.

Они заимствованы из стандарта System C TLM.

В данном контексте можно считать, что порты и экспортеры – это просто описатели

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

Итак, чтобы связать драйвер с контроллером,

мы берем описатель драйвера, sequence_item_port,

описатель контроллера, sequence_item_export,

и соединяем их, устанавливая соединение

между контролем и драйвером.

Можете считать, что эти порты уровня транзакций

- своеобразные вариации на тему портов в системах Verilog или VHDL.

На самом деле, они не полностью эквивалентны портам VHDL или Verilog,

но, если смотреть с высоты птичьего полета, то выполняют они ту же функцию

соединения между собой деталей внутреннего устройства отдельных компонентов.

Итак, я познакомил вас с методами build и connect,

которые в OVM называются фазовыми методами.

А теперь я опишу сами фазы OVM более формально.

Идея в том, что каждый компонент в иерархии верификации

должен сконструировать свои дочерние компоненты

и должен обладать неким основным поведением, выполняемым в ходе моделирования.

Кроме того, он может выполнять какие-то служебные функции: открывать файлы,

выводить результаты и так далее.

Поэтому действия всех компонентов верификации в процессе моделирования

необходимо координировать.

Именно для этого и предназначены стандартные фазы OVM.

Каждый компонент выполняет стандартный набор фаз.

Этот механизм позволяет координировать

поведение всех компонентов, входящих в иерархию верификации.

Давайте рассмотрим пример.

Мы создадим пользовательский класс my_component,

расширяющий базовый класс ovm_component.

Как вы, наверное, помните, класс ovm_component является базовым

для целого семейства различных классов компонентов. Обычно

выбирается какой-то конкретный класс, скажем ovm_agent, ovm_driver или ovm_monitor,

который отражает ваше намерение. Но технически вполне допустимо

создавать пользовательский класс, расширяя ovm_component.

В данном примере мы так и поступим.

Кое-что из показанного в этом примере мы уже видели раньше. Начинаем с метода new.

Метод new, строго говоря, не является фазой,

это просто конструктор, часть языка SystemVerilog.

Но для удобства можете считать, что это фаза 0.

Как правило, в OVM метод new не должен делать

ничего, кроме вызова метода new базового класса.

Далее идет метод build, который мы начали писать ранее. Он создает

дочерние компоненты.

Как я уже отмечал, методы new и build должны вызывать соответственно методы new и build

базового класса.

Таким образом, оба метода new и build вызываются в порядке строго сверху вниз,

то есть начиная с уровня окружения верификации вглубь.

Пока вы еще не освоились с OVM более основательно,

очень важно помнить, что компоненты

в окружении верификации строятся сверху вниз.

Напротив, все остальные фазовые методы вызываются снизу вверх.

Следующей стандартной фазой (необязательной) является фаза соединения,

на которой соединяются порты и экспортеры дочерних компонентов,

а точнее их виртуальные интерфейсы.

Методы connect вызываются снизу вверх,

начиная с компонентов верификации самого нижнего уровня.

Затем идет стандартная фаза start_of_simulation,

которая,

как следует из названия, вызывается в начале моделирования.

Название этой фазы заимствовано

из системы System C.

В System C имеется аналогичный обратный вызов, выполняемый в начале моделирования,

и называется он точно так же: start_of_simulation.

Обычно на этой фазе производятся такие служебные операции,

как открытие файлов для чтения или записи в процессе моделирования.

Затем начинается само моделирование, оно выполняется на фазе run,

и, как мы видели раньше, run - это единственная задача.

В Verilog задача, конечно, может быть продолжительной,

выполнять обработчики событий, расходуя на это модельное время.

За фазой run

следуют еще две фазы, предназначенные для выполнения

служебных операций в самом конце моделирования.

На слайде показана фаза report,

на которой можно вывести отчет о результатах

после того как собственно моделирование завершилось.

Таким образом, фазовые методы позволяют координировать и синхронизировать

действия разнообразных компонентов, находящихся на разных уровнях

иерархии верификации.

Резюмируем все, что мы узнали об анатомии компонента OVM.

Компания Mentor настоятельно рекомендует при написании компонента OVM

располагать его элементы в порядке, показанном на данном слайде.

Так, во второй строке мы всегда регистрируем компонент

в библиотеке классов OVM. Затем объявляются все внешние интерфейсы,

включая как виртуальные интерфейсы,

так и порты и экспортеры, если их необходимо объявить явно.

Далее идут объявления описателей внутренних компонентов,

в данном случае контроллера и драйвера.

И потом все стандартные фазовые методы в надлежащем порядке:

сначала конструктор, за ним собственно фазы,

build, connect и так далее.

Итак, на этом занятии я объяснил, как создавать

экземпляры нескольких компонентов в иерархии верификации.

Мы видели, что использование фабричных методов позволяет создавать

компоненты так, чтобы в отдельных тестах один компонент можно было подменить другим.

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

действий нескольких компонентов.

А также что OVM предписывает способ структурирования

компонентов верификации

с тем, чтобы повысить степень их повторного использования,

а также поддержать единый стиль кодирования.

Мы познакомились с типичной структурой: имеется так называемый агент,

который состоит из контроллера, драйвера и монитора,

а окружение верификации обычно содержит несколько агентов.

Как правило, один агент представляет один коммуникационный канал, шину или порт

в тестируемом устройстве.

Например, если в тестируемом устройстве имеется шина Amber,

то в качестве ее формирователя мог бы выступать агент Amber.

Если имеется USB-соединение, то для USB-порта заводится отдельный агент. И так далее.

Окружение верификации, как правило, содержит несколько агентов,

по одному для каждого из основных интерфейсов тестируемого устройства.

А, помимо них, существуют другие компоненты верификации, задача которых -

координировать и суммировать действия всех агентов.