«…Труд избавляет человека от трех великих зол: скуки, порока, нужды…»

OVM/Basic OVM/Session6 - Introducing Transactions — различия между версиями

Материал из Wiki
< OVM
Перейти к: навигация, поиск
(Новая страница: «{{OVM TOC}} 600px Здравствуйте, я Джон Эйнсли из ком…»)
 
 
(не показаны 2 промежуточные версии 2 участников)
Строка 1: Строка 1:
 
{{OVM TOC}}
 
{{OVM TOC}}
  
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page1|600px]]
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=1|600px]]
  
 +
Здравствуйте, я Джон Эйнсли из компании Дулос. Это шестое занятие по основам OVM,
 +
посвященное введению в транзакции. Я хочу познакомить вас с тем, как
 +
писать транзакции в OVM, но фактически транзакциями мы
 +
не ограничимся, предстоит обсудить также последовательности,
 +
представляющие собой компоненты OVM, которые генерируют транзакции,
 +
а также драйверы - компоненты, которые принимают транзакции
 +
и преобразуют их в сигналы на контактах тестируемого устройства.
  
Здравствуйте, я Джон Эйнсли
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=2|600px]]
из компании Дулос.
+
  
Это шестое занятие по основам OVM,
+
На предыдущем занятии мы рассматривали структуру типичного компонента верификации
посвященное введению в транзакции.
+
и видели, что он состоит из контроллера, драйвера и монитора.
 +
Сейчас нас будет интересовать главным образом взаимодействие между
 +
контроллером и драйвером. Драйвер должен подавать сигналы на контакты
 +
тестируемого устройства, однако взаимодействие между контроллером
 +
и драйвером происходит в виде передачи транзакций, или
 +
абстрактных команд. Каждая транзакция – это отправляемая
 +
контроллером драйверу команда подвергнуть тестируемое устройство
 +
тому или иному воздействию. Весь смысл моделирования на
 +
уровне транзакций сводится к формальному представлению этого
 +
взаимодействия в виде отдельных транзакций с очень четко
 +
определенной структурой. Именно этим мы и займемся.
  
Я хочу познакомить вас с тем, как
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=3|600px]]
писать транзакции в OVM,
+
  
но фактически транзакциями мы
+
Но сначала покажем, какое место в этой картине занимает иерархия классов OVM,
не ограничимся,
+
с которой мы познакомились на предыдущем занятии.
 +
Мы видели, что в OVM имеется целое иерархически организованное семейство классов
 +
для описания компонентов, то есть структурных элементов.
 +
Имеется также параллельная иерархия классов для описания транзакций, или данных.
 +
Базовым для всех транзакций является класс ovm_transaction. Последовательность,
 +
строго говоря, представляется классом, производным от ovm_sequence_item.
 +
Таким образом, класс ovm_sequence расширяет ovm_sequence_item, который
 +
в свою очередь расширяет ovm_transaction, ну а тот расширяет ovm_object.
 +
Транзакции и последовательности - это данные в противоположность компонентам, которые суть
 +
элементы структуры. Транзакции не являются частью иерархии компонентов.
 +
Если у компонента OVM обычно имеется родительский компонент,
 +
то у транзакций, передаваемых от одного компонента другому, родителей нет.
  
предстоит обсудить также
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=4|600px]]
последовательности,
+
  
представляющие собой компоненты OVM,
+
Давайте посмотрим, как можно определить в OVM свою транзакцию.
которые генерируют транзакции,
+
Мы создадим пользовательский класс my_transaction, расширяющий ovm_sequence_item.
 +
Отметим, что мы расширяем класс ovm_sequence_item, а не ovm_transaction,
 +
потому что создаваемая транзакция, скорее всего, будет
 +
частью последовательности. Наследование от ovm_sequence_item
 +
вместо ovm_transaction как раз и позволяет транзакции быть частью последовательности.
 +
Поэтому в общем случае классы транзакций следует создавать путем расширения ovm_sequence_item.
  
а также драйверы - компоненты,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=5|600px]]
которые принимают транзакции
+
  
и преобразуют их в сигналы на
+
Во второй строке нашего класса мы регистрируем его в качестве транзакции,
контактах тестируемого устройства.
+
применяя еще один стандартный макрос OVM. Обратите внимание, что мы используем
 +
ovm_object_utils, а не ovm_component_utils. Мы встречались с двумя стандартными макросами
 +
для регистрации классов:ovm_component_utils и ovm_object_utils.
 +
Крайне важно использовать правильный макрос.
  
На предыдущем занятии мы рассматривали
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=6|600px]]
структуру типичного компонента верификации
+
  
и видели, что он состоит из контроллера,
+
Далее идут поля - свойства транзакции. В данном случае транзакция содержит
драйвера и монитора.
+
команду, адрес и данные. Они и составляют свойства класса. Объявлению каждого свойства
 
+
предшествует ключевое слово rand. В языке SystemVerilog слово rand
Сейчас нас будет интересовать главным
+
означает, что после создания и рандомизации экземпляра данного класса
образом взаимодействие между
+
значения объявленных таким образом свойств будут случайными. И это правильно, потому что мы
 
