Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Верификация цифровых устройств. Курс лекций. Учебное пособие
.pdf
Рис. 4.2. Подключение порта к экспорту
Генератор имеет порт put_port, в который записывает сгенерированные элементы. При этом при создании порта в качестве параметра указывается тип передаваемых элементов:
class producer extends uvm_component;
uvm_blocking_put_port #(uart_trans) put_port;
function new(string name, uvm_component parent);
put_port =new(“put_port”,this);
...
endfunction
virtual task run();
uart_trans t;
for(int i = 0; i < N; i++)begin
put_port.put(t);
end
endtask
На стороне получателя аналогично объявляется экспорт и перегружается функция, которая будет запускаться при получении данных (рис. 4.3). Т.е. фактически, когда генератор вызывает функцию
put(), он вызовет функцию получателя:
class consumer extends uvm_component;
uvm_blocking_put_imp #(uart_trans, consumer) put_export;
...
task put(uart_trans t);
... // обработка транзакции
endtask
endclass
Рис. 4.3. Подключение экспорта к порту
– 41 –

В случае, когда получатель инициирует передачу, используется
другой тип интерфейсов – get. Теперь уже у генератора реализуется задача get(), которую вызывает получатель:
class get_consumer extends uvm_component;
uvm_blocking_get_port #( uart_trans) get_port;
function new(string name, uvm_component parent);
get_port =new(“get_port”,this);
...
class get_producer extends uvm_component;
uvm_blocking_get_imp #( uart_trans, get_producer)
get_export;
...
task get(output uart_trans t);
Но недостаточно объявить порты в составе классов. Необходимо установить соединение между конкретными экземплярами этих
портов. Это делается в более высоком по иерархии модуле. Для
этого вызывается метод
put или get какого объекта надо запустить:
connect(), который указывает, функцию
class my_env extends uvm_env;
...
virtual function void connect_phase(uvm_phase phase);
producer.put_port.connect(consumer.put_export);
get_consumer.get_port.connect(get_producer.get_export);
...
endfunction
endclass
В приведенном выше базовом примере для
дет активен только при вызове метода
put(). Однако часто бывает
put получатель бу-
необходимо, чтобы компоненты работали независимо, когда генератор создает транзакции в одном процессе, в то время как получатель должен работать с этими транзакциями в другом. Для этих
целей в UVM предусмотрен канал
uvm_tlm_fifo. Uvm_tlm_fifo ре-
ализует все методы интерфейса TLM, поэтому генератор помещает
транзакцию в
транзакцию из
uvm_tlm_fifo, а получатель независимо получает
fifo. Экземпляр этого класса создается и подключа-
ется к портам генератора и получателя (рис. 4.4).
– 42 –

Рис. 4.4. Использование TLM_FIFO
Все рассмотренные ранее задачи чтения/записи в порты являются блокирующими, т.е. они не могут завершиться неудачно. Вызвавший их процесс останавливается до тех пор, пока не будет выполнено необходимое действие. Существуют также неблокирующие порты:
class consumer extends uvm_component;
uvm_get_port #(uart_trans) get_port;
...
for(int i=0; i<10; i++)
if(get_port.try_get(t))
...
endclass
try_get() – функция (в противовес задачам для блокирующих
портов), которая пытается прочитать данные, и возвращает FLASE,
если это не получилось. Гарантируется, что функция завершается в
том же дельта-цикле, когда вызвана. Аналогично работают функции try_peek() и try_put().
Еще один момент, который следует рассмотреть, – это применение TLM портов при иерархическом тестовом окружении. В основе
методологии UVM лежит разделение тестового окружения на максимально универсальные, повторно используемые и взаимозаменяемые блоки. Это приводит к тому, что нельзя просто подключаться
к портам внутри компонента, хотя язык это позволяет
(
agent.sequencer.put_port). В этом случае тестовое окружение
становится жестко привязанным к данному элементу. Вместо этого
надо создавать порты во всей иерархии элементов и подключать их
друг к другу (рис. 4.5).
Рис. 4.5. Пример иерархического подключения портов
– 43 –

В данной системе связи А, B, F, D соответствуют уже рассмотренным ранее соединениям порта и экспорта. Но С и E – это соединение порта с портом и экспорта с экспортом, которое также выполняется с помощью функции connect. При этом функция con-
nect вызывается для источника данных. Пример реализации полу-
чателя в таком случае:
class consumer extends uvm_component;
uvm_put_export #(uart_trans) put_export;
uvm_tlm_fifo #(uart_trans) fifo;
...
function void connect_phase(uvm_phase phase);
put_export.connect(fifo.put_export);
...
endfunction
endclass
Все рассмотренные ранее порты предполагали соединение точка-точка, т.е. всегда был генератор данных и их получатель. Но при
построении верификационного окружения часто возникает задача
передать данные нескольким получателям одновременно – например, для анализа данных в нескольких элементах проверки.
Для таких целей в UVM введен
личие от
put/get портов данный порт не требует, чтобы он был
analysis_port (рис. 4.6). В от-
обязательно подключен, равно как он может быть подключен к нескольким получателям (
реализацию функции
export). Каждый получатель должен иметь
write, которая вызывается для всех получа-
телей, подключенных к порту.
Рис. 4.6. Подключение analysis порта
– 44 –

