«…лишь недалекие люди боятся конкуренции, а люди подлинного творчества ценят общение с каждым талантом…» А. Бек, Талант.

OVM/Basic OVM/Session7 - Sequences and Tests

Материал из Wiki
< OVM
Версия от 23:24, 21 ноября 2013; ANA (обсуждение | вклад)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск
Проект Диплом

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

* OVM *
Module basic ovm session7 sequences and tests jaynsley.pdf

Это седьмое занятие по основам OVM. Его тема - последовательности и тесты. На нем мы более внимательно рассмотрим последовательности, являющиеся важной частью OVM. Я также покажу, как создавать последовательности в тесте.


Module basic ovm session7 sequences and tests jaynsley.pdf


Ранее я рассказывал о понятии многоуровневого последовательного стимула. Мы видели, что для подачи сигнала на отдельные контакты тестируемого устройства используются транзакции, которые могут быть составлены из последовательностей. Последовательность может состоять как из нескольких индивидуальных транзакций, так и из ряда других последовательностей. Кроме того, последовательность может быть как полностью линейной и детерминированной, так и совершенно случайной. Допустимы и любые вариации между этими двумя крайними случаями. На этом занятии мы приведем примеры каждой из этих ситуаций. Начнем с рассмотрения последовательности транзакций. На предыдущем занятии я показал очень простую последовательность транзакций, а теперь поговорим об ограниченной случайной последовательности транзакций.


Module basic ovm session7 sequences and tests jaynsley.pdf


На этом слайде показан пример уже рассмотренной ранее последовательности, определенной пользователем. Здесь мы видим класс пользовательской последовательности read_modify_write, который расширяет класс ovm_sequence. Как следует из названия, класс read_modify_write выполняет чтение, за которым следует запись. Следовательно, это детерминированная последовательность в том смысле, что состоит из одной операции чтения, сопровождаемой ровно одной операцией записи. Глядя на метод body класса последовательности, стандартного метода для описания поведения последовательности, мы видим, что он начинается с объявления транзакции типа my_transaction, а затем создает транзакцию, применяя фабричный метод, как мы видели раньше. Итак, выделенная жирным шрифтом строка создает транзакцию типа my_transaction, если только ее поведение не переопределено для данного теста, поскольку это фабричный метод. Описатель этой транзакции сохраняется в переменной tx, а затем мы выполняем стандартный набор шагов: запускаем последовательность, производим некоторую рандомизацию и завершаем последовательность. Поскольку речь идет о последовательности read_modify_write, то на шаге рандомизации транзакции мы пользуемся встраиваемым ограничением наряду с командой SystemVerilog randomize, чтобы сделать эту транзакцию действительно транзакцией чтения. Отсюда встраиваемое ограничение, в силу которого команда имеет значение 0, что означает операцию чтение.


Module basic ovm session7 sequences and tests jaynsley.pdf


Далее в методе body мы встречаем следующую часть последовательности read_modify_write, а именно modify. В этом месте мы сохраняем значения фактического адреса и данных из транзакции, которые были рандомизированы на предыдущем шаге. Они записываются в локальные переменные, после чего значение данных модифицируется: в данном примере увеличивается на единицу. Так в нашем случае выглядит шаг модификации. И наконец третья часть последовательности - запись. Мы снова создаем транзакцию, вызываем метод start item, рандомизируем транзакцию и вызываем finish item. На это раз используется другое встраиваемое ограничение, гарантирующее, что это действительно операция записи. Рассмотрим по очереди все атрибуты транзакции. На атрибут command наложено ограничение равенства 1, то есть он полностью детерминирован. Поэтому транзакция будет операцией записи, и мы ничего не оставляем на волю случая. В поле адреса записывается a, то есть адрес из предыдущей транзакции чтения, который был выбран случайным образом. Стало быть, адрес рандомизирован, но в обеих транзакциях, чтения и записи, совпадает. В качестве значения данных используется значение, прочитанное в предыдущей транзакции, а затем модифицированное. Следовательно, данные детерминированы в том смысле, что совпадают с данными, возвращенными предыдущей транзакцией. Итак, хотя в этой транзакции и есть случайный элемент, о котором я еще скажу, она без сомнения является ограниченной случайной транзакцией, то есть находится где-то между двумя крайностями.


Module basic ovm session7 sequences and tests jaynsley.pdf


Это была последовательность read_modify_write. А теперь рассмотрим последовательность последовательностей, для чего создадим еще одну пользовательскую последовательность, sequence_of_commands. Класс sequence_of_commands тоже расширяет ovm_sequence, и мы пишем стандартный трафаретный код: регистрируем последовательность методом ovm_object_utils и объявляем rand-переменную, которую будем использовать для управления работой последовательности. В терминологии случайной верификации с ограничениями такая переменная называется распорядителем (nob). Это управляемый распорядитель, применяемый для управления работой последовательности. Идея в том, что значение этой переменной представляет собой нечто, способное уточнять поведение конкретной последовательности причем само это значение можно ограничить извне. В данном очень простом примере целочисленное поле n определяет количество генерируемых в этой последовательности команд. Двигаясь дальше, мы видим, что последовательность содержит ограничение, и, как я отмечал на предыдущем занятии, очень полезно включать в транзакции и последовательности ограничения по умолчанию, чтобы всем случайным полям гарантированно присваивались разумные начальные значения. Итак, при создании экземпляра такой последовательности и его выполнении количество сгенерированных команд будет находиться в диапазоне от 2 до 4. По умолчанию последовательность команд будет содержать от 2 до 4 последовательностей read_modify_write. Ранее я также отмечал, что ограничения являются мягкими, то есть их всегда можно переопределить. Иными словами, количество последовательностей необязательно должно быть числом от 2 до 4, это просто разумное значение по умолчанию. Далее, раз это класс последовательности, то в нем имеется метод body, который и описывает основное поведение последовательности. Метод body содержит цикл repeat, повторяемый в точности n раз. Таким образом, n действительно равно числу команд, генерируемых в данной последовательности. Значение n можно рандомизировать перед созданием последовательности, а впоследствии оно будет определять количество фактически сгенерированных команд. А внутри цикла мы видим уже знакомый код генерации нового элемента последовательности. Затем мы отправляем этот элемент, вызывая методы start item и finish item. В данном случае элемент последовательности - не транзакция, а другая последовательность. Выше мы видели пример последовательности, генерирующей транзакции, а эта последовательность генерирует новые последовательности. Таким образом, каждый запущенный и завершенный элемент последовательности сам является экземпляром последовательности read_modify_write. То есть эта последовательность генерирует от 2 до 4 команд read_modify_write.