+
собираемся использовать сгенерированные транзакции как стимулы
контроллером и драйвером.
+
для подачи на входы тестируемого устройства. Наконец, после объявления
 
+
свойств мы видим первый пример ограничений SystemVerilog.
Драйвер должен подавать сигналы
+
Настоятельно рекомендуется включать такие ограничения в
на контакты
+
определение транзакции,чтобы ее свойства гарантированно
 
+
имели осмысленные значения по умолчанию.Тогда, что бы ни происходило в
тестируемого устройства,
+
конкретных тестах, если мы сгенерируем экземпляр класса
 
+
my_transaction по умолчанию, что мы и собираемся сделать, наличие
однако взаимодействие между контроллером
+
ограничений дает уверенность, что свойства такого экземпляра будут иметь разумные значения.
и драйвером происходит
+
Мы задали ограничения так, чтобы адрес и данные находились в допустимом диапазоне.
 
+
Касательно ограничений стоит сделать одно важное замечание:
в виде передачи транзакций, или
+
поскольку это ограничения, а не процедурный код,
абстрактных команд.
+
впоследствии их можно будет переопределить. Стало быть, ограничения по природе
 
+
своей не жесткие, вы всегда можете изменить решение.
Каждая транзакция – это отправляемая
+
Пока что мы сказали, что адрес лежит в диапазоне от 0 до 256,
контроллером драйверу команда
+
и, значит, обычно он будет принадлежать этому диапазону.
 
+
Но позже, если возникнет такая необходимость, мы сможем переопределить это ограничение,
подвергнуть тестируемое устройство
+
тому или иному воздействию.
+
 
+
Весь смысл моделирования на
+
уровне транзакций
+
 
+
сводится к формальному представлению этого
+
взаимодействия
+
 
+
в виде отдельных транзакций с очень четко
+
определенной структурой.
+
 
+
Именно этим мы и займемся.
+
 
+
Но сначала покажем, какое место в этой картине
+
занимает иерархия классов OVM,
+
 
+
с которой мы познакомились на
+
предыдущем занятии.
+
 
+
Мы видели, что в OVM имеется целое иерархически
+
организованное семейство классов
+
 
+
для описания компонентов, то есть структурных
+
элементов.
+
 
+
Имеется также параллельная иерархия классов
+
для описания транзакций, или данных.
+
 
+
Базовым для всех транзакций является класс
+
ovm_transaction. Последовательность,
+
 
+
строго говоря, представляется
+
классом, производным от ovm_sequence_item.
+
 
+
Таким образом, класс ovm_sequence расширяет
+
ovm_sequence_item, который
+
 
+
в свою очередь расширяет ovm_transaction,
+
ну а тот расширяет ovm_object.
+
 
+
Транзакции и последовательности - это данные в
+
противоположность компонентам, которые суть
+
 
+
элементы структуры. Транзакции не являются
+
частью иерархии компонентов.
+
 
+
Если у компонента OVM обычно имеется
+
родительский компонент,
+
 
+
то у транзакций, передаваемых от одного
+
компонента другому,
+
 
+
родителей нет.
+
 
+
Давайте посмотрим, как можно
+
определить в OVM свою транзакцию.
+
 
+
Мы создадим пользовательский класс
+
my_transaction,
+
 
+
расширяющий ovm_sequence_item.
+
 
+
Отметим, что мы расширяем класс
+
ovm_sequence_item,
+
 
+
а не ovm_transaction,
+
 
+
потому что
+
 
+
создаваемая транзакция, скорее всего,
+
будет
+
 
+
частью последовательности.
+
 
+
Наследование от ovm_sequence_item
+
вместо ovm_transaction
+
 
+
как раз и позволяет транзакции
+
быть частью последовательности.
+
 
+
Поэтому в общем случае классы транзакций
+
следует создавать
+
 
+
путем расширения ovm_sequence_item.
+
 
+
Во второй строке нашего класса
+
мы регистрируем его в качестве транзакции,
+
 
+
применяя еще один стандартный макрос OVM.
+
 
+
Обратите внимание, что мы используем
+
ovm_object_utils, а не ovm_component_utils.
+
 
+
Мы встречались с двумя стандартными макросами
+
для регистрации классов:
+
 
+
ovm_component_utils
+
и ovm_object_utils.
+
 
+
Крайне важно использовать правильный
+
макрос.
+
 
+
Далее идут поля -
+
свойства транзакции.
+
 
+
В данном случае транзакция содержит
+
команду, адрес и данные.
+
 
+
Они и составляют свойства класса.
+
 
+
Объявлению каждого свойства
+
предшествует ключевое слово rand.
+
 
+
В языке SystemVerilog слово rand
+
означает,
+
 
+
что после создания и рандомизации
+
экземпляра данного класса
+
 
+
значения объявленных таким образом
+
свойств будут случайными.
+
 
+
И это правильно, потому что мы
+
собираемся использовать
+
 
+
сгенерированные транзакции как стимулы
+
для подачи на входы тестируемого устройства.
+
 
+
Наконец, после объявления
+
свойств
+
 
+
мы видим первый пример
+
ограничений SystemVerilog.
+
 
+
Настоятельно рекомендуется
+
 
+
включать такие ограничения в
+
определение транзакции,
+
 
