OVM/Basic OVM/Session5 - Connecting Components — различия между версиями
ANA (обсуждение | вклад) (Новая страница: «{{OVM TOC}} 600px Здравствуйте, я Джон Эйнли из компан…») |
ANA (обсуждение | вклад) м |
||
Строка 1: | Строка 1: | ||
{{OVM TOC}} | {{OVM TOC}} | ||
− | [[file:module_basic_ovm_session5_connecting_components_jaynsley.pdf| | + | [[file:module_basic_ovm_session5_connecting_components_jaynsley.pdf|page=1|600px]] |
Здравствуйте, я Джон Эйнли | Здравствуйте, я Джон Эйнли |
Версия 19:07, 21 ноября 2013
Здравствуйте, я Джон Эйнли из компании Дулос.
Это пятое занятие по основам 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-порта заводится отдельный агент. И так далее.
Окружение верификации, как правило, содержит несколько агентов,
по одному для каждого из основных интерфейсов тестируемого устройства.
А, помимо них, существуют другие компоненты верификации, задача которых -
координировать и суммировать действия всех агентов.