Добрый день уважаемые коллеги!!
Часто начинающие плисоводы, начав изучать какой либо из HDL языков, задаются вопросом почему в них громоздко и не оптимально описываются соединения блоков между собой. Рассмотрим это на примере языка Verilog.
Действительно, при создании любого компонента, нужно объявить его интерфейс, т.е. описать его порты(имена, типы, направления). Для синтеза, только эти порты и будут видны компонентам более высокого уровня. Дальше этих интерфейсов прыгнуть нельзя. Почему так?
ИМХО потому что это и составляет объектную парадигму языков описания аппаратуры. Т.е. всё, что внутри модуля, скрыто от других компонентов, обмениваться компоненты могут только через интерфейсы/порты. Подозреваю, что концепция ООП была подсмотрена её авторами именно у HDL щиков.
Поэтому, если вам нужно получить доступ к сигналу модуля, которого нет в его интерфейсе, вам потребуется сначала добавить его в интерфейс, потом подключить в нужном вам объекте (instance) модуля. Например, если вы хотите вывести сигнал из модуля с глубиной иерархии 10, то вам потребуется тащить этот сигнал с самых низов. И ничего вы тут не сделаете, надо было думать раньше :)
Нет позвольте, скажет кто-то, но в Verilog есть иерархический доступ к сигналам любого модуля вида top.pipa.popa.signal. Да всё правильно, но сделано это только для моделирования и средствами синтеза не поддерживается. Потому что в этом случае, сама парадигма объектного программирования теряет смысл.
Средства HDL предлагают различные решения данной проблемы: это record в VHDL, struct/interface в SystemVerilog. Это позволяет собрать несколько сигналов в один "веник" и соединить этот "веник" только один раз. В том случае если нужно добавить сигнал, то он добавляется в определение этого "веника" и автоматический протаскивается через иерархию. У этих решений есть свои плюсы и минусы.
Что мне не нравится в решениях на структурах. Это жесткое ограничение структур. Т.е. определив один раз размеры полей структуры, нужно будет везде использовать только их (хотя в SV это не совсем так), нужно изменить размер поля, делайте новую структуру и т.д.
Что мне не нравится в решениях на интерфейсах. Интерфейс это не тип сигнала, а независимый объект, большей частью заточенный под шинные реализации, а не под соединение вида точка-точка, точка-частичная многоточка. Т.е. не расплетая "веник" интерфейса, вы можете соединить его только целиком. Если вам надо из него всего один, два сигнала то получается сильно коряво. Хотя и не является ошибкой.
Что же делать спросите вы? Мой ответ такой, развивать культуру разработки и использовать средства автоматизации. Ниже описан мой подход, основанный на личном опыте. Разработку проекта я веду по следующим шагам:
1. Написание краткого ТЗ, которое отвечает на вопрос "Что надо сделать?". Хочу отметить что вопрос стоит не "Как делать", а "Что делать". Даже если это проект для себя, я завожу небольшой файл readme.txt в котором описываю основные пункты будущего проекта.
2. Разработка функциональной схемы высокого уровня абстракции. Здесь я начинаю отвечать на вопрос "Как это делать?". Рассматриваю различные варианты, делаю прикидки, рисую схемы. Схемы я рисую от руки на бумаге, потом переношу в Visio.
3. Разработка функциональных схем среднего уровня абстракции. На этом этапе я начинаю строить каркас основных модулей из которых будет состоять проект. Я не опускаюсь на уровень отдельных регистров, проводников и т.д. Я указываю только необходимые функциональные модули (например счетчики чего-то там, фильтры, FSM и т.д.).
Хочу отметить, что на этом этапе еще не написано ни строчки иерархического кода, который пойдет в итоговый проект. Да какие то наброски существуют, но они представляют собой разрозненные модули.
4. На этом этапе идет проработка интерфейсов модулей на функциональной схеме. Я указываю категории групп сигналов каждого функционального модуля. В это же время, с помощью разработанного скрипта veriloginit я веду генерацию шаблонов и сборку модулей верхнего уровня иерархии. На этом этапе функциональность модулей не описывается. Все модули это всего лишь шаблоны в виде декларации модуля и его инстанса. Если на этом этапе всплывает недочет в интерфейсе модуля, то он заново генерируется, а сигнал добавляется. Все делается копипастом из шаблона, на вставку модуля тратиться 10-20 секунд.
5. На этом этапе уже есть собранные файлы верхнего уровня и теперь можно вписывать их функциональность. При генерации и написании модуля, я стараюсь учитывать как можно большее количество возможных ситуаций его использования. Параметризую порты, внутренние настройки и т.д., т.е. делаю модуль универсальным, в пределах разумного естественно.
Дальше идет моделирование и запуск на железе. Такой подход помогает мне работать достаточно быстро, комфортно и с малым количеством ошибок при сборке иерархии проекта.
В увеличении скорости разработки и уменьшении количества ошибок, мне также помогает разработанные для себя Coding Rules & Styles и генератор конечных автоматов psm_compiler. КА на количество состояний больше 5-6 я руками не пишу, предпочитаю их генерировать из текстового описания.
В аттаче я приложил используемые мной скрипты для автоматизации разработки. Все скрипты идут в категории free for use. Для запуска скриптов необходимо иметь установленный интерпретатор языка Python не ниже версии 2.4 %)
PS. Скрипты для генерации сделаны для Verilog/SystemVerilog. Для VHDL извиняйте, это перевернутая страница в моей жизни %)
UPD1. Добавил в скрипт veriloginit знаковые типы
Комментарии
instance (Computer En-Ru) - экземпляр (объекта некоторого типа)
Отправить комментарий