+
чтобы ее свойства гарантированно
+
 
+
имели осмысленные значения по умолчанию.
+
 
+
Тогда, что бы ни происходило в
+
конкретных тестах,
+
 
+
если мы сгенерируем экземпляр класса
+
my_transaction по умолчанию,
+
 
+
что мы и собираемся сделать, наличие
+
ограничений
+
 
+
дает уверенность, что свойства такого
+
экземпляра будут иметь разумные значения.
+
 
+
Мы задали ограничения так, чтобы
+
адрес и данные
+
 
+
находились в допустимом диапазоне.
+
 
+
Касательно ограничений стоит сделать
+
одно важное замечание:
+
 
+
поскольку это ограничения, а не
+
процедурный код,
+
 
+
впоследствии их можно будет
+
переопределить.
+
 
+
Стало быть, ограничения по природе
+
своей не жесткие,
+
 
+
вы всегда можете изменить
+
решение.
+
 
+
Пока что мы сказали, что
+
адрес лежит в диапазоне от 0 до 256,
+
 
+
и, значит, обычно он будет
+
принадлежать этому диапазону.
+
 
+
Но позже, если возникнет такая
+
необходимость,
+
 
+
мы сможем переопределить это ограничение,
+
 
заменив его чем-то совершенно иным.
 
заменив его чем-то совершенно иным.
  
Далее следует конструктор,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=7|600px]]
как во всяком пользовательском классе.
+
  
У любого класса в языке SystemVerilog
+
Далее следует конструктор, как во всяком пользовательском классе.
должен быть конструктор,
+
У любого класса в языке SystemVerilog должен быть конструктор,
 +
и здесь мы включили в конструктор типичный трафаретный код.
 +
Однако отметим, что этот конструктор несколько отличается
 +
от конструктора класса, производного от ovm_component. Поскольку транзакция не является частью
 +
иерархии компонентов, у нее нет родительского компонента.
 +
Поэтому у конструктора отсутствует второй аргумент, parent.
 +
Это, конечно, очень простая транзакция, но ее уже достаточно для работы.
  
и здесь мы включили в конструктор
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=8|600px]]
типичный трафаретный код.
+
  
Однако отметим, что этот конструктор
+
Итак, транзакцию мы определили, теперь перейдем к контроллеру.
несколько отличается
+
Контроллер - это стандартный компонент OVM, задача которого – генерировать
 +
случайную последовательность транзакций.
  
от конструктора класса, производного
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=9|600px]]
от ovm_component.
+
  
Поскольку транзакция не является частью
+
Для создания контроллера мы определим пользовательский
иерархии компонентов,
+
класс, расширяющий ovm_sequencer - еще один базовый класс из
 +
библиотеки OVM.
  
у нее нет родительского компонента.
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=10|600px]]
  
Поэтому у конструктора отсутствует второй
+
ovm_sequencer - это пример параметризованного класса в
аргумент, parent.
+
SystemVerilog. Для тех, кто знаком с объектно-ориентированным
 +
программированием, скажу, что параметризованные классы в
 +
SystemVerilog похожи на шаблоны классов в C++. Параметризованный класс позволяет
 +
модифицировать некоторые свойства класса SystemVerilog в момент его создания.
 +
В данном случае при инстанцировании класса ovm_sequencer
 +
мы задаем вид транзакции, генерируемой этим контроллером.
 +
Таким образом, класс my_sequencer расширяет ovm_sequencer с целью генерировать транзакции
 +
типа my_transaction.  
  
Это, конечно, очень простая транзакция,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=11|600px]]
но ее уже достаточно для работы.
+
  
Итак, транзакцию мы определили, теперь
+
Поскольку этот класс - стандартный компонент OVM,его код должен следовать стандарту написания
перейдем к контроллеру.
+
компонентов.Мы регистрируем компонент макросом ovm_component_utils
 +
и включаем стандартный конструктор. Больше ничего не требуется.
 +
Это очень простой контроллер и тем не менее в него встроена возможность
 +
генерировать последовательность транзакций. Далее мы увидим, как можно заставить
 +
контроллер делать то, что нам нужно в этом конкретном случае.
  
Контроллер - это стандартный компонент
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=12|600px]]
OVM, задача которого – генерировать
+
  
случайную последовательность транзакций.
+
Мы изменяем контроллер так, чтобы он производил нужные нам действия,
 +
запуская на нем последовательность. В этом месте терминология OVM
 +
становится несколько путаной. На предыдущем слайде был показан класс
 +
ovm_sequencer с буквой r в конце. А теперь мы встречаем класс ovm_sequence.
 +
Напомним, что контроллер (sequencer) - это компонент, структурный элемент, принадлежащий
 +
иерархии компонентов. С другой стороны, последовательность (sequence)
 +
- это класс, расширяющий ovm_transaction. Последовательность состоит из данных,
 +
динамически изменяющихся во времени. Последовательность запускается на контроллере.
 +
На данном слайде показана определенная пользователем последовательность my_sequence.
 +
Она расширяет базовый класс ovm_sequence - еще один пример параметризованного класса.
 +
Он параметризуется типом транзакций, из которых составлена последовательность.
 +