Module basic ovm session7 sequences and tests jaynsley.pdf


Итак, сейчас мы имеем две пользовательские последовательности: read_modify_write и sequence_of_commands. В принципе эти последовательности следовало бы поместить в библиотеку последовательностей. Такая библиотека представляет собой просто собрание последовательностей, которые можно запускать из теста. Библиотека последовательностей есть не что иное, как пакет SystemVerilog. Пакет – это удобный механизм для организации последовательностей. Он позволяет хранить их в одном месте, избегая чрезмерного количества глобальных имен. Здесь мы определили пользовательский пакет my_sequence_library, в котором импортируются все символы из библиотеки OVM, а затем определяются наши собственные последовательности.


Module basic ovm session7 sequences and tests jaynsley.pdf


Итак, мы определили ряд последовательностей, а теперь посмотрим, как запускать их из тестов. Для этого рассмотрим определенный пользователем класс теста. Класс test1 расширяет класс ovm_test, в нем имеется стандартный макрос регистрации, описатель, которым мы воспользуемся для инстанцирования окружения, и стандартный фазовый метод run, выполнение которого и составляет собственно процесс моделирования. В начале этот метод создает экземпляр последовательности read_modify_write. Здесь мы видим уже знакомый вызов фабричного метода. Он создает последовательность read_modify_write, а затем запускает ее, явно вызывая метод start. Синтаксически это записывается в виде seq.start. Последовательность всегда запускается на конкретном контроллере. Поэтому аргумент метода start фактически идентифицирует тот сервер последовательностей, на котором данная последовательность будет работать. В данном случае контроллер идентифицируется своим полным именем в иерархии, my_env_h.my_agent_h.my_sequencer_h. Теперь рассмотрим второй тест. Он очень похож на первый, мы сами решаем, какой из них прогонять. Во втором тесте из библиотеки последовательностей выбирается другой контроллер, тот, что реализует последовательность команд. Мы создаем экземпляр этой последовательности, сохраняем его описатель в переменной seq, а затем рандомизируем последовательность, потому что она не вполне детерминирована. Если помните, в классе sequence_of_commands имеется распорядитель, которым можно манипулировать для задания точного поведения данной последовательности. Последовательность sequence_of_commands генерирует от 2 до 4 команд read_modify_write, а явный вызов метода sequence.randomize рандомизирует последовательность, то есть вычисляет значение переменной n, распорядителя, определяющее, сколько именно команд генерирует данная последовательность. После этого мы, как и раньше, явно запускаем последовательность на конкретном контроллере. Итак, мы рассмотрели примеры запуска двух разных последовательностей. Теперь обратимся к третьему тесту. Предположим, что существующие тесты, даже если завершаются успешно, не дают достаточного покрытия, и мы хотели более точно определить, какие именно последовательности надлежит сгенерировать. Это можно сделать, вмешавшись в процесс с целью задать точное поведение созданной и запущенной последовательности. Поэтому в классе test3 создается новый элемент последовательности, а затем отключается ограничение, включенное в эту последовательность, - с помощью встроенного в SystemVerilog метода constraint_mode. Передача этому методу аргумента 0 в SystemVerilog означает, чтобы ограничение следует отключить. Подразумеваемое по умолчанию ограничение более не действует. Вместо того чтобы применять ограничение по умолчанию, мы устанавливаем явное встраиваемое ограничение, указав, что распорядитель последовательности должен лежать в диапазоне от 10 до 20. В результате генерируется больше команд read_modify_write с целью подвергнуть тестируемое устройство более жесткому испытанию. Теперь мы имеем тест, который вручную ограничивает точное поведение данного ограниченного случайного стимула в момент запуска контроллера. Итак, я продемонстрировал, как можно написать несколько тестов таким образом, что каждый будет запускать разные последовательности, а заодно как можно настраивать точное поведение этих последовательностей.


Теперь посмотрим, как выбирается конкретный тест для прогона. Простейший способ мы уже видели: нужно просто указать имя теста в команде run_test. Здесь мы вызываем встроенную функцию run_test и задаем имя теста, который хотим прогнать. Ничего сложного. Другой способ позволяет обойтись без указания имени теста в качестве аргумент run_test. Этот аргумент можно опустить, а имя теста задать в командной строке. Тогда в момент запуска модели SystemVerilog мы можем указать имя теста в виде аргумента командной строки. К счастью, компании Cadence и Mentor договорились о стандартном имени флага Verilog, используемого в качестве плюс-аргумента для этой цели: ovm_testname. Таким образом, запись ovm testname равно test3 позволяет задать тест в командной строке без повторной компиляции и настройки кода SystemVerilog.


Подведем итог. На этом занятии я подробнее рассказал о создании последовательностей и о том, как выбирать конкретную последовательность для запуска. Вы также видели, как тесты позволяют без труда модифицировать окружение верификации с целью точной настройки его поведения.