2.14.1 Основы моделирования
Моделирование цифровых систем является важным шагом в маршруте их разработки. Возрастание сложности проектируемых устройств заставляет разработчиков тратить все больше времени на их моделирование. Целями моделирования могут быть как исследование алгоритмов работы проектируемого устройства, так и верификация характеристик, получаемых при его аппаратной реализации. В первом случае производится моделирование на верхних уровнях абстрагирования (т.е. преимущественно на поведенческом, и, возможно, RTL), а моделирование на физическом уровне призвано проверить возможность работы созданного устройства в заданных условиях эксплуатации (т.е. проверяется возможность работы на заданной тактовой частоте, с требуемыми длительностями сигналов, в заданном температурном диапазоне и т.д.).
При моделировании используется подход, основанный на «испытательном стенде» (testbench). Моделируемое устройство (в англоязычной литературе UUT, UnitUnderTest) представляется своим синтезируемым кодом, а для проверки его поведения в различных условиях создаются описания тестовых воздействий («моделируемый код»).
Задание тестовых входных воздействий может быть выполнено на VHDL с помощью модуля типа VHDLTestBench. В качестве примера рассмотрим процесс моделирования модуля my_and, синтезируемое описание которого представлено ниже:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entitymy_and is
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
c : out STD_LOGIC);
endmy_and;
architecture Behavioral of my_and is
begin
c <= a and b after 3 ns;
endBehavioral;
Данное описание является поведенческим, так как в нем присутствует конструкция after 3 ns, которая моделирует задержку срабатывания вентиля 2И. После добавления к проекту такого компонента можно вновь воспользоваться мастером создания новых модулей.
Рис. 2.7 Создание модуля, описывающего тестовые воздействия
Для унификации обозначений обычно применяется сочетание символов tb (от testbench, «испытательный стенд»). Так, если модуль имеет название my_and, то с ним удобно сопоставить тестовый файл my_and_tb.
При добавлении тестового файла в проект САПР ISE также запрашивает ассоциирование этого файла с одним из имеющихся модулей.
Рис. 2.8 Привязка модуля описания тестовых воздействий к синтезируемому модулю проекта
Запрос на ассоциирование нужен для того, чтобы сгенерировать шаблон теста с автоматической привязкой к интерфейсу, как показано в листинге, приведенном ниже.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
LIBRARY UNISIM;
USE UNISIM.Vcomponents.ALL;
ENTITY top_top_sch_tb IS
END top_top_sch_tb;
ARCHITECTURE behavioral OF top_top_sch_tb IS
COMPONENT top
PORT( a : IN STD_LOGIC;
b : IN STD_LOGIC;
c : OUT STD_LOGIC);
END COMPONENT;
SIGNAL a : STD_LOGIC;
SIGNAL b : STD_LOGIC;
SIGNAL c : STD_LOGIC;
BEGIN
UUT: top PORT MAP(
a => a,
b => b,
c => c
);
-- *** Test Bench - User Defined Section ***
tb : PROCESS
BEGIN
WAIT; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***
END;
Это описание необходимо модифицировать для получения требуемого эффекта от моделирования. Предположим, что требуется проверить поведение модуля при последовательной установке в логическую единицу сначала входа a, а затем входа b. Тогда раздел «секция пользователя» (UserDefinedSection) будет выглядеть так.
-- *** Test Bench - User Defined Section ***
tb : PROCESS
BEGIN
a <= '0', '1' after 20 ns;
b <= '0', '1' after 30 ns;
WAIT; -- will wait forever
END PROCESS;
-- *** End Test Bench - User Defined Section ***
Рис. 2.9 Временные диаграммы при моделировании в поведенческом режиме
На рис. видно, что в результате моделирования входные сигналы были установлены в соответствии с заданными тестовыми воздействиями. Задержки, заданные с помощью выражения after, отсчитываются от начала моделирования.
После этого, с учетом заданной задержки распространения сигнала в 3 нс, выход c примет значение 1 в момент времени 33 нс (30 нс до момента, в который оба входа приняли значение 1, плюс 3 нс на распространение сигнала до выхода).
Необходимо иметь в виду, что задержка в 3 нс, указанная в поведенческой модели, не является указанием САПР обеспечить заданную задержку. Напротив, приведение этого значения означает, что разработчик каким-то образом спрогнозировал задержку распространения, определил ее из технической документации, либо планирует рассмотреть, каким бы было поведение устройства, если бы задержки были равны указанным. Реальные задержки зависят от используемой аппаратной платформы, размещения компонентов на кристалле и особенностей выполнения трассировки.
В САПР ПЛИС ISE возможно проведение моделирования на физическом уровне, когда задержки распространения сигналов не принимаются равными тем, которые указаны в поведенческом описании, а рассчитываются, исходя из физических моделей компонентов ПЛИС и трассировки конкретного проекта. Для моделирования в таком режиме необходимо в выпадающем списке выбрать Post-Route перед запуском моделирования.
Рис. 2.10 Выбор режима моделирования
Результаты моделирования компонента my_and показаны на рис. Можно убедиться, что задержка распространения сигнала оказалась равна 6,05 нс (для ПЛИС XC3S500E), а не 3 нс, как это предполагалось в поведенческой модели.
4Величина 6,05 нс не является задержкой распространения через единственный логический вентиль, что было бы чрезмерно завышенным результатом для 90-нм элементной базы. Данная задержка определена с учетом влияния входных буферов для сигналов a и b и выходного буфера выхода c, подключенных к выводам ПЛИС.
Рис. 2.11 Результаты моделирования модуля my_and в режиме Post-Route.
Для получения результатов Post-Route моделирования необходимо, как следует из названия, выполнить трассировку (Routing) проекта. Таким образом, результат оказывается привязан к конкретной элементной базе. Кроме того, его получение связано с необходимостью анализа физических моделей компонентов, что требует существенно большего времени по сравнению с выполнением поведенческого моделирования. Однако такой результат существенно точнее, поскольку времена распространения сигналов рассчитываются по реальной трассировке, а не вводятся в модель из субъективных соображений.
При проектировании цифровых систем моделирование на физическом уровне обычно используется на завершающих этапах верификации проекта, когда требуется подтвердить не просто правильность выполнения преобразований, а соблюдение временных характеристик установления и распространения сигналов. В процессе отладки удобнее использовать моделирование на поведенческом уровне, поскольку оно производится существенно быстрее. В этом случае даже ориентировочные величины задержек позволяют иллюстрировать временной сдвиг сигналов друг относительно друга, что позволяет отлаживать архитектуру устройства.
Основные тестовые воздействия задаются внутри процедурных блоков process. В примере, показанном выше, было использовано последовательное назначение состояний отдельным сигналам с помощью ключевого слова after. При этом указывались абсолютные времена, т.е. моменты времени относительно начала моделирования. Другим вариантом является использование конструкции waitfor.
tb1 :process
begin
reset<= ‘1’;
waitfor 100 ns;
reset<= ‘0’;
wait ;
endprocesstb1;
В данном примере сигналу reset присваивается значение ‘1’, а затем, по истечении интервала времени 100 нс, присваивается значение ‘0’. Интервал времени отсчитывается от того момента, который был действителен при выполнении waitfor.
В качестве еще одного примера можно рассмотреть формирование бесконечного тактового сигнала (т.н. freerunningclock).
Пример 1.
-- создается тактовый сигнал с инициализацией
signalclk : std_logic_vector := ‘1’;
architecture …
begin
clk<= not clk after 5 ns;
В данном примере инициализация обязательна, поскольку в противном случае взять инверсное значение от неопределенного изначально сигнала окажется невозможно. Таким способом моделируется сигнал с периодом в 10 нс, так как для получения одного периода необходимо два раза проинвертировать значение сигнала, а интервал между этими операциями задан равным 5 нс.
Пример 2.
architecture test of my_module is
signal clk : std_logic;
constant PERIOD : time := 10 ns;
begin
clk_tb: process
begin
ifclk = 'U' then
clk<= '1';
wait for PERIOD /2
end if;
clk<= not clk;
wait for PERIOD /2;
endprocessclk_tb;
В этом примере используется отдельный процесс, в котором проверяется состояние тактового сигнала. Если он был неопределенным, что наблюдается только при старте моделирования, ему присваивается значение ‘1’, и моделируется пауза, равная половине периода тактового сигнала. В противном случае значение инвертируется, и также моделируется пауза.
В модели на VHDL можно встроить проверку выполнения определенных условий. Это производится с помощью оператора assert. Пример его использования показан ниже:
assert SUM_EXPECTED = SUM_OUT
report "ERROR: output SUM is incorrect"
severitywarning;
После ключевого слова assert указывается условие, которое предполагается истинным (т.е. при нормальной работе модуля оно должно выполняться). Если условие не выполняется, в консоль выводится сообщение, указанное после ключевого слова report. После severity указывается уровень важности проверяемого условия. Он может быть следующим: note, warning, error, failure.
note – «примечание», это сообщение не является ошибкой и носит информационный характер;
warning – «предупреждение», такие сообщения подсчитываются, но их наличие не является основанием для признания результатов некорректными;
error – «ошибка», результат моделирования признается некорректным, моделирование продолжается;
failure – «сбой», аналогично ошибке, но выполнение немедленно прерывается.
По умолчанию сообщения имеют уровень error.
Назначение уровня важности производится самим разработчиком теста. Предполагается, что сообщения уровня «сбой» будут присваиваться ошибкам, которые не могут быть достаточно легко исправлены, или относятся к «ситуациям, которые никогда не могут возникнуть». Возникновение сообщения такого уровня должно означать, что в процессе моделирования возникли существенные проблемы, и производить дальнейший анализ не имеет смысла.
Последовательная и максимально полная проверка выполнения наиболее важных условий с помощью набора операторов assert может существенно повысить надежность создаваемых модулей. Тестирование особенно важно для проектов, состоящих из большого количества повторно используемых модулей и IP-ядер. В процессе отладки сложного проекта, когда некорректная работа может объясняться большим количеством причин, последовательное покомпонентное моделирование может ускорить процесс идентификации проблемы.
2.14.2 Использование файловых операций
Доступ к файлам из модулей на VHDL может быть полезен в целом ряде случаев. Для синтезируемых модулей в файлах удобно хранить данные для инициализации памяти (впрочем, из файлов можно загрузить любые данные). Для моделей в файлах могут храниться тестовые воздействия и образцовые отклики моделируемых систем. Удобство использования текстовых файлов обусловлено также тем, что какие-то данные или параметры для проектирования на VHDL могут быть получены с помощью других программных инструментов – например, пакета Matlab или программы на языке высокого уровня, которая сохраняет результаты работы в текстовом формате.
Для доступа к файлам потребуются объекты следующих типов:
TEXT – ссылка на текстовый файл;
LINE – строка, читаемая из файла, с которой будут производиться последующие действия.
Для работы с текстовыми файлами используются следующие основные функции:
READLINE – читает очередную строку из файла;
READ – выделяет фрагмент данных из ранее прочитанной строки;
WRITE – помещает фрагмент данных в строку для последующей записи в текстовый файл;
WRITELINE – записывает строку в конец файла;
ENDFILE – проверка достижения конца файла.
Рассмотримпример:
variableLineOfText : line;
file source : TEXT open READ_MODE is "source.txt";
В данном случае объявляется переменная LineOfText типа line, которая впоследствии будет использоваться для чтения строк из текстового файла. Также объявляется переменная файлового типа (указатель на файл). Формат объявления такой переменной имеет следующий вид:
file<имя переменной> : TEXTopen<режим>is<путь к файлу>;
Режим может иметь значения READ_MODE, WRITE_MODE в зависимости от желаемого вида работы с файлом.
Input и Output являются предопределенными указателями для работы с консолью.
После объявления переменных для работы с файлом следует прочитать строку с помощью функции readline:
readline(source, LineOfText);
Теперь, когда строка из файла прочитана, можно получить записанные в ней значения. Это выполняется с помощью функций read и hread.
read(LineOfText, var, status);
hread(LineOfText, hex_var, status);
Первая из функций выделяет из строки значение переменной и записывает его в приведенном примере в переменную var. Переменная status хранит результат выполнения преобразования и равна ИСТИНЕ при успешном получении десятичного числа из строки. Для выделения шестнадцатеричного числа служит функция hread, имеющая аналогичный набор параметров.
Аналогично производится запись в файл. Создадим переменную, указывающую на файл, предназначенный для записи текста:
filedest : TEXT open WRITE_MODE is "report.txt";
Теперь можно подготовить строку для записи в этот файл.
write(LineOfText, a);
writeline(dest, LineOfText);
Подобным образом можно сформировать отчет, подходящий для изучения разработчиком, либо для автоматического анализа с помощью других программных продуктов.