Последовательность ovm_sequence всегда состоит из транзакций.
 +
То есть последовательность - это на самом деле последовательность транзакций.
  
Для создания контроллера мы определим
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=13|600px]]
пользовательский класс, расширяющий
+
  
ovm_sequencer - еще один базовый класс из
+
Ну а далее идет стандартный код. Мы должны зарегистрировать последовательность
библиотеки OVM.
+
с помощью макроса ovm_object_utils. У последовательности имеется стандартный
 +
конструктор. А теперь более интересная часть - у последовательности есть метод body.
  
ovm_sequencer - это пример параметризованного
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=14|600px]]
класса в SystemVerilog.
+
  
Для тех, кто знаком с объектно-ориентированным
+
С этим мы еще не сталкивались. Весь содержательный код, описывающий фактическое поведение
программированием,
+
последовательности, должен находиться в определяемой пользователем
 +
задаче body. В каком-то смысле метод body аналогичен
 +
фазовым методам, хотя и не принадлежит к числу стандартных фаз OVM.
 +
Метод body применяется только в последовательностях
 +
и определяет существенное поведение последовательности.
  
скажу, что параметризованные классы в
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=15|600px]]
SystemVerilog похожи на шаблоны классов в C++.
+
  
Параметризованный класс позволяет
+
Он исполняется, когда последовательность запускается.
модифицировать некоторые свойства класса
+
Посмотрим, как выглядит метод body для данной конкретной последовательности.
 +
На слайде показана задача body. Как видите, она содержит бесконечный цикл.
 +
Значит, после запуска эта последовательность будет генерировать непрерывный поток
 +
транзакций, который можно остановить, только принудительно завершив моделирование,
 +
например, путем вызова метода stop_request. Ничто не может помешать вам
 +
создать последовательность, содержащую бесконечный цикл,
 +
которая, следовательно, будет генерировать непрерывный поток транзакций. Но можно
 +
вместо этого создать последовательность, которая работает конечное время, а потом
 +
останавливается. Оба решения имеют полное право на существование,
 +
нужно лишь понять, какое из них лучше отвечает имеющейся задаче верификации.
 +
В данном случае последовательность будет генерировать непрерывный поток
 +
транзакций, пока мы не прекратим моделирование.
  
SystemVerilog в момент его создания.
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=16|600px]]
  
В данном случае при инстанцировании
+
Внутри цикла, чтобы сгенерировать очередную транзакцию
класса ovm_sequencer
+
в данной последовательности, необходимо выполнить несколько
 +
стандартных шагов. Первым делом мы создаем объект транзакции,
 +
для чего в очередной раз прибегаем к использованию фабричного метода.
 +
Раньше я говорил о фабричных методах в контексте создания компонентов.
 +
Сейчас же мы применяем фабричный метод create для создания экземпляра транзакции.
 +
Но идея та же самая. На первый взгляд кажется, что создается
 +
транзакция типа my_transaction, но, поскольку это фабричный метод, в
 +
тесте есть возможность переопределить тип фактически генерируемой
 +
транзакции. Следовательно, в конкретном тесте можно
 +
динамически изменить последовательность, так что она будет генерировать транзакции
 +
другого типа. Технически между этим методом и фабричным
 +
методом для генерации компонентов есть только одно различие:
 +
в данном случае методу create не передается второй аргумент, определяющий родителя,
 +
поскольку никакого родителя у транзакции не существует.
  
мы задаем вид транзакции, генерируемой
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=17|600px]]
этим контроллером.
+
  
Таким образом, класс my_sequencer расширяет
+
Это был первый шаг - создание транзакции. Последующие шаги со второго по четвертый
ovm_sequencer с целью генерировать транзакции
+
составляют стандартный шаблон кода. На шаге 2 вызывается метод start_item,
 +
на шаге 3 транзакция рандомизируется, а на шаге 4 вызывается метод finish item.
 +
Итак, мы создаем транзакцию, сигнализируем инфраструктуре, что начинаем
 +
процесс ее обработки, рандомизируем объект транзакции и вызываем finsh_transaction,
 +
сообщая о том, что обработка закончена. Методы start_item и finish_item
 +
запускают внутренние механизмы взаимодействия с драйвером,
 +
который будет потребителем данной транзакции.
  
типа my_transaction.
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=18|600px]]
 
+
Поскольку этот класс - стандартный
+
компонент OVM,
+
 
+
его код должен следовать стандарту написания
+
компонентов.
+
 
+
Мы регистрируем компонент макросом
+
ovm_component_utils
+
 
+
и включаем стандартный конструктор.
+
 
+
Больше ничего не требуется.
+
 
+
Это очень простой контроллер и тем
+
не менее в него встроена возможность
+
 
+
генерировать
+
последовательность транзакций.
+
 
+
Далее мы увидим, как можно заставить
+
контроллер делать то, что нам нужно
+
 
+
в этом конкретном случае.
+
 
+
Мы изменяем контроллер так,
+
чтобы он производил нужные нам действия,
+
 
+
запуская на нем последовательность.
+
 
+
В этом месте терминология OVM
+
становится несколько путаной.
+
 
+
На предыдущем слайде был показан класс
+
ovm_sequencer с буквой r в конце.
+
 
