OVM/Basic OVM/Session8 - Monitors & Subscribers
Материал из Wiki
Здравствуйте, я Джон Эйнли из компании Дулос. Это восьмое занятие по основам OVM. Его тема - мониторы и подписчики. На этом последнем занятии в данном учебном блоке я собираюсь поговорить о пассивных компонентах в окружении верификации. Роль пассивных компонентов сводится к анализу. Как правило, они решают такие задачи, как проверка и сборка покрытия.
Ранее я уже рассказывал о стандартной структуре агента. А сейчас мы уделим внимание одному из компонентов агента - монитору. Монитор следит за состоянием контактов тестируемого устройства и обычно периодически считывает данные с этих контактов, упаковывает их в транзакцию и отправляет ее другим частям окружения верификации для проверки и сборки покрытия. Вот этим мы сейчас и займемся.
Для распространения транзакции по окружению верификации существует специальный механизм - порт анализа, который существенно упрощает решение этой задачи. Возможно, вам знаком термин порт анализа, это еще одно средство, унаследованное от стандарта SystemC TLM. Порт анализа предназначен для анализа. Иными словами, он служит для распространения транзакций по окружению верификации, например, с целью проверки и сборки покрытия. С технической точки зрения, ключевой особенностью порта анализа служит тот факт, что с ним можно связать сколько угодно так называемых подписчиков: одного, двух, трех, вообще любое количество, в том числе ни одного. При этом каждый подписчик, то есть компонент, зарегистрировавший себя в порту анализа, будет получать копии всех отправленных в этот порт транзакций, которые затем сможет проанализировать. Но поскольку транзакция может быть отправлена сразу нескольким подписчикам, на подписчиков налагается весьма важное ограничение: они не должны модифицировать хранящиеся в транзакции данные, поскольку это исказило бы данные, получаемые другими подписчиками. Посмотрим, как этот механизм работает.
Итак, новое занятие - новый пользовательский класс. На слайде показан класс my_monitor, расширяющий ovm_monitor. Понятно, что этот встроенный компонент предназначен для реализации мониторов. ovm_monitor - еще один пример класса в системе OVM, его поведение фактически идентично поведению ovm_component. Но мы выбрали именно ovm_monitor, а не ovm_component, ради единообразия и чтобы читателю было понятно, что речь идет именно о мониторе. Однако технически с равным успехом можно было бы расширить класс ovm_env или ovm_component.
Зарегистрировав класс с помощью макроса ovm_component_utils, мы объявляем порт анализа - переменную встроенного типа ovm_analysis_port. Это еще один пример параметризованного класса. Создаваемый экземпляр класса ovm_analysis_port, параметризуется типом транзакции которая будет посылаться в данный порт анализа.
Если вы были внимательны на предыдущих занятиях, то, наверное, помните, что в языке SystemVerilog, переменная типа класса содержит описатель, или ссылку на объект, а не сам объект. А объект, то есть сам порт анализа, еще необходимо сконструировать. В данном случае мы для этого явно вызываем метод new порта анализа. Мы уже говорили, что в OVM это рекомендуется делать в методе build, стандартном фазовом методе обратного вызова. Итак, внутри функции build, после вызова super.build, мы записываем aport = new, и передаем конструктору уже знакомые нам стандартные аргументы: имя конструируемого объекта и ссылку на его родителя. В данном случае родителем порта анализа является this, то есть тот самый монитор, с которым мы работаем.
Теперь рассмотрим стандартную задачу run для нашего монитора. Как вы помните, монитор следит за контактами тестируемого устройства, компонует транзакцию, и отправляет ее другим частям окружения верификации. Поэтому он объявляет описатель транзакции, а затем синхронизирует себя с тестируемым устройством, ожидая его синхроимпульса. Затем, на фронте синхроимпульса монитор опрашивает определенные контакты устройства, считывает их значения и записывает их в поля транзакции. А именно транзакции tx, которую мы создаем с помощью уже знакомого вызова фабрики.
Создав фабричным методом транзакцию и заполнив ее поля, монитор отправляет транзакцию в порт анализа, вызывая метод write этого порта. Таким образом, write - это метод, с помощью которого транзакция отправляется всем подписчикам, зарегистрировавшимся в данном порту анализа. В частном случае порта анализа всегда вызывается метод write. То есть write - это встроенный метод, предназначенный специально для портов анализа.
До сих пор все было очень просто. Мы видели, как создать экземпляр порта анализа внутри монитора, как создать простенькую транзакцию и с помощью монитора отправить ее. Итак, сейчас мы имеем транзакцию, которая доставлена в тело нашего агента. Теперь надо понять, как эту транзакцию переправить другим частям окружения верификации. Рекомендуемый способ - передать транзакцию через другой порт анализа - принадлежащий агенту. Получается, что на каждом уровне мы используем порты и экспортеры для взаимодействия через границы иерархии. Сейчас мы увидим, что у агента тоже имеется порт анализа и соединим (или свяжем) порт анализа дочернего модуля, то есть монитора, с портом анализа агента, организовав тем самым соединение родитель-потомок.
Посмотрим, как это выглядит. Этот код вам должен быть уже знаком. На слайде показан определенный пользователем класс агента, расширяющий класс ovm_agent. Объявляем порт анализа ovm_analysis_port, принадлежащий родительскому компоненту, агенту, также параметризованный типом my_transaction.
Не забудем создать экземпляр порта анализа. В данном случае это делает строка aport = new. Создадим также все дочерние компоненты агента: контроллер, драйвер и монитор. Все это делается с помощью уже знакомых вам фабричных методов.
А затем в методе агента connect мы соединяем порт анализа дочернего компонента, монитора, с портом анализа родительского компонента, драйвера: my_monitor_h.aport.connect (aport). Это соединение двух портов анализа: родительского и дочернего.
Теперь перейдем на верхний уровень окружения верификации. Здесь мы имеем класс my_env, описывающий пользовательское окружение. Окружение создает экземпляры двух компонентов верификации: агента и подписчика, который будет получать транзакции, сгенерированные этим агентом. Экземпляры этих компонентов создаются в методе build, а соединение порта анализа агента с портом анализа подписчика осуществляется в методе connect. Мы снова воспользовались методом connect для создания соединения между компонентами, а порт и экспортер являются ссылками на поля агента и подписчика соответственно. В результате оба компонента оказываются связанными.
Теперь для полноты картины взглянем на самого подписчика. На слайде показан пользовательский класс my_subscriber, расширяющий ovm_subscriber. Это последний из классов, производных от ovm_component, с которыми мы встретимся в этом блоке. ovm_subscriber - еще одна разновидность ovm_component, играющая роль подписчика, который соединяется с портом анализа. Особенность подписчика состоит в том, что он обязан реализовать метод write. Иными словами, при написании любого класса, расширяющего ovm_subscriber, вы должны определить в нем метод write. В нижней части слайда мы видим функцию write, принимающую в качестве аргумента транзакцию, которую мы собираемся отправить через данный порт анализа.
Далее нам предстоит реализовать поведение, то есть сам метод write. В данном случае метод write извлекает содержимое транзакции, то есть считывает поля объекта транзакции, копирует их значения в набор регистров покрытия, а затем вызывает метод sample группы покрытия. В данном случае мы пользуемся группами покрытия SystemVerilog для сбора информации о функциональном покрытии, что и является целью этого подписчика, компонента анализа. Но вообще подписчик может протоколировать транзакции, собирать информацию о покрытии, или, быть может, сравнивать фактическое поведение тестируемого устройства с ожидаемым. В данном примере мы просто протоколируем информацию о покрытии, применяя группу покрытия. Существует два ограничения на то, что может делать метод write. Об одном из них я уже говорил. Метод write не должен модифицировать транзакцию. То есть подписчику разрешено только читать транзакцию, но не изменять ее. Кроме того, метод write не должен ни блокировать выполнение, ни потреблять время. Таким образом, метод должен прочитать транзакцию и, не модифицируя ее, тут же вернуть управление.
Однако метод write может сообщить некоторую информацию о транзакции, воспользовавшись стандартными встроенными в OVM средствами отчета. На одном из предыдущих занятий я упоминал об этих средствах. В простейшем виде для формирования отчета используется одна из четырех встроенных функций, в частности ovm_report_info. Таким образом, ovm_report_info - пример использования стандартных средств отчета. Часть info – это один из уровней серьезности сообщения. Поскольку вы, вероятно, знакомы с языками VHDL или Verilog, то не будете удивлены, узнав, что в OVM есть четыре уровня серьезности: info, warning, error и fatal. Поэтому в имени функции часть info можно заменить любой из этих строк. Второй, а точнее первый, аргумент, но вторая из выделенных на данном слайде вещей – это строка, идентифицирующая источник транзакции, известная также под название «идентификатор сообщения». Идея в том, что этот аргумент показывает, кто сгенерировал данное сообщение, откуда оно поступило. Обычно в нем указывается ваше имя или название вашей компании, или название проекта, или любая информация, идентифицирующая данную интеллектуальную собственность. Когда пользователь увидит такое сообщение, он сможет понять, откуда оно взялось. Второй аргумент – это собственно строка сообщения. Она может быть составлена из постоянных или переменных частей и несет содержательную информацию, которую вы хотите донести до пользователя. Но это лишь основа стандартного механизма отчета. На самом деле он настраивается в широких пределах, и вы можете расширить его, запрограммировав действия, выполняемые при вызове ovm_report_info.
На этом занятии я рассмотрел мониторы, порты анализа и поведение подписчиков. И мы подошли к концу этого блока, состоящего из восьми занятий. Подведем итоги. OVM - это библиотека классов, написанных на языке SystemVerilog. Она стандартна. Имеются реализации, работающие с любым из ныне существующих стандартных эмуляторов на SystemVerilog. Ее основная задача - построение повторно используемых, конфигурируемых окружений верификации. Идея в том, чтобы можно было создавать тесты, конкретные тестовые сценарии, которые не являются частью окружения верификации, а отделены от него. Это позволяет повторно использовать одно и то же окружение верификации с различными тестами.
OVM предоставляет также стандартный способ структурирования окружения верификации, или, если угодно, испытательного стенда. Для этого предлагается стандартизированный способ взаимодействия на уровне транзакций. То есть имеются стандартные средства для взаимодействия внутри окружения верификации. Имеется стандартный способ организации окружения верификации в целом и построения компонентов верификации. Много внимания уделено созданию многоуровневых последовательных стимулов, состоящих из последовательностей, о чем я неоднократно упоминал. Отдельные компоненты верификации могут быть представлены в виде повторно используемой интеллектуальной собственности, которую можно распространять и использовать в разных окружениях верификации благодаря наличию средств конфигурирования. Я надеюсь, что изложенная информация оказалась вам полезной. Если вы захотите расширить свои знания, то можете связаться со мной через компанию Дулос или следить за обновлениями на сайте Академии верификации, где сообщается о новых учебных блоках. Благодарю за внимание.