Настройка визуального представления сигналов при моделировании в среде ModelSim (часть 1)
Добрый день читателям ! Меня зовут Алексей, я занимаюсь работой с ПЛИС (FPGA) уже более 15 лет. Хабр читаю давно, но статьи здесь никогда не писал. В общем решил попробовать. Не знаю, насколько на Хабре интересны темы, связанные с ПЛИС? Но всё же, вдруг кому-то эта небольшая статья будет полезна.
Вступление
Данная статья описывает настройки основных вкладок среды моделирования ModelSim и работу в них. Статья не претендует на подробное руководство по использованию ModelSim. Это скорее краткое изложение личного опыта автора по базовой настройке среды моделирования для комфортной работы в ней. Здесь не рассматриваются вопросы, связанные с компилированием библиотек, созданием файлов моделей (testbench) и скриптов для их запуска. Это темы для отдельных статей.
Для чего вообще нужно что то настраивать, и зачем тратить на это время? Разработка программы, или как в случае с ПЛИС, разработка HDL-описания – это не только написание кода, но и его последующая отладка. И зачастую, именно на процесс отладки тратится наибольшая часть времени. Помочь сделать отладку удобной, а моделирование в среде ModelSim комфортным, и тем самым сократить общие затраты времени на разработку – вот основная цель данной статьи.
1. С чего начать? Вкладка «Wave»
Будем считать, что у нас уже имеется HDL-код тестируемого модуля, файлы модели (testbench) и скрипты для запуска моделирования. И всё это запустилось и без ошибок скомпилировалось в ModelSim.
Основная работа при моделировании и отладке HDL-кода проекта в среде ModelSim обычно происходит на вкладке «Wave».
Если по какой-то причине этой вкладки нет, то скорей всего она была отключена в настройках. Включается она просто – щелкаем левой кнопкой мышки в основном меню на «View», затем в открывшемся списке ставим галочку напротив «Wave».
Вкладка появится в горизонтальном списке внизу окна программы. Перейти на нее (как и на любую другую вкладку) можно по щелчку левой кнопкой мышки.
Теперь можно заняться добавлением сигналов и на вкладку «Wave». Если быть более точным, то на данную вкладку переносятся объекты (сигналы, переменные, константы и т.д.) из вкладки «Objects». Но так как в большинстве случаев работа при моделировании идет именно с сигналами, то для удобства будем называть все эти объекты сигналами.
2. Добавление сигналов
В самом начале работы вкладка «Wave» скорей всего будет пустой. Нужно добавить на нее сигналы. Для начала добавим сигналы, описанные в файле модели (testbench). Обычно это внешние сигналы, подключенные ко входам и выходам тестируемого модуля, а также какие-нибудь вспомогательные сигналы. Для их добавления перейдем на вкладку «Transcript» и в консоли введём команду:
add wave *
После выполнения команды возвращаемся обратно в «Wave». Здесь в левой колонке будет выведен список всех сигналов из файла модели. Выглядит это так:
кДля каждого сигнала приводится его полное имя. То есть кроме названия самого сигнала указывается иерархия модулей, внутри которой он объявлен. В данном примере все сигналы находятся в самом верху иерархии – в файле модели, верхний модуль которой имеет название «sdram_memory_ctrl_vhd_tst». Если же сигнал расположен в модуле, находящимся в глубине иерархии, то его полное имя при отображении может быть слишком длинным. Например, сигнал для счетчика адреса внутреннего FIFO имеет полное имя:
sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/addr_wr
Такие обозначения сигналов не слишком удобны при работе. Для того чтобы отображалось только название, нужно нажать на кнопку «Toggle leaf names», расположенную под списком сигналов в левом нижнем углу.
Как не трудно заметить, короткие наименования сигналов гораздо более удобны при работе.
3. Вкладки «sim» и «Objects»
Конечно же при полноценном моделировании и отладке невозможно ограничиться только лишь внешними сигналами. Необходимо иметь перед глазами также и сигналы, расположенные внутри тестируемого модуля (и его подмодулей). Для их добавления необходимо перейти на вкладку «sim». Здесь представлен иерархический список. Самым верхним в этом списке, как уже упоминалось, будет модуль, описывающий саму модель. Внутри него находится тестируемый модуль со своими подмодулями. Также могут присутствовать дополнительные модули, если они были подключены внутри файла модели.
Следует заметить, что в списке указывается не само название модуля, а имя, присвоенное его копии (одновременно может быть несколько копий одного модуля). Название, каким оно присутствует в файле HDL-описания модуля, приводится правее – в графе «Design unit». Например, тестируемый модуль здесь – это «i1», в файле HDL-описания его название – «sdram_memory_ctrl».
Теперь в иерархическом списке выбираем модуль, в котором находится интересующий нас сигнал. В данном примере это модуль «br_core». После этого переключаемся на вкладку «Objects». Здесь будут показаны все сигналы, которые присутствуют в модуле, выбранном на вкладке «sim». Теперь находим нужный нам сигнал (или несколько сигналов) и отмечаем его левой кнопкой мышки. Далее нажимаем на него правой кнопкой и выбираем пункт «Add Wave» – сигнал будет автоматически перенесен на вкладку «Wave».
В данном примере выбран сигнал «addr_wr». Также можно перенести нужный сигнал, используя вкладку «Transcript», выполнив следующую консольную команду, например:
add wave -noupdate sim:/sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/addr_wr
В таком варианте необходимо указать полное имя сигнала со списком всех подмодулей. Если же нужны сразу все сигналы из выбранного модуля, то для этого в консольной команде следует заменить название сигнала на символ «*», например:
add wave -noupdate sim:/sdram_memory_ctrl_vhd_tst/i1/w_fifo_inst/br_core/*
Постоянное переключение между вкладками «sim», «Objects» и «Wave» может быть утомительным. Для одновременного отображения нескольких вкладок на одном экране служит кнопка «zoom/unzoom», расположенная в правом верхнем углу.
Теперь можно напрямую перетаскивать мышкой нужные сигналы из «Objects» на «Wave» без дополнительных переключений между вкладками.
4. Компоновка сигналов
После того как на вкладку «Wave» перемещены все нужные сигналы, в принципе, уже можно было бы начинать моделирование. При тестировании небольших модулей так и поступают. Но при работе с большим проектом, содержащим вложенные подмодули, на вкладке «Wave» может одновременно оказаться несколько десятков, а то и сотни сигналов. Было бы удобно каким-то образом их скомпоновать, чтобы банально не запутаться в разнообразии сигналов. Существует несколько основных вариантов.
Первый – это группировка. Выполняется она просто. Выделяются несколько сигналов, затем по команде «Group» из них формируется единая группа. По умолчанию группа создается с именем «New Group», но в любой момент её можно переименовать. В приведенном примере создана группа с именем «GRP_R», в которую объединены сигналы, связанные с чтением данных.
Тот же самый результат можно получить при помощи консольных команд, например:
add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_rts
add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_data
. . .
add wave -noupdate -expand -group GRP_R /sdram_memory_ctrl_vhd_tst/R_extra_info
Значение «-expand» указывает, что созданная группа будет сразу отображаться раскрытой, то есть со списком сигналов всех сигналов, из которых она состоит. Если это значение убрать, то отобразится только название группы. Сигналы будут скрыты. Кроме того, можно создавать группы внутри уже существующих групп. Делается это всё той же командой «Group».
Второй вариант для компоновки сигналов – это использование разделителей. Здесь тоже нет никаких сложностей. Для добавления данного элемента служит команда «Add –> New Divider». По умолчанию разделитель создается с именем «New Divider», но в любой момент его можно переименовать. В приведенном примере созданы разделители с именами «READ» и «LOGIC».
Также как и для группы, для создания разделителя можно использовать консольные команды, например:
add wave -noupdate -divider -height 35 READ
add wave -noupdate -divider -height 35 LOGIC
В примере используется параметр «-height» со значением, равным 35. Он задает размер разделителя по высоте. Если этот параметр не использовать, то будет создан разделитель со значением высоты, равной 17 единиц.
Последний вариант компоновки сигналов, о котором хотелось написать – это комбинирование. Данный вариант удобно использовать при работе с шинами. Например, имеется сигнал, представляющий собой шину данных некоторой разрядности. Иногда может быть удобно разбить ее на отдельных части по 8 бит каждая.
Данная операция выполняются при помощи команды «Combine Signals…», или же при помощи консольных команд, например:
quietly virtual signal -install /<...> { /<...>/q_a(255 downto 248)} byte31add wave -noupdate /<...>/byte31
Примечание: сигнал «q_a» из данного примера находится глубоко внутри иерархии. Для экономии места в примере не указано его полное имя, оно заменено на <…>.
В итоге, после всех выполнения всех итераций, результат компоновки сигналов выглядит так:
Выведены все необходимые для работы сигналы. Они удобно скомпонованы, разделены на группы, которые можно развернуть либо свернуть по необходимости. Добавлены разделители. Всё находится на своём месте, вероятность ошибок и путаницы сведена к минимуму.
5. Подводя промежуточный итог
В данной части статьи были разобраны и проиллюстрированы подготовительные итерации, предшествующие непосредственно процессу моделирования. Может показаться, что вся эта подготовка займет много времени, и без неё можно легко обойтись? На самом деле, после некоторой практики, на данные действия будет тратиться не более 5-10 минут. Зато удобство при дальнейшей работе сэкономит часы!
Изначально, я хотел описать здесь еще и сам процесс моделирования, и сопутствующие ему настройки. Но, кажется, это будет слишком много для одной статьи. Решил разбить её на две.
Поэтому процесс моделирования, работу с временными диаграммами и создание файла настроек планирую подробно разобрать в следующей части статьи.
Автор: ClockEnable