+
А теперь мы встречаем класс ovm_sequence.
+
 
+
Напомним, что контроллер (sequencer) - это
+
компонент, структурный элемент, принадлежащий
+
 
+
иерархии компонентов.
+
 
+
С другой стороны, последовательность (sequence)
+
- это класс, расширяющий ovm_transaction.
+
 
+
Последовательность состоит из данных,
+
динамически изменяющихся во времени.
+
 
+
Последовательность запускается на контроллере.
+
 
+
На данном слайде показана определенная
+
пользователем последовательность my_sequence.
+
 
+
Она расширяет базовый класс ovm_sequence -
+
еще один пример параметризованного класса.
+
 
+
Он параметризуется типом транзакций, из
+
которых составлена последовательность.
+
 
+
Последовательность ovm_sequence всегда
+
состоит из транзакций.
+
 
+
То есть последовательность - это на самом деле
+
последовательность транзакций.
+
 
+
Ну а далее идет стандартный код.
+
Мы должны зарегистрировать последовательность
+
 
+
с помощью макроса ovm_object_utils.
+
 
+
У последовательности имеется стандартный
+
конструктор.
+
 
+
А теперь более интересная часть -
+
у последовательности есть метод body.
+
 
+
С этим мы еще не сталкивались.
+
 
+
Весь содержательный код,
+
 
+
описывающий фактическое поведение
+
последовательности,
+
 
+
должен находиться в определяемой пользователем
+
задаче body.
+
 
+
В каком-то смысле метод body аналогичен
+
фазовым методам,
+
 
+
хотя и не принадлежит к числу
+
стандартных фаз OVM.
+
 
+
Метод body применяется только в
+
последовательностях
+
 
+
и определяет существенное поведение
+
последовательности.
+
 
+
Он исполняется, когда последовательность
+
запускается.
+
 
+
Посмотрим, как выглядит метод body
+
для данной конкретной последовательности.
+
 
+
На слайде показана задача body.
+
 
+
Как видите, она содержит бесконечный цикл.
+
 
+
Значит, после запуска эта последовательность
+
будет генерировать непрерывный поток
+
 
+
транзакций, который можно остановить, только
+
принудительно завершив моделирование,
+
 
+
например, путем вызова метода stop_request.
+
 
+
Ничто не может помешать вам
+
создать последовательность,
+
 
+
содержащую бесконечный цикл,
+
 
+
которая, следовательно, будет генерировать
+
непрерывный поток транзакций. Но можно
+
 
+
вместо этого создать последовательность,
+
которая работает конечное время, а потом
+
 
+
останавливается. Оба решения имеют полное
+
право на существование,
+
 
+
нужно лишь понять, какое из них лучше отвечает
+
имеющейся задаче верификации.
+
 
+
В данном случае последовательность
+
будет генерировать непрерывный поток
+
 
+
транзакций, пока мы не прекратим
+
моделирование.
+
 
+
Внутри цикла,
+
 
+
чтобы сгенерировать очередную транзакцию
+
в данной последовательности,
+
 
+
необходимо выполнить несколько
+
стандартных шагов.
+
 
+
Первым делом мы создаем объект
+
транзакции,
+
 
+
для чего в очередной раз
+
прибегаем к использованию
+
 
+
фабричного метода.
+
 
+
Раньше я говорил о фабричных методах
+
 
+
в контексте создания компонентов.
+
 
+
Сейчас же мы применяем фабричный метод create
+
для создания экземпляра транзакции.
+
 
+
Но идея та же самая.
+
 
+
На первый взгляд кажется, что создается
+
транзакция типа my_transaction,
+
 
+
но, поскольку это фабричный метод, в
+
тесте есть возможность
+
 
+
переопределить тип фактически генерируемой
+
транзакции.
+
 
+
Следовательно, в конкретном тесте можно
+
динамически изменить последовательность,
+
 
+
так что она будет генерировать транзакции
+
другого типа.
+
 
+
Технически между этим методом и фабричным
+
методом
+
 
+
для генерации компонентов есть только одно
+
различие:
+
 
+
в данном случае методу create не передается
+
второй аргумент, определяющий родителя,
+
 
+
поскольку никакого родителя у транзакции
+
не существует.
+
 
+
Это был первый шаг -
+
создание транзакции.
+
 
+
Последующие шаги со второго по четвертый
+
составляют стандартный шаблон кода.
+
 
+
На шаге 2 вызывается метод start_item,
+
на шаге 3 транзакция рандомизируется,
+
 
+
а на шаге 4 вызывается метод finish item.
+
 
+
Итак, мы создаем транзакцию,
+
 
+
сигнализируем инфраструктуре, что начинаем
+
процесс ее обработки,
+
 
+
рандомизируем объект транзакции
+
и вызываем finsh_transaction,
+
 
+
сообщая о том, что обработка закончена.
+
 
+
Методы start_item и finish_item
+
запускают внутренние механизмы
+
 
+
взаимодействия с драйвером,
+
 
+
который будет потребителем данной
+
транзакции.
+
 
+
Итак, я показал, как
+
создать экземпляр контроллера,
+
 
+
еще одного стандартного компонента OVM;
+
и как создать последовательность,
+
 