Пример записи в порт:
uvm_analysis_port#(uart_trans) ap;
...
ap.write(t);
и чтения из порта:
class uart_sub#(type T =uart_trans)extends
uvm_subscriber #(T);
...
function void write(T t);
...
При этом в данном примере класс sub1 унаследован от класса
uvm_subscriber. В этом классе уже объявлен analysis_export порт.
Поэтому требуется только перегрузить реализацию функции write.
Подключение этого типа портов выполняется аналогично – для
порта вызывается функция
connect для каждого получателя дан-
ных:
Rx.ap.connect(sub1.analysis_export);
Rx.ap.connect(sub2.analysis_export);
UVM также включает значение uvm_tlm_analysis_fifo, которое является аналогом uvm_tlm_fifo с соответствующим типом
портов. Данное FIFO не ограничено по размеру. Источник данных
может записать в него данные, а получатель прочитать их позднее.
– 45 –

Лекция 5. UVM базовые элементы окружения и фазы теста
Введение
Важное место в работе тестового окружения занимают механизмы синхронизации работы всех элементов – фазы. В лекции
рассмотрен механизм работы фаз. Вторая часть лекции посвящена
описанию устройства и процессу разработки одного из основных
элементов окружения – агента – и его составляющих – драйвера и
монитора.
5.1. Фазы теста
стового окружения, построенного по методологии UVM. Построение этого окружения выполняется с использованием входящих в
состав библиотеки базовых классов, которые заранее реализуют
основной функционал каждой компоненты. Эти классы могут взаимодействовать между собой, передавая и принимая транзакции. И
все эти элементы работают параллельно. Возникает вопрос: как
обеспечить синхронизацию работы этих компонент? Ведь, если
генератор начнет передавать пакеты в неподключенный порт или
драйвер попробует прочитать данные из порта, который еще даже
не создан, – это может приводить к ошибкам.
используется механизм фаз работы теста. Фазы являются виртуальными методами, которые определены в базовом классе
uvm_component. При реализации этих методов в расширенных клас-
сах-наследниках надо явно вызывать метод родителя, включив
оператор
низируется средами UVM – переход к следующей фазе теста выполняется только после того, как все компоненты сняли ограничение на этот переход, т.е. завершили текущую фазу.
В предыдущей лекции была рассмотрена общая структура те-
Для решения задачи синхронизации работы компонент в UVM
super. <Имя фазы> _phase (phase); Работа фаз синхро-
– 46 –

Всего определено три группы фаз:
• сборки;
• выполнения;
• очистки.
5.1.1. Фазы сборки
Фазы сборки – это build phase, connect phase и
end_of_elaboration phase. Все эти фазы являются функциями, ко-
торые выполняются до нулевого момента времени моделирования.
Целью этих этапов является создание тестовых компонентов и их
соединение для создания тестового окружения. В тестовых окружениях на Verilog эти шаги не были необходимыми, поскольку все
компоненты являлись статическими модулями. Все статические
компоненты создаются во время компиляции. Однако компоненты
в UVM являются классами, которые являются динамическими объектами, поэтому необходимо явно их создавать.
Фаза build_phase используется для создания компонентов тестового окружения. После запуска теста (вызов функции
()) создается корневой компонент тестового окружения и для него
запускается функция
build_phase(). Далее функция вызывается
run_test
при создании объектов по нисходящему прицепу. Задача данной
фазы, помимо непосредственно создания объектов, – получение их
конфигураций и формирование конфигураций для нижележащих
компонент. После завершения фазы гарантируется, что все объекты, унаследованные от
uvm_component, были созданы.
Следующая фаза – connectphase. После того, как все компоненты созданы, начинается их соединение. Прежде всего это соединение TLM портов. К моменту завершения работы данной фазы все
соединения между компонентами должны быть установлены.
Фаза end_of_elaboration phase – заключительная фаза сборки
окружения. После того, как все компоненты собраны и подключены на вышеуказанных этапах, может потребоваться внести корректировки в тестовое окружение – эти операции могут выполняться в
данной фазе. Также эта фаза используется для печати итоговой
конфигурации тестового окружения.
– 47 –

