Часть 11: ИНТЕРПРЕТАТОРЫ


plug

11-3: Интерфейс TCL

plug



Этот раздел поясняет интерфейс языка интерпретатора TCL в Electric, системе разработки VLSI.

На протяжении этого раздела примеры кода TCL будут появляться underlined (подчеркнутыми). Например, предикат "getarcproto" получает имя прототипа дуги и возвращает указатель на этот объект. Это кодируется, как (getarcproto 'Metal-1), который вычисляется по указателю формы #arcproto15391808.

В разделе предполагается, что читатель очень хорошо знает Electric, и как-то знаком с внутренним строением системы. Внутреннее руководство (Internals Manual) (документ, доступный на Static Free Software) обеспечивает широкий, С-ориентированный взгляд на информацию, описанную здесь. Для пользователей TCL, однако, этот раздел суммирует важные аспекты внутреннего руководства. В общем, наилучший путь к пониманию этого раздела - выполнить каждую команду по мере ее объяснения.



Управление сессией

Для вызова интерпретатора TCL используйте субкоманду TCL... команды Language Interpreter меню Tools. На некоторых системах, возможно, понадобится переместить курсор в окно сообщений (текстовое окно), чтобы интерпретатор "слышал" вас.

Если у вас есть дисковый файл с кодом TCL, вы можете прочитать его в интерпретатор, введя:
  source FILENAME

Чтобы вернуться в Electric из TCL, введите ^D (удерживайте на клавиатуре клавишу Control и нажмите "D"). В  Windows вы должны нажать клавишу ESC.

Структура базы данных

Полная база данных Electric - это коллекция объектов, каждый из которых имеет произвольное количество атрибутов. Этот раздел кратко показывает типы объектов и то, как они связаны. Дальнейшее знакомство можно продолжить по внутреннему руководству (Internals Manual). См. в разделе 11-5 список атрибутов этих объектов.

Индивидуальные компоненты внутри схемы описаны nodeinst  объектами (образцы узлов), а индивидуальные провода описаны arcinst  objects объектами (образцы дуг).  Соединения между компонентами и провода описаны 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

string

null-terminated string of bytes

float

32-bit floating point number

window

window partition object

windowframe

display window object

constraint

constraint system object

graphics

graphical attributes object

Также есть возможность иметь отображаемые переменные (те, чьи значения появляются на объекте) с ключевым словом: displayable.

Проверка базы данных

Для начала поиска в базе данных важно знать текущую библиотеку. Это сделано так:
  (curlib)

возвращает указатель на объект library (например, #library15464800). Отсюда текущий фасет может быть получен с помощью:
  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
Для добавления отображаемого имени узлу "t1" используйте:
  setval $t1 NODE_name Q1 displayable
Для установки массива значений используйте lists. Например, для установки очертания узла чисто слоя - pure-layer node "metal" со звездочкой используйте:
  setval $metal trace {-1000 0 0 1000 1000 0 0 -1000}

Единственный элемент в массиве атрибутов может быть установлен с помощью:
  setind Object Attribute Index Value
где Index - это 0-базируемый элемент массива.

И, наконец, атрибут может быть удален с помощью:
  delval Object Attribute
Однако только те атрибуты, которые были созданы  setval, могут быть удалены таким образом. Другие атрибуты защищены.

Основы синтеза

Для создания нового фасета в текущей библиотеке используйте:  
  newnodeproto FacetName [curlib]

возвращающий указатель nodeproto, который может быть использован при последующих вызовах, размещающих компоненты и провода в этом фасете.

Для получения адреса существующего nodeproto используйте:
  getnodeproto FacetName
возвращающий тот же тип значения, что и newnodeproto. Таким образом, код:
  set myfacet [newnodeproto "adder{lay}" [curlib]]
тот же, что и код:
  newnodeproto "adder{lay}" [curlib]
  set 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 это не нуль для транспонирования ориентации компонента (после поворота), а Faset - nodeproto в котором будет размещаться компонент.

Четыре ограничивающих значения это нечто путанное для вычисления. Для примитивов компонент (таких, как транзистор) любое значение приемлемо, и компонент будет масштабирован. Однако все еще хорошо бы знать значение по умолчанию, которое может быть получено из nodeproto с помощью getval следующим образом:
  set tran [getnodeproto P-Transistor]
  set lowx [getval $tran lowx]
  set highx [getval $tran highx]
  set lowy [getval $tran lowy]
  set highy [getval $tran highy]
Когда сложные компоненты (фасеты) размещаются, контуры ДОЛЖНЫ быть точно такими же, как рамки содержимого фасета. Эта информация доступна вышеприведенным образом. В качестве примера newnodeinst, и получения вычисления выше показанного контура, предопределенный размер P-транзистора создается в "adder" фасета с помощью:
  set t1 [newnodeinst $tran $lowx $highx $lowy $highy 0 0 $myfacet]
Возвращаемый указатель на компонент транзистор будет использован позже при соединении.

Для соединения двух компонент необходимо знать следующие четыре вещи:

Места соединения названы portprotos и ассоциированы с nodeprotos. Для получения адреса используйте:
  getportproto NodeProto PortName
Например, для получения порта поликремния на левой стороне MOSIS CMOS P-транзистора используйте:
  set polyleft [getportproto $tran p-trans-poly-left]
К сожалению, нет хороших способов получить список имен портов на примитивах компонент. Есть, однако,  некоторые упрощения. Например, если есть только один порт (как в случае с большинством контактов и выводов), тогда его имя не нужно:
  set port [getval $tran firstportproto]
Этим будет получен первый порт на компоненте P-транзистор. Для получения координат порта для соединения используйте:
  portposition Node Port
Возвращается список с координатами. Например:
  set portpos [portposition $t1 $polyleft]
и будут получены координаты порта "p-trans-poly-left" на вновь созданном P-транзисторе t1. Значение X будет lindex $portpos 0, а значение Y lindex $portpos 1.

Последняя часть необходимой информации - тип дуги и ширина дуги. Задавая имя дуги, можно получить тип с помощью:
  getarcproto ArcName
Задавая arcproto, предопределенная ширина будет получена с помощью:
  getval Arc 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
  set myfacet [newnodeproto tran-contact [curlib]]

  # get pointers to primitives
  set tran [getnodeproto P-Transistor]
  set contact [getnodeproto Metal-1-Polysilicon-1-Con]

  # get default sizes of these primitives
  set tlowx [getval $tran lowx]
  set thighx [getval $tran highx]
  set tlowy [getval $tran lowy]
  set thighy [getval $tran highy]
  set clowx [getval $contact lowx]
  set chighx [getval $contact highx]
  set clowy [getval $contact lowy]
  set chighy [getval $contact highy]

  # get pointer to Polysilicon arc and its default width
  set arctype [getarcproto Polysilicon-1]
  set width [getval $arctype nominalwidth]

  # create the transistor and the contact to its left
  set c1 [newnodeinst $contact $clowx $chighx
    $clowy $chighy 0 0 $myfacet]
  set t1 [newnodeinst $tran [expr $tlowx+8000]
    [expr $thighx+8000] $tlowy $thighy 0 0 $myfacet]

  # get the transistor's left port coordinates
  set tport [getportproto $tran p-trans-poly-left]
  set tpos [portposition $t1 $tport]

  # get the contacts's only port coordinates
  set cport [getval $contact firstportproto]
  set cpos [portposition $c1 $cport]

  # run a wire between the primitives
  newarcinst $arctype $width 0
    $t1 $tport [lindex $tpos 0] [lindex $tpos 1]
    $c1 $cport [lindex $cpos 0] [lindex $cpos 1] $myfacet

Figure 11.1

Иерархия 

Фасеты, как созданные newnodeproto, могут быть размещены в других фасетах с помощью newnodeinst. Образцы просто используют комплексные поля nodeproto, а не примитивы nodeprotos, как в вышеприведенном примере. Например, следующий код создает новый фасет, названный "two-trans" и размещает два образца фасета "tran-contact", один над другим.

  # create a facet called "two-trans"
  set higherfacet [newnodeproto two-trans [curlib]]

  # get pointer to the "tran-contact" facet
  set tc [getnodeproto tran-contact]

  # get size of this facet
  set lowx [getval $tc lowx]
  set highx [getval $tc highx]
  set lowy [getval $tc lowy]
  set highy [getval $tc highy]

  # create the two facet instances, one above the other
  set o1 [newnodeinst $tc $lowx $highx $lowy $highy
    0 0 $higherfacet]
  set o2 [newnodeinst $tc $lowx $highx
    [expr $lowy+10000] [expr $highy+10000]
      0 0 $higherfacet]

Figure 11.2

Другой необходимой особенностью при создании иерархии является возможность разместить провода между местами соединения на образцах фасета. Чтобы сделать это, необходимо создать экспорты. При этом берется порт на примитиве компонента (например, транзистора или контакта в фасете "tran-contact") и устраивается в экспорте на текущем фасете. Выполняется с помощью:
  newportproto Facet NodeInFacet PortOnNode PortName
где Facet - это фасет, содержащий компонент, чей порт экспортируется, NodeInFacet это тот компонент, а PortOnNode это частный порт на этом узле, который будет экспортирован. Например, для экспорта верхнего и нижнего портов фасета "tran-contact" (как показано здесь), может быть добавлен следующий код:


  newportproto $myfacet $t1
    [getportproto $tran p-trans-diff-top] topdiff
  newportproto $myfacet $t1
    [getportproto $tran p-trans-diff-bottom] botdiff

Figure 11.3

И затем компоненты "o1" и "o2" в фасете "two-trans" могут быть соединены, используя порты, названные "topdiff" и "botdiff":

  # get pointer to P-Active arc and its default width
  set darctype [getarcproto P-Active]
  set dwidth [getval $darctype nominalwidth]

  # get the bottom facet's top port
  set lowport [getportproto $myfacet topdiff]
  set lowpos [portposition $o1 $lowport]

  # get the top facet's bottom port
  set highport [getportproto $myfacet botdiff]
  set highpos [portposition $o2 $highport]

  # run a wire between the primitives
  newarcinst $darctype $dwidth 0
    $o1 $lowport [lindex $lowpos 0] [lindex $lowpos 1]
      $o2 $highport [lindex $highpos 0]
        [lindex $highpos 1] $higherfacet

Figure 11.4

Модификация

Два вида модификации может быть выполнено для существующих объектов: удаление и изменение. Для удаления фасета используйте:
  killnodeproto Facet

Чтобы скопировать фасет (внутри той же библиотеки или из одной библиотеки в другую) используйте:
  copynodeproto FromFacet ToLibrary ToFacetName
где FromFacet - оригинальный фасет (nodeproto) и ToLibrare - библиотека-получатель (destination ). Используйте (curlib) для копирования в ту же самую библиотеку. Новое имя фасета - последний параметр. Предикат возвращает адрес нового фасета (nodeproto).

Для удаления компонента используйте:


  killnodeinst Node
До удаления компонента все провода и экспорты должны быть удалены.

Для изменения размера или ориентации компонента используйте:
  modifynodeinst Node DLowX DLowY DHighX DHighY DRotation DTrans
где DLowX, DLowY, DHighX и DHighY изменения позиции и размера. DRotation и DTrans изменения ориентации.

Для изменения прототипа компонента используйте:
  replacenodeinst OldNode NewPrototype
где старый компонент - OldNode, а новый nodeproto, который должен быть на его месте, это NewPrototype. Этот новый прототип должен быть способен соединиться со всеми существующими дугами. Предикат возвращает адрес нового компонента.

Для удаления проводов используйте: 
  killarcinst Arc

Для изменения ширины или позиции проводов используйте:
  modifyarcinst Arc DWidth DX1 DY1 DX2 DY2
где DWidth, DX1, DY1, DX2 и DY2 - изменения ширины, X/Y позиции end 1, и X/Y позиции end 2. Заметьте, что изменения позиции не сказываются на перемещении соединенных узлов, так что изменения могут быть только небольшими, работающими внутри портов.

Для изменения прототипа провода используйте: 
  replacearcinst OldArc NewPrototype
где OldArc - формирователь провода, а NewPrototype - новый arcproto для использования. Узлы на обоих концах должны быть доступны этому новому типу провода. Предикат возвращает адрес нового провода.

Для удаления экспорта используйте: 
  killportproto Facet Port
что удалит порт Port на фасете Facet.

Для перемещения экспорта с одного компонента на другой (сохраняя присоединенные провода) используйте: 
  moveportproto Facet OldPort NewNode PortOnNewNode
где старый порт - OldPort в фасете Facet, а его теперь перемещенный компонент - NewNode (который также в фасете Facet), порт PortOnNewNode этого компонента.

Поиск

Общей операцией является поиск всех компонент в фасете. Следующий код печатает имена всех компонент в фасете "myfacet":

  for { set node [getval $myfacet firstnodeinst] }
    { [string c $node #nodeinst-1] != 0 }
    { set node [getval $node nextnodeinst] }
  {
    puts stdout [format "Found %s node" [describenode $node]]
  }

Где describenode - определено так (имя узла находится в разных местах, в зависимости от того, является ли он примитивом или сложным nodeproto):

  proc describenode node
  {
    set proto [getval $node proto]
    if { [getval $proto primindex] == 0}
      { return [getval [getval $proto cell] cellname] }
    return [getval $proto primname]
  }

А следующий код печатает имена всех проводов в фасете "myfacet":

  for { set arc [getval $myfacet firstarcinst] }
    { [string c $arc #arcinst-1] != 0 }
    { set arc [getval $arc nextarcinst] }
  {
    puts stdout [format "Found %s arc"
      [getval [getval $arc proto] protoname]]
  }

Для осуществления поиска всех узлов и дуг в прямоугольной области фасета вначале вызовите: 
  initsearch LowX HighX LowY HighY Facet
где LowX, HighX, LowY и HighY - координаты поиска в фасете Facet (nodeproto). Этот предикат вернет ключ поиска, который затем повторно будет передан:
  nextobject SearchKey
что вернет geom объекты каждого узла и дуги в области поиска. Когда предикат возвращает #geom-1, поиск завершается. geom объекты могут указывать либо на узел, либо на дугу, в зависимости от их атрибута "entryisnode". Затем атрибут "entryaddr" укажет на актуальный nodeinst или arcinst. Вот пример кода, который печатает имена всех узлов и дуг в области (2000 <= X <= 10000, -3000 <= Y <= 3000). Выбранная область показана здесь как черный ящик.

  set key [initsearch 2000 10000 -3000 3000 $myfacet]
  for { set object [nextobject $key] }
    { [string c $object #geom-1] != 0 }
    { set object [nextobject $key] }
  {
    set isnode [getval $object entryisnode]
    if { $isnode }
      { puts stdout [format "Found %s node"
        [describenode [getval $object entryaddr]]] }
      else
      { puts stdout [format "Found %s arc" [getval [getval [
        getval $object entryaddr] proto] protoname]] }
  }

Figure 11.5

Виды

Вид (отображение) - объект, описывающий ячейку. Есть много стандартных отображений: 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 Lib

Библиотека может быть удалена:
  killlibrary Lib

Библиотека может быть вытерта (erased) (ее фасеты удаляются, но не сама библиотека) с помощью:
  eraselibrary Lib

Технологии

Технология - это окружение разработки, включающее примитивы компонент и прототипы проводов. Текущая технология может быть получена с помощью:
  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 NoCatchUp
где Tool объект инструмента, а NoCatchUp не нулевое для сдерживания активности, обычно предусмотрено, когда инструмент отключается.

Инструмент можно отключить с помощью:
  toolturnoff Tool

Инструменту можно передать специальные инструкции:
  telltool Tool PARAMETERS
Например, список всех технологий, используя следующий код:
  telltool [getaid user] {show technologies}
Эти команды исходят от низкоуровневого интерпретатора команд, который полностью задокументирован в  Internals Manual.

Разное

Все изменения в базе данных выстраиваются во внутреннюю очередь в "batch", который включает изменения и любые вынужденные сторонние эффекты этих изменений. Новый пакет (batch) создается для каждой сессии TCL интерпретатора (также для каждой команды Electric, которая вызывается с клавиатуры/мышкой). Для отказа от последнего пакета изменений используйте: 
  undoabatch

Множественные вызовы этим предикатом в единственном пакете отменят множество пакетов. Для очистки списка пакетов изменений используйте:
  noundoallowed

Если вы создаете проводник, который делает много изгибов, необходимо создать специальные узлы, называемые "pins" на каждом изгибе. Для отыскания, какого рода вывод использовать для данного типа проводника, используйте:
  getpinproto Arc
где Arc - тип проводника, а предикат возвращает тип компонента (nodeproto) вывода.

Сетевые объекты могут быть получены по имени с предикатом getnetwork, который берет имя и фасет для поиска. Например, код:
  getnetwork insig Myfacet
получает адрес сети, названный "insig" в фасете Myfacet.

Общая функция образца узла может быть определена с помощью: 
  nodefunction Node
возвращая значения из списка констант в файле С заголовка "efunction.h". Это значение совершенно то же самое, что было бы получено при просмотре полей "userbits" прототипа узла. Однако некоторые компоненты, имеющие общие прототипы, будут в большей степени специфицироваться этим предикатом.

Чтобы получить значение атрибута из образца выше в иерархии используйте:
  getparentval Name Default Height
где Name - имя атрибута, Default - значение по умолчанию, возвращаемое, если атрибут не найден, а Height - число уровней иерархии, по которым нужно подняться при поиске атрибута (0 для бесконечности). Как и горячая клавиша для поиска значений параметра, есть четыре макроса, которые используют этот шаблон:


Prev

Предыдущий

   

Contents

Содержание

   

Следующий

Next