+
которая будет выполняться на данном
+
контроллере.
+
  
 +
Итак, я показал, как создать экземпляр контроллера,
 +
еще одного стандартного компонента OVM; и как создать последовательность,
 +
которая будет выполняться на данном контроллере.
 
Теперь пришло время взглянуть на драйвер.
 
Теперь пришло время взглянуть на драйвер.
  
Драйвер - это тоже стандартный компонент
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=19|600px]]
OVM.
+
  
Класс пользовательского драйвера расширяет
+
Драйвер - это тоже стандартный компонент OVM. Класс пользовательского драйвера расширяет
класс ovm_driver,
+
класс ovm_driver, который параметризован типом транзакции,
 +
потребляемой данным драйвером.
  
который параметризован типом транзакции,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=20|600px]]
 
+
потребляемой данным драйвером.
+
  
 
При написании класса мы делаем все, что
 
При написании класса мы делаем все, что
необходимо для компонента OVM.
+
необходимо для компонента OVM. Как видим, присутствует регистрация драйвера,
 +
объявление виртуального интерфейса, конструктор, методы new и build и, наконец,
 +
задача run.  
  
Как видим, присутствует регистрация драйвера,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=21|600px]]
объявление виртуального интерфейса, конструктор,
+
  
методы new и build и, наконец,
+
Но сейчас мы сразу перейдем к рассмотрению задачи run, потому что все остальные элементы
задача run.
+
нам уже знакомы. Задача run для данного драйвера
 +
содержит цикл, то есть этот драйвер потребляет
 +
ровно четыре транзакции. В цикле драйвер синхронизируется
 +
по фронту синхроимпульса. Напомним, что именно драйвер подает и
 +
считывает сигналы с отдельных контактов тестируемого устройства.
 +
Поэтому в драйвере может присутствовать интерфейс к уровню логических элементов или
 +
уровню межрегистровых передач тестируемого устройства.
  
Но сейчас мы сразу перейдем к рассмотрению
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=22|600px]]
задачи run,
+
  
потому что все остальные элементы
+
Этот конкретный драйвер взаимодействует с RTL-кодом,
нам уже знакомы.
+
в самом начале он синхронизируется по фронту синхроимпульса в интерфейсе
 +
тестируемого устройства. Это делается в предложении @(posedge dut_vi.clock).
  
Задача run для данного драйвера
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=23|600px]]
содержит цикл,
+
  
то есть этот драйвер потребляет
+
Затем, по достижении готовности, драйвер получает транзакцию от контроллера.
ровно четыре транзакции.
+
То есть драйвер потребляет транзакции, генерируемые контроллером.
 
+
Для этого драйвер вызывает метод get порта sequence_item_port.
В цикле драйвер синхронизируется
+
Напомню, на предыдущем занятии мы видели, что порт - это по существу описатель,
по фронту синхроимпульса.
+
который применяется для организации взаимодействия между компонентом и
 
+
Напомним, что именно драйвер подает и
+
считывает сигналы с отдельных контактов
+
 
+
тестируемого устройства.
+
Поэтому в драйвере может присутствовать
+
 
+
интерфейс к уровню логических элементов или
+
уровню межрегистровых передач
+
 
+
тестируемого устройства.
+
 
+
Этот конкретный драйвер взаимодействует
+
с RTL-кодом,
+
 
+
в самом начале он синхронизируется
+
по фронту синхроимпульса в интерфейсе
+
 
+
тестируемого устройства. Это делается в
+
предложении @(posedge dut_vi.clock).
+
 
+
Затем, по достижении готовности, драйвер
+
получает транзакцию от контроллера.
+
 
+
То есть драйвер потребляет транзакции,
+
генерируемые контроллером.
+
 
+
Для этого драйвер вызывает метод get
+
порта sequence_item_port.
+
 
+
Напомню, на предыдущем занятии мы
+
видели,
+
 
+
что порт - это по существу описатель,
+
который применяется для организации
+
 
+
взаимодействия между компонентом и
+
 
окружающим миром.
 
окружающим миром.
  
Получив транзакцию, драйвер
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=24|600px]]
  
может обратиться к отдельным ее полям
+
Получив транзакцию, драйвер может обратиться к отдельным ее полям
 +
и присвоить значения полям виртуального интерфейса устройства.
  
и присвоить значения полям виртуального
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=25|600px]]
интерфейса устройства.
+
  
И наконец, потребив все четыре
+
И наконец, потребив все четыре транзакции, драйвер может вызвать метод stop_request,
транзакции,
+
чтобы прекратить моделирование. Таким образом, драйвер потребляет транзакции и подает
 +
сигналы на входы тестируемого устройства.
  
драйвер может вызвать метод stop_request,
+
[[file:module_basic_ovm_session6_introducing_transactions_jaynsley.pdf|page=26|600px]]
чтобы прекратить моделирование. Таким
+
 
+
образом, драйвер потребляет транзакции и подает
+
сигналы на входы тестируемого устройства.
+
  
 
Подведем итоги. На этом занятии я показал,
 
Подведем итоги. На этом занятии я показал,
как определяется транзакция,
+
как определяется транзакция, как создается экземпляр контроллера,
 
