Часть 11: ИНТЕРПРЕТАТОРЫ
11-2: Интерфейс Lisp |
Этот раздел поясняет интерфейс
языка интерпретатора Lisp в Electric, системе
разработки VLSI . Этот интерфейс встроен
в верхней части ELK Lisp 3.0, диалекта Scheme
(см. http://www-rn.informatik.uni-bremen.de/software/elk/elk.html).
На протяжении этого раздела примеры кода Lisp будут появляться underlined (подчеркнутыми). Например, предикат "getarcproto" получает имя прототипа дуги и возвращает указатель на этот объект. Это кодируется, как (getarcproto 'Metal-1), что вычисляется по указателю формы #[arcproto Metal-1].
В разделе предполагается, что читатель очень хорошо знает Electric, и как-то знаком с внутренним строением системы. Внутреннее руководство (Internals Manual) (документ, доступный на Static Free Software) обеспечивает широкий, С-ориентированный взгляд на информацию, описанную здесь. Для пользователей Lisp, однако, этот раздел суммирует важные аспекты внутреннего руководства. В общем, наилучший путь к пониманию этого раздела - выполнить каждую команду по мере ее объяснения.
Для вызова интерпретатора Lisp используйте субкоманду LISP... команды Language Interpreter меню Tools. На некоторых системах, возможно, понадобится переместить курсор в окно сообщений (текстовое окно), чтобы интерпретатор "слышал" вас.
Если у вас есть дисковый файл с кодом
Lisp, вы можете прочитать его в интерпретатор,
введя:
(load 'FILENAME)
Чтобы вернуться в Electric из Lisp, введите ^D (удерживайте на клавиатуре клавишу Control и нажмите "D"). В Windows вы должны нажать клавишу ESC.
Полная база данных Electric - это коллекция объектов, каждый из которых имеет произвольное количество атрибутов. Этот раздел кратко показывает типы объектов и то, как они связаны. Дальнейшее знакомство можно продолжить по внутреннему руководству (Internals Manual). См. в разделе 11-5 список атрибутов этих объектов.
Индивидуальные компоненты внутри схемы описаны NODEINST объектами (образцы узлов), а индивидуальные провода описаны ARCINST объектами (образцы дуг). Соединения между компонентами и провода описаны PORTARCINST объектами (образцы портов, которые соединены с дугами). Поскольку и компоненты, и провода имеют геометрию, каждый, тем не менее, имеет ассоциированный объект GEOM, и все объекты GEOM в фасете организованы пространственно в R-дерево с набором RTNODE объектов.
Класс объектов также существует для описания всех индивидуальностей данного типа. Объект NODEPROTO описывает компоненты прототипов, которые могут иметь много индивидуальных NODEINST объектов, ассоциированных с ними. Например, CMOS P-транзистор описан единственным объектом NODEPROTO, и есть много NODEINST объектов для каждого образца такого транзистора в любой цепи. Иерархия реализована вводом сложных компонент, больше известных как фасеты, представленных таким же образом, как примитивы компонент, такие как транзисторы. Например, цепь ALU описана единственным объектом NODEPROTO, а каждый образец этой цепи выше в иерархии описан объектом NODEINST.
Объект CELL собирает разные виды и версии схемы. Каждый из них назван "facet" (представленный объектом NODEPROTO), и фасет имеет и указатель VIEW, и номер версии.
Дополнительно к прототипам компонент ARCPROTO описывает классы проводов, а PORTPROTO описывает классы проводов соединения компонент (component-wire connections). Дополнительный объект PORTEXPINST существует для экспортов. Объект NETWORK описывает электрически соединенные ARCINST и PORTPROTO объекты внутри FACET.
В качестве дальнейшей агрегации объектов есть LIBRARY - коллекция ячеек и фасет. TECHNOLOGY - набор примитивов компонент (NODEPROTOs) и всех классов проводов (ARCPROTOs).
Дополнительно к выше описанным указателям на объекты есть некоторые стандартные типы значений, которые могут ассоциироваться через getval:
integer |
32-bit integer |
address |
32-bit integer |
char |
8-bit byte |
string |
null-terminated string of bytes |
float |
32-bit floating point number |
double |
64-bit floating point number |
fract |
fractional integer number that is multiplied by 120 |
short |
16-bit integer |
window |
window partition object |
window-frame |
display window object |
constraint |
constraint system object |
graphics |
graphical attributes object |
Также есть возможность иметь отображаемые переменные (те, чьи значения появляются на объекте) с ключевым словом: displayable.
Для начала поиска в базе данных важно
знать текущую библиотеку. Это сделано
так:
(curlib)
возвращает
указатель на объект LIBRARY (например,
#[library noname]). Отсюда текущий фасет
может быть получен с помощью:
(getval
(curlib) 'firstnodeproto)
Существенно, что любой атрибут может
быть проверен с помощью getval, и новый
атрибут может быть создан с помощью
setval. Getval имеет следующий формат:
(getval OBJECT 'ATTRIBUTE)
где OBJECT
- ассоциируемый объек, а ATTRIBUTE -
запрашиваемые атрибуты. Список всех
существующих атрибутов на объектах
Electric дан в конце этого документа.
Новые атрибуты могут быть созданы на
любом объекте с помощью setval. В общем,
многие из существующих атрибутов,
которые описаны в конце этого документа,
не могут быть установлены с помощью
setval, но управляются специальными
предикатами модификации базы данных.
Формат setval:
(setval OBJECT
'ATTRIBUTE VALUE OPTIONS)
где OPTIONS это либо
0, либо 'displayable для показа этого
атрибута при отображении объекта.
Например, для добавления нового атрибута,
названного "power-consumption" к компоненту
транзистор "t1", и придания ему
значения 75, используйте:
(setval
t1 'power-consumption 75 0)
Для добавления
отображаемого имени узлу "t1"
используйте:
(setval t1 'NODE_name "Q1"
'displayable)
Для установки массива
значений используйте vectors. Например,
для установки очертания узла чисто слоя
- pure-layer node "metal" со звездочкой
используйте:
(setval metal 'trace
(vector -1000 0 0 1000 1000 0 0 -1000) 0)
Единственный элемент в массиве
атрибутов может быть установлен с
помощью:
(setind OBJECT 'ATTRIBUTE INDEX
VALUE)
где INDEX - это 0-базируемый
элемент массива.
И, наконец, атрибут может быть удален
с помощью:
(delval OBJECT
'ATTRIBUTE)
Однако только те атрибуты,
которые были созданы setval, могут
быть удалены таким образом. Другие
атрибуты защищены.
Для создания нового фасета в текущей
библиотеке используйте:
(newnodeproto
'FACETNAME (curlib))
возвращающий указатель
NODEPROTO, который может быть использован
при последующих вызовах, размещающих
компоненты и провода в этом фасете.
Для получения адреса существующего
NODEPROTO используйте:
(getnodeproto
'FACETNAME)
возвращающий тот же тип
значения, что и newnodeproto. Таким образом,
код:
(define myfacet (newnodeproto 'adder{lay}
(curlib)))
тот же, что и код:
(newnodeproto
'adder{lay} (curlib))
(define myfacet
(getnodeproto 'adder{lay}))
а оба - часть
представления "layout" ячейки, названной
"adder".
В качестве отступления, предикат
getcell может быть использован для
получения объекта CELL, как здесь:
(getcell 'adder)
возвращая то
же, что и:
(getval myfacet 'cell)
Для создания компонента в фасете
используйте:
(newnodeinst PROTO LOWX
HIGHX LOWY HIGHY TRANSPOSE ANGLE FACET)
где PROTO
это NODEPROTO компонента, который будет
создан, LOWX, HIGHX, LOWY и HIGHY
- это рамки компонента, ANGLE число
десятков градусов поворота компонента,
TRANSPOSE это не нуль для транспонирования
ориентации компонента (после поворота),
а FACET - NODEPROTO, в котором будет
размещаться компонент.
Четыре ограничивающих значения это
нечто путанное для вычисления. Для
примитивов компонент (таких, как
транзистор) любое значение приемлемо,
и компонент будет масштабирован. Однако
все еще хорошо бы знать значение по
умолчанию, которое может быть получено
из NODEPROTO с помощью getval следующим
образом:
(define tran (getnodeproto
'P-Transistor))
(define lowx (getval tran
'lowx))
(define highx (getval tran
'highx))
(define lowy (getval tran
'lowy))
(define highy (getval tran
'highy))
Когда сложные компоненты
(фасеты) размещаются, контуры ДОЛЖНЫ
быть точно такими же, как рамки содержимого
фасета. Эта информация доступна
вышеприведенным образом. В качестве
примера newnodeinst, и получения вычисления
выше показанного контура, предопределенный
размер P-транзистора создается в "adder"
фасета с помощью:
(define t1
(newnodeinst tran lowx highx lowy highy 0 0 myfacet))
Возвращаемый
указатель на компонент транзистор будет
использован позже при соединении.
Для соединения двух компонент необходимо знать следующие четыре вещи:
Компонентные объекты на двух концах, возвращаемые newnodeinst
Значения PORTPROTO мест соединения на компонентах
X и Y координаты мест соединения
Тип, ширину и другие характеристики созданных проводников
Места соединения названы PORTPROTOs и
ассоциированы с NODEPROTOs. Для получения
адреса используйте:
(getportproto
NODEPROTO 'PORTNAME)
Например, для получения
порта поликремния на левой стороне
MOSIS CMOS P-транзистора используйте:
(define polyleft (getportproto tran
'p-trans-poly-left))
К сожалению, нет хороших
способов получить список имен портов
на примитивах компонент. Есть, однако,
некоторые упрощения. Например, если
есть только один порт (как в случае с
большинством контактов и выводов), тогда
его имя не нужно:
(define port
(getval tran 'firstportproto))
Этим будет получен
первый порт на компоненте P-транзистор.
Для получения координат порта для
соединения используйте:
(portposition
NODE PORT)
Возвращается вектор с
координатами. Например:
(define
portpos (portposition t1 polyleft))
и будут получены
координаты порта "p-trans-poly-left" на
вновь созданном P-транзисторе t1. Значение
X будет (vector-ref portpos 0), а значение Y
(vector-ref portpos 1).
Последняя часть необходимой информации
- тип дуги и ширина дуги. Задавая имя
дуги, можно получить тип с помощью:
(getarcproto 'ARCNAME)
Задавая
ARCPROTO, предопределенная ширина будет
получена с помощью:
(getval
ARCTYPE 'nominalwidth)
Когда вся информация
готова, вызов:
(newarcinst ARCTYPE
WIDTH BITS NODEA PORTA XA YA NODEB PORTB XB YB FACET)
разместит
проводку. Вы можете игнорировать значение
BITS и установить его в ноль.
Вот полный пример размещения транзистора, контакта и проведения соединения между ними (результат показан здесь же).
; create a facet called "tran-contact"
in the current library |
Фасеты, как созданные newnodeproto, могут быть размещены в других фасетах с помощью newnodeinst. Образцы просто используют комплексные поля NODEPROTO, а не примитивы NODEPROTOs, как в вышеприведенном примере. Например, следующий код создает новый фасет, названный "two-trans" и размещает два образца фасета "tran-contact", один над другим.
; create a facet called "two-trans" |
Другой необходимой
особенностью при создании иерархии
является возможность разместить провода
между местами соединения на образцах
фасета. Чтобы сделать это, необходимо
создать экспорты. При этом берется порт
на примитиве компонента (например,
транзистора или контакта в фасете
"tran-contact") и устраивается в экспорте
на текущем фасете. Выполняется с помощью:
(newportproto FACET NODE-IN-FACET PORT-ON-NODE
'PORTNAME)
где FACET - это фасет, содержащий
компонент, чей порт экспортируется,
NODE-IN-FACET это тот компонент, а
PORT-ON-NODE это частный порт на этом
узле, который будет экспортирован.
Например, для экспорта верхнего и нижнего
портов фасета "tran-contact" (как показано
здесь), может быть добавлен следующий
код:
|
И затем компоненты "o1" и "o2" в фасете "two-trans" могут быть соединены, используя порты, названные "topdiff" и "botdiff":
; get pointer to P-Active arc and its default
width |
Два вида модификации может быть
выполнено для существующих объектов:
удаление и изменение. Для удаления
фасета используйте:
(killnodeproto
FACET)
Чтобы скопировать фасет (внутри той
же библиотеки или из одной библиотеки
в другую) используйте:
(copynodeproto
FROM-FACET TO-LIBRARY 'TO-FACET-NAME)
где FROM-FACET
- оригинальный фасет (NODEPROTO) и
TO-LIBRARY - библиотека-получатель
(destination). Используйте (curlib) для
копирования в ту же самую библиотеку.
Новое имя фасета - последний параметр.
Предикат возвращает адрес нового фасета
(NODEPROTO).
Для удаления компонента используйте:
(killnodeinst NODE)
До удаления
компонента все провода и экспорты должны
быть удалены.
Для изменения размера или ориентации
компонента используйте:
(modifynodeinst
NODE DLOWX DLOWY DHIGHX DHIGHY DROTATION DTRN)
где DLOWX,
DLOWY, DHIGHX и DHIGHY изменения
позиции и размера. DROTATION и DTRN
изменения ориентации.
Для изменения прототипа компонента
используйте:
(replacenodeinst OLD-NODE
NEW-PROTOTYPE)
где старый компонент -
OLD-NODE, а новый NODEPROTO, который
должен быть на его месте, это NEW-PROTOTYPE.
Этот новый прототип должен быть способен
соединиться со всеми существующими
дугами. Предикат возвращает адрес нового
компонента.
Для удаления проводов используйте:
(killarcinst ARC)
Для изменения ширины или позиции
проводов используйте:
(modifyarcinst
ARC DWIDTH DX1 DY1 DX2 DY2)
где DWIDTH, DX1,
DY1, DX2 и DY2 - изменения ширины,
X/Y позиции end 1, и X/Y позиции end 2. Заметьте,
что изменения позиции не сказываются
на перемещении соединенных узлов, так
что изменения могут быть только
небольшими, работающими внутри портов.
Для изменения прототипа провода
используйте:
(replacearcinst OLD-ARC
NEW-PROTOTYPE)
где OLD-ARC - формирователь
провода, а NEW-PROTOTYPE - новый ARCPROTO
для использования. Узлы на обоих концах
должны быть доступны этому новому типу
провода. Предикат возвращает адрес
нового провода.
Для удаления экспорта используйте:
(killportproto FACET PORT)
что удалит
порт PORT на фасете FACET.
Для перемещения экспорта с одного
компонента на другой (сохраняя
присоединенные провода) используйте:
(moveportproto FACET OLD-PORT NEW-NODE
PORT-ON-NEW-NODE)
где старый порт - OLD-PORT
в фасете FACET, а его теперь перемещенный
компонент - NEW-NODE (который также в
фасете FACET), порт PORT-ON-NEW-NODE этого
компонента.
Общей операцией является поиск всех компонент в фасете. Следующий код печатает имена всех компонент в фасете "myfacet":
(do
(
(node
(getval myfacet 'firstnodeinst)
(getval
node 'nextnodeinst))
)
((null?
node))
(format #t "Found
~s node~%" (describenode node))
)
Где describenode - определено так (имя узла находится в разных местах, в зависимости от того, является ли он примитивом или сложным NODEPROTO):
(define describenode
(lambda
(node)
(define proto
(getval node 'proto))
(if
(= (getval proto 'primindex) 0)
(getval
(getval proto 'cell) 'cellname)
(getval
proto 'primname)
)
)
)
А следующий код печатает имена всех проводов в фасете "myfacet":
(do
(
(arc
(getval myfacet 'firstarcinst)
(getval
arc 'nextarcinst))
)
((null?
arc))
(format #t "Found ~s
arc~%"
(getval
(getval arc 'proto) 'protoname))
)
Для осуществления
поиска всех узлов и дуг в прямоугольной
области фасета вначале вызовите:
(initsearch LOWX HIGHX LOWY HIGHY FACET)
где
LOWX, HIGHX, LOWY и HIGHY - координаты
поиска в фасете FACET (NODEPROTO). Этот
предикат вернет ключ поиска, который
затем повторно будет передан:
(nextobject
SEARCHKEY)
что вернет GEOM объекты
каждого узла и дуги в области поиска.
Когда предикат возвращает Null, поиск
завершается. GEOM объекты могут
указывать либо на узел, либо на дугу, в
зависимости от их атрибута "entryisnode".
Затем атрибут "entryaddr" укажет на
актуальный NODEINST или ARCINST. Вот
пример кода, который печатает имена
всех узлов и дуг в области (2000 <= X <=
10000, -3000 <= Y <= 3000). Выбранная область
показана здесь как черный ящик.
(define key (initsearch 2000 10000 -3000 3000
myfacet)) |
Вид (отображение) - объект, описывающий
ячейку. Есть много стандартных отображений:
Layout, Schematic, Icon, Simulation-snapshot, Skeleton, VHDL,
Verilog, Document, Unknown и много вариантов Netlist.
Дополнительно может быть создан новый
вид с помощью "newview":
(newview
'VIEWNAME 'ABBREVIATION)
и вид может быть удален
с помощью killview (стандартные виды не
могут удаляться):
(killview
VIEW)
Для получения объекта вида
используйте getview на его имени.
Для ассоциации разных видов ячейки
предикаты iconview и contentsview достигают
разных фасет. Например:
(iconview
myfacet)
находит ассоциированный фасет
иконки ячейки, в которой находится
"myfacet".
В примерах выше всегда используются
текущие библиотеки. Это определяется
вызовом:
(curlib)
Однако могут
быть и другие библиотеки. Для получения
специально названной библиотеки
используйте:
(getlibrary 'LIBNAME)
Для создания новой библиотеки
используйте:
(newlibrary 'LIBRARYNAME
'LIBRARYFILE)
где LIBRARYNAME - используемое
имя, а LIBRARYFILE - имя, где эта библиотека
будет хранится. Этот предикат возвращает
адрес нового объекта библиотеки, который
может быть использован, когда создается
фасет.
Только одна библиотека является
текущей, и для переключения вы должны
использовать:
(selectlibrary LIBRARY)
Библиотека может быть удалена:
(killlibrary LIBRARY)
Библиотека может быть вытерта (erased)
(ее фасеты удаляются, но не сама библиотека)
с помощью:
(eraselibrary LIBRARY)
Технология - это окружение разработки,
включающее примитивы компонент и
прототипы проводов. Текущая технология
может быть получена с помощью:
(curtech)
Определенная технология может быть
получена по имени с помощью:
(gettechnology
'TECHNAME)
Все технологии могут быть найдены в списке, начинающемся с технологии, которая называется "Generic".
Инструмент - это кусочек кода синтеза
или анализа, который может оперировать
на базе данных. Обычный объект инструмента
может быть получен с помощью:
(gettool
'TOOLNAME)
где возможные имена инструментов:
compaction |
circuit compaction |
compensation |
geometry compensation |
drc |
design-rule checking |
erc |
electrical-rule checking |
io |
input/output control |
logeffort |
logical effort analysis |
network |
network maintenance |
pla |
programmable logic array generator |
project |
project management |
routing |
automatic wire routing |
silicon-compiler |
netlist-to-layout silicon assembler |
simulation |
simulation |
user |
the user interface |
vhdl-compiler |
VHDL-to-netlist compiler |
Некоторое количество инструментов
доступно через:
(maxtool)
И
частные инструменты, индексированные
от 0 до (maxtool)-1, могут быть получены:
(indextool INDEX)
Инструменты можно переключать с
помощью:
(toolturnon TOOL NO-CATCH-UP)
где
TOOL объект инструмента, а NO-CATCH-UP
не нулевое для сдерживания активности,
обычно предусмотрено, когда инструмент
отключается.
Инструмент можно отключить с помощью:
(toolturnoff TOOL)
Инструменту можно передать специальные
инструкции:
(telltool TOOL
PARAMETERS)
Например, список всех
технологий, используя следующий код:
(telltool (gettool 'user) 'show 'technologies)
Эти
команды исходят от низкоуровневого
интерпретатора команд, который полностью
задокументирован в Internals Manual.
Все изменения в базе данных выстраиваются
во внутреннюю очередь в "batch",
который включает изменения и любые
вынужденные сторонние эффекты этих
изменений. Новый пакет (batch) создается
для каждой сессии Lisp интерпретатора
(также для каждой команды Electric, которая
вызывается с клавиатуры/мышкой). Для
отказа от последнего пакета изменений
используйте:
(undoabatch)
Множественные вызовы этим предикатом
в единственном пакете отменят множество
пакетов. Для очистки списка пакетов
изменений используйте:
(noundoallowed)
Если вы создаете проводник, который
делает много изгибов, необходимо создать
специальные узлы, называемые "pins"
на каждом изгибе. Для отыскания, какого
рода вывод использовать для данного
типа проводника, используйте:
(getpinproto ARC-PROTO)
где ARC-PROTO
- тип проводника, а предикат возвращает
тип компонента (NODEPROTO) вывода.
Сетевые объекты могут быть получены
по имени предикатом getnetwork, который
берет имя и фасет для поиска. Например,
код:
(getnetwork 'insig myfacet)
получает
адрес сети, названный "insig" в фасете
myfacet.
Общая функция образца узла может быть
определена с помощью:
(nodefunction
NODE)
возвращая значения из списка
констант в файле С заголовка "efunction.h".
Это значение совершенно то же самое,
что было бы получено при просмотре полей
"userbits" прототипа узла. Однако
некоторые компоненты, имеющие общие
прототипы, будут в большей степени
специфицироваться этим предикатом.
Чтобы получить значение атрибута из
образца выше в иерархии используйте:
(getparentval 'name DEFAULT HEIGHT)
где
name - имя атрибута, DEFAULT - значение
по умолчанию, возвращаемое, если атрибут
не найден, а HEIGHT - число уровней
иерархии, по которым нужно подняться
при поиске атрибута (0 для бесконечности).
Как и горячая клавиша для поиска значений
параметра, есть четыре макроса, которые
используют этот шаблон:
(P 'xx) получает значение параметра xx из родительского образца в иерархии.
(PD 'xx def) получает значение параметра xx из родительского образца в иерархии и использует значение def, если параметр не может быть найден.
(PAR 'xx) получает значение параметра xx из любого высшего образца где-нибудь в иерархии.
(PARD 'xx def) получает значение параметра xx из любого высшего образца где-нибудь в иерархии и использует значение def, если параметр не может быть найден.
|
|