5.1.2. Фазы выполнения
К моменту запуска фаз выполнения время моделирования всееще находится на отметке ноль, хотя некоторое количество дельтациклов могло выполниться к этому моменту. Фазы выполнения:
start_of_simulation_phase и run_phase, которая имеет 12 подфаз.
Фаза start_of_simulation вызывается между созданием тестового окружения и фактическим моделированием. Обычно она используется для печати сообщений или отображения информации о
конфигурации.
run_phase – единственная фаза, которая реализуется не функцией, а задачей. Она имеет 12 подфаз: reset_phase, configure_phase,
main_phase, shutdown_phase, а также версии фаз до
(pre_reset_phase) и после (post_reset_phase). Эти подфазы выполняются последовательно. При этом параллельно подфазам выполняется основная фаза – run_phase. Т.е. фаза pre_reset запустится
одновременно с run_phase.
run_phase используется для генерации тестовых воздействий,
подачи воздействий на тестируемое устройство и мониторинга выходных данных. Компоненты, такие как драйвер и монитор, должны реализовывать задачу run_phase.
Рассмотрим коротко назначение подфаз:
pre_reset_phase используется для выполнения операций перед
применением сброса к DUT. Например, дождаться включения
устройства.
reset_phase – для генерации сброса и применения к DUT или
любому интерфейсу.
post_reset_phase – для выполнения любых операций после применения сброса. Например, анализ и вывод результатов выполнения сброса.
pre_configure_phase – для сбора информации о конфигурации и
ожидания готовности компонентов к конфигурации после сброса.
configure_phase – для настройки DUT и инициализации памяти
в тестовом стенде.
post_configure_phase – для ожидания передачи информации о
конфигурации в DUT. Она нужна для гарантии, что основной тестовый сценарий может быть запущен.
– 48 –

pre_main_phase – проверка готовности всех компонент начать
моделирование.
main_phase – основная фаза. Используется для генерации и передачи тестовых воздействий на DUT.
post_main_phase – эта фаза должна обеспечить завершение всех
операций, запущенных в main_phase.
pre_shutdown_phase – ожидание завершения генерации воздействий.
shutdown_phase – используется, чтобы гарантировать, что все
тестовые воздействия достигли проверяемого устройства, а выходные данные получены из него.
post_shutdown_phase – заключительная фаза моделирования.
Используется для выполнения любых необходимых действий.
5.1.3. Фазы очистки
Фазы очистки используются для извлечения информации из
табло (scoreboards) и мониторов покрытия, чтобы определить,
прошел ли тест, достигнуты ли его цели покрытия. Этапы очистки
реализованы в виде функций, и поэтому для их выполнения не требуется модельное время. К фазам очитки относятся extract_phase,
check_phase, report_phase и final_phase.
extract_phase – фаза извлечения; она предназначена для извле-
чения и обработки информации из табло и мониторов функционального покрытия. Может включать расчет статистической информации, используемой на этапе отчета. Этот этап обычно используется компонентами анализа.
check_phase – фаза проверки, используется для проверки правильности поведения проверяемого устройства и выявления любых
ошибок, которые могли возникнуть во время выполнения теста.
Фаза report_phase нужна для отображения результатов моделирования или записи результатов в файлы. Этот этап обычно используется компонентами анализа.
Заключительная фаза – final_phase; используется для выполнения любых операций, которые нужны в тестовом окружении.
Завершая рассмотрение механизма фаз, надо отметить еще две
возможности. Во-первых, фазы синхронизированы и выполняются
последовательно, так как находятся в одном домене синхрониза-
– 49 –

ции. Но при необходимости возможно создание нескольких доменов, в каждом их которых фазы теста будут выполняться независимо от другого домена.
Во-вторых, в UVM есть возможность создания своих фаз теста,
если это необходимо. Хотя, учитывая и так большое их количество,
это требуется крайне редко.
5.2. Базовые элементы тестового окружения
В состав агентов тестового окружения, как правило, входят
драйвер, монитор, генератор последовательностей,
5.2.1. Драйвер
Драйвер – компонент, который выступает мостом между TLM и
интерфейсами DUT. Драйвер извлекает транзакции из генератора
последовательностей и отправляет их на интерфейсы тестируемого
устройства. Драйвер во время фазы run вычитывает из входного
порта
seq_item_port данные для отправки, формирует необходи-
мые для передачи данных сигналы и передает их в интерфейс DUT.
После передачи драйвер записывает в порт подтверждение отправки и считывает следующие данные.
Рассмотрим пример простого драйвера для работы с интерфейсом uart:
class uart_driver extends uvm_driver#(uart_transaction);
`uvm_component_utils(uart_driver)
uart_transaction u_item;
virtual uart_if vif;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction:new
function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual uart_if)::get(this,
“”,"vif",vif))
`uvm_fatal("NOVIF",{"virtual interface must be set
for: ", get_full_name(),".vif"});
endfunction: build_phase
– 50 –
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