+
как создается последовательность, которая будет запущена на этом контроллере,
как создается экземпляр контроллера,
+
как определяется и создается драйвер. А ранее мы видели, как соединить
 
+
контроллер с драйвером, а драйвер с тестируемым устройством.
как создается последовательность, которая
+
На следующем занятии мы подробнее поговорим о контроллерах и о том,
будет запущена на этом контроллере,
+
 
+
как определяется и создается драйвер.
+
 
+
А ранее мы видели, как соединить
+
контроллер с драйвером,
+
 
+
а драйвер с тестируемым устройством.
+
 
+
На следующем занятии мы подробнее
+
поговорим о контроллерах и о том,
+
 
+
 
как запускать последовательности на контроллерах.
 
как запускать последовательности на контроллерах.

Текущая версия на 13:49, 25 ноября 2013

Проект Диплом

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

* OVM *

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

Но сначала покажем, какое место в этой картине занимает иерархия классов OVM, с которой мы познакомились на предыдущем занятии. Мы видели, что в OVM имеется целое иерархически организованное семейство классов для описания компонентов, то есть структурных элементов. Имеется также параллельная иерархия классов для описания транзакций, или данных. Базовым для всех транзакций является класс ovm_transaction. Последовательность, строго говоря, представляется классом, производным от ovm_sequence_item. Таким образом, класс ovm_sequence расширяет ovm_sequence_item, который в свою очередь расширяет ovm_transaction, ну а тот расширяет ovm_object. Транзакции и последовательности - это данные в противоположность компонентам, которые суть элементы структуры. Транзакции не являются частью иерархии компонентов. Если у компонента OVM обычно имеется родительский компонент, то у транзакций, передаваемых от одного компонента другому, родителей нет.

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

Во второй строке нашего класса мы регистрируем его в качестве транзакции, применяя еще один стандартный макрос OVM. Обратите внимание, что мы используем ovm_object_utils, а не ovm_component_utils. Мы встречались с двумя стандартными макросами для регистрации классов:ovm_component_utils и ovm_object_utils. Крайне важно использовать правильный макрос.

Module basic ovm session6 introducing transactions jaynsley.pdf

Далее идут поля - свойства транзакции. В данном случае транзакция содержит команду, адрес и данные. Они и составляют свойства класса. Объявлению каждого свойства предшествует ключевое слово rand. В языке SystemVerilog слово rand означает, что после создания и рандомизации экземпляра данного класса значения объявленных таким образом свойств будут случайными. И это правильно, потому что мы собираемся использовать сгенерированные транзакции как стимулы для подачи на входы тестируемого устройства. Наконец, после объявления свойств мы видим первый пример ограничений SystemVerilog. Настоятельно рекомендуется включать такие ограничения в определение транзакции,чтобы ее свойства гарантированно имели осмысленные значения по умолчанию.Тогда, что бы ни происходило в конкретных тестах, если мы сгенерируем экземпляр класса my_transaction по умолчанию, что мы и собираемся сделать, наличие ограничений дает уверенность, что свойства такого экземпляра будут иметь разумные значения. Мы задали ограничения так, чтобы адрес и данные находились в допустимом диапазоне. Касательно ограничений стоит сделать одно важное замечание: поскольку это ограничения, а не процедурный код, впоследствии их можно будет переопределить. Стало быть, ограничения по природе своей не жесткие, вы всегда можете изменить решение. Пока что мы сказали, что адрес лежит в диапазоне от 0 до 256, и, значит, обычно он будет принадлежать этому диапазону. Но позже, если возникнет такая необходимость, мы сможем переопределить это ограничение, заменив его чем-то совершенно иным.

Module basic ovm session6 introducing transactions jaynsley.pdf

Далее следует конструктор, как во всяком пользовательском классе. У любого класса в языке SystemVerilog должен быть конструктор, и здесь мы включили в конструктор типичный трафаретный код. Однако отметим, что этот конструктор несколько отличается от конструктора класса, производного от ovm_component. Поскольку транзакция не является частью иерархии компонентов, у нее нет родительского компонента. Поэтому у конструктора отсутствует второй аргумент, parent. Это, конечно, очень простая транзакция, но ее уже достаточно для работы.

Module basic ovm session6 introducing transactions jaynsley.pdf

Итак, транзакцию мы определили, теперь перейдем к контроллеру. Контроллер - это стандартный компонент OVM, задача которого – генерировать случайную последовательность транзакций.

Module basic ovm session6 introducing transactions jaynsley.pdf

Для создания контроллера мы определим пользовательский класс, расширяющий ovm_sequencer - еще один базовый класс из библиотеки OVM.

Module basic ovm session6 introducing transactions jaynsley.pdf

ovm_sequencer - это пример параметризованного класса в SystemVerilog. Для тех, кто знаком с объектно-ориентированным программированием, скажу, что параметризованные классы в SystemVerilog похожи на шаблоны классов в C++. Параметризованный класс позволяет модифицировать некоторые свойства класса SystemVerilog в момент его создания. В данном случае при инстанцировании класса ovm_sequencer мы задаем вид транзакции, генерируемой этим контроллером. Таким образом, класс my_sequencer расширяет ovm_sequencer с целью генерировать транзакции типа my_transaction.

