TCL — язык управления средой разработки
Рост производительности персональных компьютеров позволил использовать ПК с платформой Windows для проектирования сложных проектов на ПЛИС. Программное обеспечение для разработки ПЛИС на ПК приближается по своим функциональным возможностям к программам, работающим на рабочих станциях, и приобретает новые для пользователей ПК свойства. Одним из таких свойств является встраиваемый язык TCL.
Процесс разработки ПЛИС включает в себя процедуру описания поведенческой модели узлов проектируемого устройства, тестирование полученной модели, процедуру синтеза, тестирование синтезированной модели. Существуют другие подходы к проектированию, и при использовании различных средств количество и предназначение этапов разработки может изменяться, но для рассмотрения общего подхода предлагается вышеописанная схема.
Описания поведенческой модели в настоящее время выполняются на высокоуровневых языках описания аппаратуры: Verilog HDL и VHDL. Проект обычно содержит много модулей, разрабатываемых различными разработчиками, библиотеки, также практикуется повторное использование кода. Таким образом, проект имеет структуру, описание которой требуется не только на уровне языка описания аппаратуры, но и на уровне хранения информации: в каких файлах хранятся модули или библиотеки, куда направлять результаты или сообщения и т. п. Одно из назначений языка управления в среде разработки — управление структурой проекта и связь с операционной системой.
При отладке проекта (симуляция поведенческой модели) появляется потребность в обработке событий, возникающих во время симуляции, и реакция на них. Например, моделирование внешних воздействий или отображение результатов в преобразованной форме. Использование языка HDL для этих целей может оказаться не эффективным, и любое изменение в описании модели влечет за собой необходимость перезапуска симуляции. Таким образом, развитый скриптовый язык позволяет облегчить моделирование проекта.
Наибольшую вычислительную мощность требует процесс синтеза, как правило, это итеративный процесс, который приходится запускать с различными параметрами для того, чтобы добиться требуемых характеристик по времени и занимаемой площади. Отсутствие языка управления требует присутствия оператора для изменения параметров синтеза, перезапуска и сохранения полученных результатов. Наличие командного языка позволяет автоматизировать этот процесс.
Преимущество стандартного скриптового языка перед графической оболочкой управления заключается в упрощении процедуры переноса проекта с одной платформы на другую. Если управляющие скрипты разбиты на две части: платформо-зависимую и универсальную, то изменения потребует только первая часть скриптов. А так как функции, выполняемые специализированными командами в разных средах проектирования, достаточно похожи (иногда достаточно заменить только имя команды), то изменения платформо-зависимой части не вызывает труда. Забегая вперед, скажу, что эти изменения могут быть выполнены скриптом TCL, так как язык имеет мощные средства обработки текста.
Почему в качестве такого языка выбран TCL? Плюс этого языка в том, что библиотеки распространяются свободно и позволяют создавать приложения (объединять интерпретатор TCL и скомпилированные функции, описанные на С/С++ или другой системе), в которых синтаксис языка расширяется функциями, запрограммированными пользователями и выполняющими основную задачу средства проектирования (например project, do_optimize, do_build_generic, constrain_ file и т. п). Из-за того что эти функции скомпилированы, скорость их исполнения высока, а вызывающий их интерпретатор TCL имеет плюсы, присущиеинтерпретаторам. Простота синтаксиса и логики работы интерпретатора, а также существование языка в течение длительного времени обеспечивает выигрыш по сравнению с другими языками, имеющими подобные свойства (Perl, Scheme, Java, Python и др.).
Так как TCL используется программистами для разработки пользовательских интерфейсов и интернет-приложений, то документация содержит много лишнего с точки зрения пользователя средств разработки (как правило, описание графического интерфейса Тk).
Владеющим английским языком советую посетить
www.scriptics.com. К настоящему времени мне не удалось найти соответствующих ресурсов на русском. В описании я постараюсь не прибегать к использованию специфических команд конкретной среды разработки, симулятора, синтеза, так как в различных средах эти команды имеют различный синтаксис, описание которого нужно искать в документации. Для проверки прилагаемых в статье примеров будет достаточно просто интерпретатора TCL, не встроенного в какую-либо среду разработки, для Windows интерпретатор TCL можно загрузить с
http://sources.redhat.com/cygwin/ (нужен пакет tcltk — это библиотека, но я рекомендую поставить все утилиты). Исполняемые файлы wish или tclsh (cygwish — для Windows). Следует заметить, что в некоторых версиях cygwin содержатся ошибки, например, в работе с регулярными выражениями. Пользователи Unix сумеют найти wish или tclsh без моей помощи. Но, конечно, гораздо эффективнее будет разобраться с описанием дополнительных tcl-команд, реализованных в средстве проектирования, и воспользоваться скриптами с практической пользой.
Основы синтаксиса
Одним из плюсов TCL является простота синтаксиса. Все конструкции языка имеют следующий вид:
|
разделителями являются «;» или перевод строки.
Что интересно — даже управляющие конструкции языка: циклы, условные операторы и т. п. реализованы таким же образом.
Например:
|
В этом примере два оператора:
- set — имеет два аргумента: а — имя переменной, 10 — присваиваемое значение;
- expr — имеет произвольное число аргументов (в данном примере 1) и выполняет математические вычисления;
- % — это приглашение, которое обычно используется в tcl (его вводить не надо), если вводимая команда занимает несколько строк, то приглашение может иметь вид «>».
- expr — имеет произвольное число аргументов (в данном примере 1) и выполняет математические вычисления;
Первый оператор завершен знаком «;», а второй — переводом строки. Результат, который должен быть выведен на экран:
|
Для того чтобы узнать, какие команды существуют в системе, можно воспользоваться командой info:
|
Как можно видеть из отклика, управляющие конструкции языка if, for, while и др. являются командами. Часть команд может быть описана на языке TCL. Чтобы получить список таких команд, используйте следующее выражение:
|
Чтобы посмотреть реализацию (например, процедуры history), наберите
|
Если первый символ команды #, то оставшаяся часть строки — комментарий.
|
Подстановки
Перед исполнением строки интерпретатор выполняет подстановки. Использование подстановок — основной механизм программирования на TCL. Подстановки должны быть понятны пользователям юникс-подобных систем, а пользователям других ОС я рекомендую внимательно изучить следующие описания, попробовать написать свои команды с подстановками и предсказать результат.
- символ «$» обозначает подстановку переменной: то есть во всех случаях, когда нужно получить значение переменной, следует писать $имя_переменной, вместо имя_переменной
%set a 20; expr $a*$a
400но следует помнить, что некоторым процедурам требуется именно имя переменной, а не ее значение, примерами таких процедур являются
%set a
%incr a
%foreach a {1 2 3 4} {puts -nonewline «$a «}
1 2 3 4 % - для подстановки результата команд используются квадратные скобки «[« «]», то есть выполняется команда — для этого запускается еще одна процедура интерпретатора TCL, — и результат выполнения заменяетскобки с содержимым:
%set a 1;set b [incr a]
%foreach a {1 2 3 4} {puts «a=$a a^2=[expr $a*$a]»} - символьная подстановка «» используется так же, как и в С для подстановки непечатных символов: n — перевод строки, t — табуляция и т. д. Во время ввода команды знак «» перед переводом строки позволяетпродолжить команду на другой строке.
% puts «atbnc
dte\f»
a b
c d ef
%
Для работы языковых конструкций подстановку иногда следует отложить, для этого используются фигурные скобки «{» «}». Рассмотрим пример с фигурными скобками подробнее: для работы цикла foreach требуется, чтобы тело цикла (puts «a=$a a^2=[expr $a*$a]») выполнялось каждый раз с новым значением переменной а. Поэтому оно помещается в фигурные скобки, тем самым указывается, что подстановки должны выполняться внутри цикла во время исполнения итераций. То есть то, что заключено внутри фигурных скобок, игнорируется интерпретатором. Исполнение произойдет, когда скобки будут «раскрыты».
|
В предлагаемом примере переменная а получает значение «expr 3+2», и для того чтобы его вычислить используется процедура eval.
Внимательный читатель может задать вопрос: почему нельзя воспользоваться квадратными скобками для вычисления значения вместо eval? Это связано с тем, что интерпретатор выполняет подстановку один раз, то есть выполняется один проход. Для того чтобы выполнить подстановку и получить результат в выражении, полученном после подстановки, выполняемой автоматически, требуется принудительно запустить интерпретатор, используя процедуру eval.
Кавычки используются для блокирования действия символов-разделителей (пробелов, табуляций и т. п.). Но, в отличие от фигурных скобок, интерпретатор выполняет подстановки в строке, заключенной в кавычки.
Переменные TCL
Все переменные в TCL являются символьными строками. При выполнении арифметических выражений строки-операнды преобразуются в численное представление, а после завершения вычислений результат преобразуется в строку.
|
В данном случае фигурные скобки показывают, что требуется значение переменной а, если бы скобок не было, интерпретатор искал бы переменную а456. Если строка содержит внутри себя пробелы, то она должна заключаться в кавычки.
В TCL поддерживаются массивы и списки. Массив реализован как хэш-таблица, поэтому размер и размерность массива могут быть какими угодно и даже допустимо использование строковых значений в качестве индекса.
|
Оператор unset нужен, чтобы удалить переменную а. Создавая элемент массива а(1), мы создаем массив, который может рассматриваться как одномерный массив set a(1) privet, хэш-таблица set a(string) 100, или как четырехмерный массив set a(1,2,35,9) 5.
Для работы с массивами существует набор процедур
|
Распечатать массив можно процедурой parray, остальные операции выполняет процедура array, в которой первый аргумент определяет операцию, а второй — имя массива. Некоторые из возможных действий с массивами:
- еxist — определяет, является ли данный объект массивом;
- size — возвращает количество элементов;
- names — выдает значения индексов массива.
В последнем примере видно, что для массивов подстановка производится дважды: подстановка индексов, а затем подстановка значения элементов.
В качестве упражнения предлагаю проверить, что выдаст следующая конструкция:
|
Важным объектом является список (list). Как правило, многие процедуры TCL возвращают список или получают его в качестве аргумента. Неоднократно использовавшаяся в примерах процедура foreach получает своим вторым аргументом список, значения из которого последовательно принимает переменная цикла (первый аргумент). Собственно, любая запись, не заключенная в кавычки, является простым списком. Для разделения элементов используется пробел.
А кавычки (или фигурные скобки) используются для того, чтобы заключить слова, разделенные пробелами, в один элемент. Вообще, любая TCL-конструкция является списком, а любой список является синтаксически правильной конструкцией. Можно рассматривать список как строку, а список, элементами которого являются другие списки, как строку, содержащую пары фигурных скобок. То есть разделение на строки, списки и языковые конструкции является условным — для интерпретатора TCL эти объекты не различаются. Особым элементом является массив, так как это единственный элемент, в котором подстановка выполняется дважды: «вычисление» индекса и получение значения по индексу.
Регулярные выражения
Так как основным типом данных, которые обрабатываются языком TCL, являются строки, то нужен механизм обработки строк. Такой механизм существует в TCL и называется «регулярными выражениями» (regexp). Пользователи, работающие в юникс-подобных системах, наверняка сталкивались с обработкой регулярных выражений, так как она реализована во многих утилитах этих ОС. Упрощенным примером реализации регулярных выражений в DOS/Windows является возможность использования символов «*» и «?» при задании шаблона для работы с файлами.
TCL поддерживает несколько механизмов регулярных выражений и позволяет задавать шаблоны различной сложности для поиска фрагментов строк. Общая идея состоит в использовании специальных символов с предопределенным значением. Наиболее простой вариант называется globbing и использует следующие символы:
- ? — заменяет любой одиночный символ;
- * — заменяет любую группу символов (в том числе и нулевой длины);
- [набор_символов] — любой символ из набора;
- [символ_А-символ_Z] — диапазон символов (не всегда работает корректно с русскими буквами);
- {строка1,строка2,…} — заменяет любую строку.
- * — заменяет любую группу символов (в том числе и нулевой длины);
Как правило, тип globbing используемых выражений задается ключом -glob или оговаривается, что команда понимает только такой тип выражений, например, команда glob, которая служит для поиска файлов.
Для проверки работы регулярных выражений воспользуемся командой поиска в списке lsearch.
|
Для того чтобы по индексу получить значение, используется lindex.
|
Так как lsearch возвращает первую строку, удовлетворяющую регулярному выражению, то для того, чтобы получить все строки, напишем простой скрипт.
|
Данный скрипт можно сохранить в файл (стандартным расширением является tcl) или использовать повторный ввод (если интерпретатор собран с поддержкой readline и history, то для повтора команды можно использовать клавишу «стрелка вверх»).
Используемый цикл while повторяется до тех пор, пока lsearch находит в списке строки, удовлетворяющие образцу, заданному регулярным выражением (если соответствия не обнаружено, то lsearch возвращает -1). В теле цикла производится печать обнаруженной строки и удаленние ее из списка blist. Таким образом, по завершении цикла получается распечатка выражений, удовлетворяющих образцу, а список blist содержит оставшиеся выражения. Присваивая переменной pattern различные регулярные выражения, можно проверить работу скрипта и механизм действия регулярных выражений.
Более мощную систему представляют собственно регулярные выражения regexp:
- . — любой символ, кроме перевода каретки;
- ^ — начало строки;
- $ — конец строки;
- regexp* — выражение, повторенное любое число раз, в том числе 0;
- regexp+ — выражение, повторенное любое число раз, большее 0;
- regexp? — выражение либо его отсутствие.
- regexp{N} regexp{N,M} regexp{N,} — показывает точное число повторений {N}, интервал {N,M} — больше или равно N и меньше или равно M, и {N,} — больше или равно N.
- ^ — начало строки;
Таким образом , regexp* == regexp{0,} , regexp+ == regexp{1,} , regexp? == regexp{0,1}: regexp1|regexp2 — выражение удовлетворяет либо regexp1, либо regexp2;
- [abc] — набор символов;
- [^abc] — набор исключенных символов (то есть в данном месте проверяемой строки такого символа быть не должно);
- [a-z] — интервал символов;
- [^a-z] — интервал исключенных символов;
- () — задает приоритет при построении regexp;
- — отменяет значение специальных символов.
- [^abc] — набор исключенных символов (то есть в данном месте проверяемой строки такого символа быть не должно);
Для проверки работы регулярных выражений воспользуемся скриптом с командой поиска в списке lsearch. Нужно заменить ключ -glob на -regexp (существует еще ключ -exact, который задает поиск по точному совпадению).
|
Обратите внимание, что образец «*» в glob-выражениях соответствует образцу «.*» в regexp-выражениях. Достаточно распространенная ошибка — использование в регулярных выражениях (regexp) «*» вместо «.*».
Попробуем задавать разные образцы regexp. Я буду приводить только образец и совпавшие строки, а скрипт будет использоваться тот же.
|
Для того чтобы научиться использовать регулярные выражения, можно попрактиковаться в задании образца для приведенного скрипта, выбирающего выражения из списка.
Управляющие конструкции
Как и в любом другом языке программирования, в TCL есть набор управляющих конструкций. Управляющие конструкции содержат какое-либо условие (cond) и выполняемые операции — тело (body). Из-за принципа подстановки в TCL, для того чтобы исполнение операторов в конструкциях условия и тела происходило во время выполнения (а не разбора) выражения — их следует заключать в фигурные скобки. В остальном синтаксис большинства управляющих конструкций похож на синтаксис процедурных языков.
Управляющие конструкции TCL можно разделить на группы:
- условные: if then elseif else switch;
- циклы: for, while, foreach, continue, break;
- процедуры: proc, return, global, uplevel, upvar.
Я не буду подробно останавливаться на конструкциях, подобных используемым в других языках, а приведу синтаксис и пример.
|
Ключевое слово then не обязательно.
|
Эти действия могут быть выполнены командой switch:
|
Циклы реализуются следующим образом:
|
В дополнение к приведенным выше примерам использования циклов приведу примеры использования циклов с командами continue, break.
|
Важным элементом языка являются процедуры, определяемые пользователем. Перед использованием процедура должна быть объявлена с помощью команды proc. В качестве примера рассмотрим рекуррентную процедуру вычисления факториала.
|
Для доступа к коду процедуры и получения информации о ней можно воспользоваться командой info: info args fac или info body fac. В качестве примера оформим процедуру поиска значений в списке.
|
Предположив, что переменная alist сохранила значение, определенное выше, вызовем процедуру.
|
В процедуре TCL параметры и все используемые переменные (set) являются локальными, для того чтобы получить доступ к глобальным переменным, требуется воспользоваться командой global. Перепишем процедуру, так чтобы она работала с глобальной переменной blist. При использовании процедуры find_all_glob значение переменной blist, объявленной на верхнем уровне, не меняется.
|
Использовать глобальные переменные не всегда удобно, поэтому TCL предоставляет пользователю механизм работы с «вызовом по ссылке», то есть вместо копии переменной в параметре можно получить саму переменную и модифицировать ее. Этот механизм реализуется командой upvar.
|
Формат директивы uplevel: uplevel parameter_name local_variable. После объявления локальной переменной с помощью директивы uplevel, любые операции с ней будут приводить к изменению переменной, полученной в качестве параметра. Следует обратить внимание, что параметр, используемый в процедуре с командой uplevel, передается без подстановки (без знака $).
В TCL есть еще одно замечательное свойство, которое позволяет пользователю создавать управляющие конструкции языка. Очень мало языков имеет такую возможность. На практике мне не приходилось пользоваться этой возможностью, но в сложных скриптах, предназначенных для распространения, и в коммерческих продуктах такие конструкции встречаются. Реализуется это с помощью директивы uplevel. Напишем цикл do:
|
Смысл команды uplevel в том, что ее аргумент исполняется на верхнем уровне и имеет доступ к переменным верхнего уровня. В процедуру может передаваться произвольное число параметров, и процедура может получать параметры с предопределенными значениями (default). При вызове процедуры с предопределенными параметрами, если фактический параметр не передается, то формальный принимает предопределенноезначение.
|
Для передачи произвольного числа аргументов указывается специальный аргумент args. После вызова процедуры этот аргумент содержит список параметров.
|
В описании аргумента с предопределенным значением используется конструкция {name value}.
Важно рассмотреть взаимодействие tcl с операционной системой: как правило, команды ОС выполняются из tclsh. Но также существует команда exec, которой следует пользоваться в некоторых случаях. Следует учесть, что в DOS и Windows разделителем поддиректорий в полном имени файла выступает символ обратной косой черты «», а не косой черты «/», принятый в Unix. Если программа автоматически не переводит этот разделитель, то пользователям Windows следует использовать ‘\» для обозначения «» — это стандартная необходимость при использовании утилит Unix под Windows. В cygwin реализовано автоматическое преобразование разделителя и в дальнейшем я буду использовать «/».
Для получения списка файлов текущей директории используется команда glob:
|
Пользуясь образцами globbing, можно выбрать требуемую группу файлов (например, исходники на verilog и отчеты: glob *.v *.log).
Смена директории — cd, получить имя текущей директории — pwd. Также существует набор специфических команд, связанных с обработкой ошибок и отладкой, поддержкой многозадачности, контролем времени, взаимодействием с ОС и т. п.
Зная основы языка и принципы работы интерпретатора, не составит труда разобраться с этими возможностями и правильно использовать команды, не приведенные в данном обзоре.
Примеры использования
Приведу примеры использования TCL в среде разработки Ambit. Для использования примеров с другой средой следует заменить специфические команды Ambit на соответствующие команды используемой среды.
Пример 1: сохранение и восстановление базы данных в сжатом виде:
|
Для использования этих процедур в другом средстве синтеза нужно заменить write_adb, read_adb на команды записи и чтения, реализованные в этом средстве.
Пример 2: генерация отчета статического временного анализа
.
|
Здесь специфической командой является report_timing с параметрами.
Пример 3: генерация доклада о нарушении ограничений.
|
В этом примере специфические команды find, set_current_instance, report_design_rule_ violations.
Пример 4: выравнивание тактового дерева после завершения автоматического синтеза:
|
Заключение
Предполагается, что в ближайшее время языком управления в средствах разработки ПЛИС будет оставаться TCL. Данная статья должна помочь разработчику создавать скрипты TCL и понимать скрипты, написанные другим разработчиком. Несмотря на большое количество разнообразных скобок, которые вводят в заблуждение начинающего пользователя, TCL является простым для понимания и удобным языком. Использующийся в TCL принцип однократной подстановки позволяет упростить программную реализацию интерпретатора и в то же время сделать основы синтаксиса языка простыми для запоминания человеком.