Module basic ovm session6 introducing transactions jaynsley.pdf

Поскольку этот класс - стандартный компонент OVM,его код должен следовать стандарту написания компонентов.Мы регистрируем компонент макросом ovm_component_utils и включаем стандартный конструктор. Больше ничего не требуется. Это очень простой контроллер и тем не менее в него встроена возможность генерировать последовательность транзакций. Далее мы увидим, как можно заставить контроллер делать то, что нам нужно в этом конкретном случае.

Module basic ovm session6 introducing transactions jaynsley.pdf

Мы изменяем контроллер так, чтобы он производил нужные нам действия, запуская на нем последовательность. В этом месте терминология OVM становится несколько путаной. На предыдущем слайде был показан класс ovm_sequencer с буквой r в конце. А теперь мы встречаем класс ovm_sequence. Напомним, что контроллер (sequencer) - это компонент, структурный элемент, принадлежащий иерархии компонентов. С другой стороны, последовательность (sequence) - это класс, расширяющий ovm_transaction. Последовательность состоит из данных, динамически изменяющихся во времени. Последовательность запускается на контроллере. На данном слайде показана определенная пользователем последовательность my_sequence. Она расширяет базовый класс ovm_sequence - еще один пример параметризованного класса. Он параметризуется типом транзакций, из которых составлена последовательность. Последовательность ovm_sequence всегда состоит из транзакций. То есть последовательность - это на самом деле последовательность транзакций.

Module basic ovm session6 introducing transactions jaynsley.pdf

Ну а далее идет стандартный код. Мы должны зарегистрировать последовательность с помощью макроса ovm_object_utils. У последовательности имеется стандартный конструктор. А теперь более интересная часть - у последовательности есть метод body.

Module basic ovm session6 introducing transactions jaynsley.pdf

С этим мы еще не сталкивались. Весь содержательный код, описывающий фактическое поведение последовательности, должен находиться в определяемой пользователем задаче body. В каком-то смысле метод body аналогичен фазовым методам, хотя и не принадлежит к числу стандартных фаз OVM. Метод body применяется только в последовательностях и определяет существенное поведение последовательности.

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

Внутри цикла, чтобы сгенерировать очередную транзакцию в данной последовательности, необходимо выполнить несколько стандартных шагов. Первым делом мы создаем объект транзакции, для чего в очередной раз прибегаем к использованию фабричного метода. Раньше я говорил о фабричных методах в контексте создания компонентов. Сейчас же мы применяем фабричный метод create для создания экземпляра транзакции. Но идея та же самая. На первый взгляд кажется, что создается транзакция типа my_transaction, но, поскольку это фабричный метод, в тесте есть возможность переопределить тип фактически генерируемой транзакции. Следовательно, в конкретном тесте можно динамически изменить последовательность, так что она будет генерировать транзакции другого типа. Технически между этим методом и фабричным методом для генерации компонентов есть только одно различие: в данном случае методу create не передается второй аргумент, определяющий родителя, поскольку никакого родителя у транзакции не существует.

Module basic ovm session6 introducing transactions jaynsley.pdf

Это был первый шаг - создание транзакции. Последующие шаги со второго по четвертый составляют стандартный шаблон кода. На шаге 2 вызывается метод start_item, на шаге 3 транзакция рандомизируется, а на шаге 4 вызывается метод finish item. Итак, мы создаем транзакцию, сигнализируем инфраструктуре, что начинаем процесс ее обработки, рандомизируем объект транзакции и вызываем finsh_transaction, сообщая о том, что обработка закончена. Методы start_item и finish_item запускают внутренние механизмы взаимодействия с драйвером, который будет потребителем данной транзакции.

Module basic ovm session6 introducing transactions jaynsley.pdf

Итак, я показал, как создать экземпляр контроллера, еще одного стандартного компонента OVM; и как создать последовательность, которая будет выполняться на данном контроллере. Теперь пришло время взглянуть на драйвер.

Module basic ovm session6 introducing transactions jaynsley.pdf

Драйвер - это тоже стандартный компонент OVM. Класс пользовательского драйвера расширяет класс ovm_driver, который параметризован типом транзакции, потребляемой данным драйвером.

Module basic ovm session6 introducing transactions jaynsley.pdf

При написании класса мы делаем все, что необходимо для компонента OVM. Как видим, присутствует регистрация драйвера, объявление виртуального интерфейса, конструктор, методы new и build и, наконец, задача run.

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

Этот конкретный драйвер взаимодействует с RTL-кодом, в самом начале он синхронизируется по фронту синхроимпульса в интерфейсе тестируемого устройства. Это делается в предложении @(posedge dut_vi.clock).

Module basic ovm session6 introducing transactions jaynsley.pdf

Затем, по достижении готовности, драйвер получает транзакцию от контроллера. То есть драйвер потребляет транзакции, генерируемые контроллером. Для этого драйвер вызывает метод get порта sequence_item_port. Напомню, на предыдущем занятии мы видели, что порт - это по существу описатель, который применяется для организации взаимодействия между компонентом и окружающим миром.

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

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

Module basic ovm session6 introducing transactions jaynsley.pdf

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