Tcl Bindings for the OpenAccess API


This document consists of five major sections:

Overview

The OpenAccess API is a C++ API to an IC design database. Although the OpenAccess reference implementation is implemented in C++, you can access the reference implementation from Tcl. This document describes the OpenAccess API in Tcl. If you prefer to script part or all of your database application in Tcl, you can access and use the OpenAccess reference implementation through the Tcl OpenAccess API.

The Tcl OpenAccess API resembles its C++ counterpart, but it is not identical. For example, some OpenAccess API C++ objects are not directly available in Tcl, such as the oaString class (Tcl provides built-in string support). More significantly, Tcl is a procedural language not an object-oriented language. Although Tcl calls to native OpenAccess functionality are designed to be as fast as possible, running Tcl is slower than running compiled C++ object code.

Tcl is a straightforward programming language and well documented in numerous books and publications. The main focus of this document is the OpenAccess API in Tcl, but it also introduces a few fundamental Tcl language concepts and practices for those who are new to Tcl.

The Tcl OpenAccess API is available in Tcl version 8.4.6. In order to use the Tcl OpenAccess API in Tcl, you must install Tcl 8.4.6 or later. You can obtain the most recent Tcl version from:

http://www.tcl.tk

You must set the TCL_HOME environment variable to the location of your Tcl installation.

Build Instructions

Understanding the Tcl OpenAccess API

This section describes basic features of the Tcl OpenAccess API in comparison to the OpenAccess C++ API. This information is helpful to C++ programmers who want to use the OpenAccess Tcl API for specific Tcl scripting tasks.

Mapping Tcl Command Names to OpenAccess API Function Names

All OpenAccess Tcl commands involve either using or returning an instance of an OpenAccess class. Tcl variables are used to hold either a reference or a pointer to an instance of an OpenAccess class. From the OpenAccess C+++ API perspective, this is either a class reference or pointer to a class. The Tcl variable can then be used to access the non-static member functions for this class or used as an argument when a reference or pointer to the class is required. When used to access a non-static member function of the class, it must be passed as the first argument of the Tcl command for the member function.

All OpenAccess Tcl command names are defined in the Tcl namespace: oa. OpenAccess Tcl command names derive from their corresponding OpenAccess C++ class and member function names according to a set of rules. The rules for transforming non-static C++ function names to Tcl command names are different from those for transforming static C++ function names.

Tcl commands bound to a non-static C++ member function of an OpenAccess class

Tcl commands bound to a static C++ member function of an OpenAccess class

Examples:

Function Type OA Class Name Member Function Name Tcl Command
Static oaDesign open() oa::DesignOpen
  oaBlock create() oa::BlockCreate
Non-Static oaDesign save() oa::save
  oaBlock getDBUPerUU oa::getDBUPerUU

Example usage:

    set design [oa::DesignOpen libName cellName viewName w]
    set block [oa::BlockCreate $design]
    set dbu [oa:getDBUPerUU $block]
    oa::save $design

See also the complete list of Tcl OpenAccess Commands.

Mapping Tcl Command Arguments to OpenAccess C++ Types

Tcl has direct support for string, long, double and user defined values. Tcl command arguments map to OpenAccess C++ types according to the following table.

Tcl Argument Mapping

Open Access C++ Type

Tcl Argument Type

oaChar

string

oaByte

int

oaInt2

int

oaInt4

int

oaInt8

long long

oaUInt2

int

oaUInt4

int

oaUInt8

long long

oaFloat

double

oaDouble

double

oaBoolean

string true or false (case insensitive), 1 or 0

enum

string enum representation

oaObject

user defined type

oaString

Tcl string

oaBox

{{left bottom} {right top}}

oaComplex

{real imaginary}

oaComplexArray

{{r0 i0} {r1 i1} …}

oaHashTable

Excluded

oaPoint

{x y}

oaPointArray

{{x0 y0} {x1 y1} …}

oaScalarName

user defined type

oaTransform

user defined type

Notes

Tcl Output Arguments

A number of parameters of the OpenAccess C++ API are output arguments in Tcl. Some examples of OpenAccess C++ APIs are:

    void oaDesign::getLibName(oaScalarName &name)
    void oaPathSeg::getPoints(const oaPoint &beginPoint,
                              const oaPoint &endPoint)

For member functions with void return values that have a single output parameter, the output parameter is converted to a Tcl return value. These functions may have additional input parameters. An example is:

    set libName [oa::getLibName $design]
    

Commands with output arguments that do not satisfy these limitations are mapped directly. In other words, the arguments passed into the Tcl command are directly modified by the OpenAccess C++ implementation. These variables must first be initialized and be of the correct type. In the next example, $beginPt and $endPt are assigned by reference by oa::getPoints. Note that $beginPt and $endPt are first initialized to be oaPoint type variables.

    set beginPt [oa::point [list 0 0]]
    set endPt [oa::point [list 0 0]]
    oa::getPoints $pathSeg $beginPt $endPt

Tcl Overloaded Commands

As a consequence of the conventions for OpenAccess function names as described earlier, many of the OpenAccess C++ functions appear to be overloaded in Tcl. Because the Tcl interpreter does not handle command overloading, the resolution is handled by the Tcl binding.

The choice of the command based on the first arguments for mapped C++ member functions is the most common situation. The appropriate binding is first selected based on the class that this first argument represents, taking class derivation into account. For example, the Tcl function getBBox for an oaRect object selects the C++ getBBox member function of the oaFig class. Subsequently, the appropriate member function is selected if multiple functions by the same name, but with different argument types, exist for that class.

OpenAccess Namespaces and Names

OpenAccess names are represented by strings and an OpenAccess namespace that defines the rules for the interpretation of the string. OpenAccess namespaces are objects and are different from Tcl or C++ namespaces. The OpenAccess namespaces can be created with the following Tcl commands:

oa::NativeNS 
oa::CdbaNS 
oa::LefNS 
oa::SpefNS 
oa::SpfNS 
oa::UnixNS 
oa::VerilogNS 
oa::VhdlNS 
oa::WinNS 

The namespace can be used for creating names. For example,

set uns [oa::UnixNS] 
set bc [oa::ScalarName $uns BigChip] 
oa::get $bc [oa::WinNS] 

The last command returns the string %Big%Chip, which is how the scalar name BigChip is represented in the Windows namespace. OpenAccess names can be handled automatically in Tcl. Names are represented in Tcl by the string that is obtained within the global namespace. It can be set globally with the following Tcl commands:

oa::pushNameSpace namespace 
oa::popNameSpace 
oa::getNameSpace 

The native namespace is set as the global namespace on startup.

The global namespace is also used for the construction of command arguments. Arguments that are scalar names can be specified with simple strings, which are converted to scalar names using the global namespace. Therefore, you can create a library with

oa::LibCreate myLib myLib 

instead of:

oa::LibCreate [oa::ScalarName [oa::NativeNS] myLib] myLib 

Constants and Enumerations

Several command arguments take enumerated values.

For example, the oa::ViewTypeGet command takes an oaReservedViewType argument:

% oa::help ReservedViewType 
ReservedViewType 
   valueIn 
==> oaReservedViewType 
ReservedViewType 
   name oaString 
==> oaReservedViewType 

Enumerated values and constants are Tcl variables in the oa namespace that start with “oac”. You can query all variables in Tcl with:

% info vars oa::oacMask* 
oa::oacMaskLayout 

You can use this variable directly.

% set oa::oacMaskLayout

0

%oa::ViewTypeGet [oa::ReservedViewType $oa::oacMaskLayout]
oa:0x029A0092 

Alternatively, for enumerated values, you can use its string representation. The latter can be found with the getName function:

% oa::getName [oa::ReservedViewType $oa::oacMaskLayout] 
maskLayout 

The command to obtain the reserved view type can simply be:

% oa::ViewTypeGet maskLayout 
oa:0x029A0092 

Collections

A number of OpenAccess member functions return collection classes. These return values are represented by user-defined objects in Tcl just like regular objects. The collection can be traversed directly using the Tcl while command:

set design [oa::DesignOpen $lib $cell $view r] 
set top [oa::getTopBlock $design]
set shapes [oa::getShapes $top] 
while {[set shape [oa::getNext $shapes]] != ""} {
    set box [oa::getBBox $shape]
    puts "The bounding box is: $box"
}

set terms [oa::getTerms $top $oa::oacTermIterSingleBit]
while {[set term [oa::getNext $terms]] != ""} {
    set termName [oa::getName $term [oa::NativeNS]]
    puts "Term: $termName"
}

Note that the box and shape variables are unbound at the end of each iteration, and this code is therefore memory efficient.

User Units

In Tcl, coordinates, offsets, and distances are floating-point numbers specified in user units. For Tcl commands, these user units are converted to database units by the Tcl bindings. Any distance or coordinate results returned by Tcl commands are automatically converted from database units back to user units.

This affects the following C++ types directly:

Database units are converted to user units directly by the Tcl binding whenever possible. For example, when you call the getWidth command on a path object, the width return value is converted from database units to user units. This conversion is accomplished with oaTech conversion functions, as follows.

Type

Database to user

User to database

oaCoord

dbuToUU

uuToDBU

oaDist

dbuToUUDistance

uuToDBUDistance

oaOffset

dbuToUU

uuToDBU

These functions require the technology database and the view type. Tcl commands for C++ member functions that are derived from the oaDesignObject class obtain the technology database and the view type from their design. Because of this automatic conversion, a technology database must be available on the design before functions involving this conversion can be called. If a technology database is not available, a Tcl error results.

The procedure for converting command arguments from user units to database units is similar to that of converting return values from database units to user units.

Points and Boxes

In Tcl, a point is represented by a Tcl list of a double x value and a double y value. The values are in user units. Round-off precision must be taken into account by a script when the values of two points are compared.

A box object is represented in Tcl by a Tcl list of the lower left and the upper right points of the box. For example, the following command creates a rectangle with the lower left corner at (0,0) and the upper right at (100,400).

    oa::RectCreate $block $layer $purpose [list [list 0 0] [list 100 400]]]

Similarly, functions that return boxes return a TCL list of two points. As a result, the following commands can be used to obtain the lower left corner of the bounding box of a shape.

    set bbox [oa::getBBox $shape]
    set lowerLeft [lindex $bbox 0]

Important exceptions to this rule are the member functions of oaBox. The following example computes the center of the bounding box of a shape. The code illustrates how a bounding box obtained from an OA command can be used with an oaBox member function (oaBox::getCenter in this case).

 
    set box [join [oa::getBBox $shape]]
    set boxObj [oa::Box [lindex $box 0] [lindex $box 1] [lindex $box 2] [lindex $box 3]]
    set center [oa::getCenter $boxObj]

Tcl OpenAccess Command Help

The OpenAccess API in Tcl provides many commands. The info command provides a means to simply list the OpenAccess commands. However, the command oa::help provides additional, basic information on how to use an OpenAccess command. To create a library, you can use the LibOpen command returned by the info query in the previous section. To obtain additional information on this command, use the help command as follows:

% oa::help LibCreate
 LibCreate 
   name        oaScalarName 
   libPath     oaString 
   mode        oaLibMode 
   dmSystem    oaString 
   dmAttrList  oaDMAttrArray 
 ==> oaLib 

For example, create a library as follows:

% oa::LibCreate myLib myLib

This returns an address such as:

oa:0x80013 

Tcl Error Handling

When errors occur in the OpenAccess API, a Tcl error is thrown. These errors can be the result of an exception that is thrown by the C++ implementation. Errors also can be the result of the C++ Tcl binding code. The Tcl error can be caught in Tcl. For example, a second call to create a library results in a Tcl error. The following code shows how this type of error can be caught:

oa::LibCreate myLib myLib
if [catch {oa::LibCreate myLib myLib} err] {
    puts "Error: $err"
} 
puts “Successfully continued the script”

If the Tcl error is not caught as in the above example, Tcl aborts the execution of the script. In the example code, the error is caught and script execution continues.

Using the Tcl OpenAccess API

This section provides information on using OpenAccess Tcl.

Using the Tcl Bindings

The Tcl bindings are packaged in a shared library that can be loaded by a standard Tcl shell, version 8.4.6 or later. This shared library path is shown in the table below and depends on the OpenAccess shared libraries that contain the reference implementation. To successfully load the Tcl library, you must set the library path environment variable to include the path to the directory of OpenAccess shared libraries. The following table provides sample commands to accomplish this.

Solaris

 setenv LD_LIBRARY_PATH /opt/oa2.2/lib/sunos_58_32/opt:/usr/lib 

HP

 setenv SHLIB_PATH /opt/oa2.2/lib/hpux_11_32/opt:/usr/lib 

Linux

 setenv LD_LIBRARY_PATH /opt/oa2.2/lib/linux_rhel21_32/opt:<gcc3.2.3_compliant_installDir>/lib 

AIX

 setenv LIBPATH /opt/oa2.2/lib/aix_51_32/opt:/usr/lib 

Windows XP

 set PATH = c:\oa2.2\bin\win32\opt;c:\window\system32 

Note that the path on Windows should be modified through the Windows GUI.

Linux

If you want to run the Tcl bindings on a Linux platform, you must have a compliant version of the gcc runtime shared libraries in your LD_LIBRARY_PATH. In most cases on Linux, these are not the standard C++ runtime libraries supplied with the operating system.

setenv LD_LIBRARY_PATH /opt/oa2.2/lib/linux_rhel21_32/opt:<gcc3.2.3_compliant_installDir>/lib

If you do not have access to the libraries, for example, from your EDA vendor, you can build them. Refer to Notes on Compiling on Linux Platforms Without gcc 3.2.3 for build instructions.

Starting Tcl and Loading the Tcl OpenAccess Shared Library

You can start Tcl from the command line. For example, on UNIX platforms, enter:

> tclsh8.4 

On Windows , enter:

> tclsh84.exe 

Alternatively, you can launch the Tcl shell on Windows by double-clicking the Tcl shortcut.

This starts the Tcl shell from the Tcl distribution installed on your system. You can now enter Tcl commands. To see all available commands in the global Tcl namespace, use the info command:

% info commands * 

This returns:

tell socket subst open eof pwd glob list exec pid auto_load_index time unknown eval 
lrange fblocked lsearch auto_import gets case lappend proc break variable llength 
auto_execok return linsert error catch clock info split array if fconfigure concat 
join lreplace source fcopy global switch auto_qualify update close cd for auto_load 
file append format read package set binary namespace scan trace seek while flush 
after vwait uplevel continue foreach lset rename fileevent regexp upvar unset 
encoding expr load regsub history interp exit puts incr lindex lsort tclLog string 

All OpenAccess commands are provided in the Tcl namespace oa. To view commands in the oa namespace, enter:

% info commands oa::* 

At this point, nothing is returned since there are no available OpenAccess commands because the oaTcl shared library is not loaded. The Tcl binding of OpenAccess supports the Tcl package command, which is preferred over the Tcl load command. The name of the OpenAccess package is “oa” and the version is 2.2. See the Tcl documentation for details on the package command. To use this Tcl command, the auto_path variable must include the directory of the oaTcl shared library. You can inspect the value of this variable with the Tcl command:

    set auto_path

To add the directory that contains the oaTcl shared library, use a statement such as:

    lappend auto_path /opt/oa2.2/lib/linux_rhel21_32/opt

The OpenAccess binding can be loaded with the package command as follows:

    package require oa

This command should return the value "2.2".

The command info oa::* now returns a long list of functions. To see just the commands for opening libraries, use:

% info commands oa::Lib* 

This returns:

::oa::LibDefListGetDefaultPath ::oa::LibDefListOpenLibs ::oa::LibDefCreate 
::oa::LibGetOpenLibs ::oa::LibDefListFind ::oa::LibDMDataDestroy::oa::LibMode
::oa::LibDefListGetLibDefLists ::oa::LibCreate ::oa::LibExists
::oa::LibDefListRefFind ::oa::LibDMDataOpen ::oa::LibDMDataFind
::oa::LibDefListRefCreate ::oa::LibAccess ::oa::LibAccessLevel
::oa::LibOpen ::oa::LibDefFind ::oa::LibFind ::oa::LibDefListGetTopList
::oa::LibDMDataExists ::oa::LibDataType ::oa::LibDefListGet

All Tcl OpenAccess commands can be used after the oaTcl shared library is loaded. The OpenAccess database is automatically initialized when the OpenAccess Tcl shared library is loaded into Tcl.

Opening Library Definition Files in Tcl

While OpenAccess Tcl does not support oaObserver notifications in general, however it does supply one internal observer for handling of the messages generated during loading of the library defintion files. This internal observer for oaLibDefListObserver::onLoad call backs will accumulate the warning messages that occur during loading of library definition files initiated by the Tcl call to oa::LibDefListOpenLibs. If warning messages occur oa::LibDefListOpenLibs will throw an exception with those warning messages. Users are expected to enclose any call to oa::LibDefListOpenLibs in a catch block to detect this error condition.

This behavior can be modifed via the oa::setLibDefListErrorLogging command. If oa::setLibDefListErrorLogging has not been called or has been called with the value true then the call back is enabled and the behavior of oa::LibDefListOpenLibs is as described above. If oa::setLibDefListErrorLogging has been called with the argument false then the observer will be disabled. oa::LibDefListOpenLibs will not print any warning messages and will return an ok status.

Tcl Namespaces

All commands defined in the oa namespace are exported upon initialization of the OpenAccess Tcl API after all commands have been defined. OpenAccess commands can be imported to the global namespace with the common Tcl command namespace import. For example

namespace import oa::DesignOpen 

Note that there are functions in the oa namespace that conflict with common Tcl functions, so you should not import all functions in the oa namespace to the global namespace.

Memory Management

There are two types of objects involved in the OpenAccess API: utility and managed. The utility type of objects have constructor commands. These commands are the name of the object type itself. For example, oa::Transform creates a transform object of the type Transform. These objects are created and, if assigned to a Tcl variable, remain in memory until no variables reference the object. When the reference count of the object becomes zero, the object is removed and the implemented C++ destructor for the object is called.

The managed type of objects do not have constructor commands, but instead have create commands. In Tcl, such commands are named according to the type of the object created, with “Create” appended to the command name. For example, the Tcl command oa::RectCreate is the name of the OpenAccess command to create a rectangle object. The lifetime of managed objects does not depend on Tcl variable references, but instead depends on the database the objects reside in. These objects remain valid as long as that database is opened. They become invalid as soon as the database is closed. For example, created rectangle objects are valid for as long as the design is open in which they reside. The validity of these objects is the responsibility of the Tcl programmer.

Tcl Examples

The following listing is a simple Tcl script that creates a net and adds two rectangles to it. The second half of this example outputs the bounding boxes of the two rectangles. The script assumes you have set the appropriate shared library path variable as explained previously.

# <---- Example Tcl Script: myExample.tcl ----> 
# A simple script to create a net and add two rectangles.

proc openLib {name path} {
    set lib [oa::LibFind $name]
	
    if {$lib != ""} {
            return $lib
    }

    if {$lib != ""} {
            return $lib
    }
    
    if {[oa::LibExists $path]} {
            set lib [oa::LibOpen $name $path]
            return $lib
    }
 
    return [oa::LibCreate $name $path]
}
 
proc openTech {lib} {
    set tech [oa::TechFind $lib]
	
    if {$tech != ""} {
        return $tech
    }
 
    if {[oa::TechExists $lib]} {
        return [oa::TechOpen $lib]
    }
 
    return [oa::TechCreate $lib]
}
 
    

proc openLayer {{tech} {layerName} {layerNumber}} {
    set layer [oa::PhysicalLayerFind $tech $layerName]
	
    if {$layer != ""} {
        return $layer
    }
	
    return [oa::PhysicalLayerCreate $tech $layerName $layerNumber]
}


proc sample {} { 
    # Load OA shared libraries
    set numBits [expr $::tcl_platform(wordSize) * 8]
    lappend auto_path [exec oaGetLibPath -numBits $numBits]
    
    package require oa 2.2

    
    # Set the name space to oa::NativeNS
    oa::pushNameSpace [oa::NativeNS] 
    # Create the lib if it does not already exist
    set lib [openLib "lib" "lib"]
         
    # Create a tech database if one does not already exists
    set tech [openTech $lib]
    
    # Create a new design in the library
    set master [oa::DesignOpen "lib" "cell" "view" [oa::ViewTypeGet maskLayout] w]
    set top [oa::BlockCreate $master]
    
    # Create the net "net1" in the design
    set net1 [oa::ScalarNetCreate $top "net1"]

    # Create the layer "Metal1" if it does not exist
    set layer [openLayer $tech "Metal1" 10]
    set metal1 [oa::getNumber $layer]

    # Get the "drawing" purpose from the tech database
    set purpose [oa::PurposeGet $tech [oa::PurposeType $oa::oacDrawingPurposeType]]
    set drawing [oa::getNumber $purpose]

    # Create 2 shapes on "net1"
    set rect1 [oa::RectCreate $top $metal1 $drawing [list [list 0 0] [list 100 400]]]
    set rect2 [oa::RectCreate $top $metal1 $drawing [list [list 0 0] [list 400 100]]]
    oa::addToNet $rect1 $net1
    oa::addToNet $rect2 $net1

    oa::save $master
    oa::close $master

    # Re-open the design and report the bounding boxes of the shapes on "net1"
    set master [oa::DesignOpen "lib" "cell" "view" r]
    set top [oa::getTopBlock $master]
    
    set net1 [oa::ScalarNetFind $top "net1"]
    set shapes [oa::getShapes $net1]

    while {[set shape [oa::getNext $shapes]] != ""} {
        set box [join [oa::getBBox $shape]]
        puts "The bounding box is: $box"

        set box [oa::Box [lindex $box 0] [lindex $box 1] [lindex $box 2] [lindex $box 3]]
        puts "The center is [oa::getCenter $box]\n"
    }
}
To load and run the script in the Tcl shell, enter:
    >tclsh
    %source myExample.tcl
    %sample

Sample .tclshrc File

This sample .tclshrc file provides two procedures for initializing your Tcl environment. The procedure initoa loads the oaTcl shared library and initializes the Tcl OpenAccess command interface. The setup procedure calls the LibDefListOpenLibs command to open all your libraries defined by your lib.defs file. It uses the environment variables OA_HOME for your installation directory and OA_MODE for debuggable or optimized mode selection.

################################################################################
# oaInit.tcl#
# This file is a Tcl package and is not intended to be executed as a standalone
# script. This file provides Tcl functions to initialize the OpenAccess Tcl
# binding and to perform some common setup tasks. This file also contains some
# constants commonly used by OA Tcl scripts.
################################################################################
################################################################################
package require Tcl 8.4.6
################################################################################
# getOAInstDir
#
# This function returns the OpenAccess installation directory.
################################################################################
proc getOAInstDir {} {
    # Check first to see if it has been locally overridden
    if {[info exists ::OA_HOME] && [file exists $::OA_HOME]} {
        return $::OA_HOME
    } elseif {[info exists ::env(OA_HOME)]} {
        return $::env(OA_HOME)
    }
    
    set file    [file join data plugins]
    set cwd [file split [pwd]]

    for {set i [llength $cwd]} {$i >= 0} {incr i -1} {
        set dir     [eval file join [lrange $cwd 0 $i]]

        if [file exists [file join $dir $file]] {
            return $dir
        }
    }
    return ""
}

################################################################################
# getSharedLibPath
#
# This function returns the path to the shared library directory of OpenAccess.
################################################################################
proc getSharedLibPath {{mode ""}} {
    set dir [getOAInstDir]

    if {$dir == ""} {
        return ""
    }


    set lib lib
    if {$::tcl_platform(platform) == "windows"} {
        set lib bin
    }

    return [file join $dir $lib [getSysName $dir] [getOAMode $mode]]
}

################################################################################
# getSysName
#
# This function returns the OpenAccess system name, including the width which is
# based on the tcl executable.
################################################################################
proc getSysName {dir} {
    if {$::tcl_platform(platform) == "windows"} {
        return win32
    }

    set plaf [exec [file join $dir bin sysname]]
    set bits [expr $::tcl_platform(wordSize) * 8]

    return ${plaf}_${bits}
}

################################################################################
# getOAMode
#
# This function returns the mode. The default is dbg on UNIX and dbgStatic on
# Windows.
################################################################################
proc getOAMode {{mode ""}} {
    if {$mode != ""} {
        return $mode
    }

    if {[info exists ::env(OA_MODE)]} {
        return ${::env(OA_MODE)}
    }

    if {$::tcl_platform(platform) == "windows"} {
        return dbgStatic
    }

    return dbg
}

################################################################################
# initoa
#
# This function initializes the Tcl OpenAccess binding. Call this function
# with the mode argument.
################################################################################
proc initoa {{mode ""}} {
    global auto_path

    set mode    [getOAMode $mode]
    set dir     [getSharedLibPath $mode]

    if {$dir == ""} {
        puts "Cannot determine the OpenAccess installation directory. In order to
        initialize OpenAccess run the Tcl shell from a directory inside the
        installation hierarchy, or set the OA_HOME environment variable."
        return
    }

    lappend auto_path $dir

    
    if {[catch {set val [package require oa]}]} {
        puts "\nERROR: Cannot load the OA TCL shared libraries from $dir. 
        Verify that the OA TCL shared libraries exist at that location. 
        On Unix the global environment variable \$LD_LIBRARY_PATH must 
        include $dir. Set its value using 'setenv' and rerun this program, 
        since a TCL script cannot modify its own global environment variables.\n"    
        return    
    }     

    puts "OpenAccess is loaded from $dir"
    return val
}

################################################################################
# setup
#
# This function performs some setup tasks that are common to most OA Tcl
# scripts. This function loads the default lib.defs file, and sets the global 
# OA namespace variable (ns) to oaNativeNS.
################################################################################
proc setup {{libDefs lib.defs}} {
    set retval [initoa]
    if {$retval != ""} {
        if [file exists $libDefs] {
            if {[catch {oa::LibDefListOpenLibs $libDefs} msg]} {
                puts "Problem loading lib.defs: $msg"
            }
        }
    }

    return $retval
}

The examples/oa/TCL directory in your OpenAccess installation hierarchy contains a number of example Tcl files, which are described in the following table.

Example Tcl Files Included With Your OpenAccess Installation
sample.tcl Excercises the findInst command implemented in C++ in findInst.cpp. Use "make" to compile the C++ code into "libfindInst.so". From the Tcl shell, enter:
% oa::examples::demoSample
route.tcl Tcl routines for creating and printing information on OpenAccess routes. From the Tcl shell, enter:
% oa::examples::demoRoute
pcell.tcl Demonstrates the Tcl PCell interface. From the Tcl shell, enter:
% oa::examples::demoPcell
oa.tcl Tcl routines for creating and printing information on shapes. From the Tcl shell, enter:
% oa::examples::demoOa
ns.tcl Demonstrates OA Namespaces in Tcl. From the Tcl shell, enter:
% oa::examples::demoNS
libStructure.tcl Prints the cells, views and DMFiles in an OA library. From the Tcl shell, enter:
% oa::examples::demoInst
inst.tcl Traverses an OA design and prints information about the instances it contains. From the Tcl shell, enter:
% oa::examples::demoInst
hello.tcl The Tcl implementation of the C++ HelloWorld example. From the Tcl shell, enter:
% oa::examples::demoHello
contents.tcl Prints statistical information about the contents of an OA design. From the Tcl shell, enter:
% oa::examples::demoContents

Programming With the Tcl OpenAccess API

C++ Access

This section addresses:

As an example, consider a C++ application function to get all instances in a design that match a given name pattern. The programmer wants to bind this function in Tcl so that it can be used in Tcl as in the following example:

    set design [oa::DesignOpen lib cell view r]
    set instances [findInstance $design "I3.*" [oa::NativeNS]]

The Tcl command findInstance is bound to the implementation with the wrapper function:

    extern "C" int
    wrap_findInstance (ClientData  clientData,
                       Tcl_Interp  *interp,
                       int         objc,
                       Tcl_Obj     *const objv[]);

This function is usually registered by the Tcl initialization procedure of the shared library, as explained in the Tcl documentation of the load command. This is achieved with a call similar to:

    Tcl_CreateObjCommand(interp, "findNearestRoute", wrap_findNearestRoute, NULL, NULL);

The second element of the objv argument refers to an OpenAccess object, in this case a design. The body of the binding function obtains the C++ OpenAccess object from the objv as explained below. The binding function also needs a way to create Tcl objects that are returned from the application wrapper, which in this example are objects that are stored in a Tcl list. These Tcl objects are used in a Tcl script and can be passed to an OpenAccess Tcl command. The TclCnv template class converts Tcl objects to OpenAccess C++ objects and converts OpenAccess C++ objects to Tcl objects. The oaTclArgException class is used to throw exceptions due to conversion errors. The TclCnv class is easily used in binding code.

extern "C" int 
wrap_findInstance(ClientData    clientData,
                  Tcl_Interp    *interp,
                  int           objc,
                  Tcl_Obj       *const objv[])
{
    TclEnv  env(interp, objc, objv);

    try {
     const TclParams params(env.params());

     switch (params.size()) {
       case 3:
         {
           TclCnv<const oaDesign*>        design(params[0]);
           TclCnv<const oaString&>        pattern(params[1]);
           TclCnv<const oaNameSpace&>     ns(params[2]);
           TclCnv<oaArray<oaInst*> >      inst(findInstance(design, pattern, 
                                                            ns));
           Tcl_Obj                        *result = createTclList(inst);

           Tcl_SetObjResult(interp, result);

           return TCL_OK;
         }
 
       default:
         throw oaTclArgException(oacBadParamCount);
     }
 
    } catch (oaTclException &ex) {
        return env.error(ex.getMsg());
    } catch (oaException  &ex) {
        Tcl_SetObjResult(interp, Tcl_NewStringObj(ex.getMsg(), -1));
		
        return TCL_ERROR;
    }
}

The TclParams class is a simple helper class to avoid array boundary violations. A complete code example is provided as wrapper.h and wrapper.cpp in the directory <install_directory>/examples/oa/Tcl.

Linking Shared Libraries

There are six shared libraries needed for binding Tcl with the OpenAccess API. These are:

  oaLangBaseContains support classes to describe OpenAccess classes.
  oaLangInfoContains the description of OpenAccess classes and functions.
  oaTclCommonProvides general support classes for Tcl bindings of C++ types.
  oaTclBaseProvides support classes for Tcl bindings to OpenAccess types.
  oaTclPlugInProvides support classes for the Tcl Script engine, which is used for Tcl Pcells.
  oaTclHelpProvides the oa::help command bindings.

Shared libraries for custom Tcl bindings must be linked to oaTclBase, oaLangInfo, oaTclCommon, oaLangBase, and oaTclPlugIn; and your header file must include oaTcl.h.

Using a Specific Tcl Interpreter

Some applications use a Tcl interpreter for other purposes besides OpenAccess. If a consistent interpreter is required in these situations, make the following call from the application:

oaTcl::oaTclEngineFactory::create(interp);

This call is necessary only in exceptional situations where the oaTcl shared library is not loaded from the interpreter. This call must be made before the call to Oa_Init.

Limitations

The oaTcl dynamic libraries are not guaranteed to be drop-in compatible for applications that are compiled using the oaTcl header files. Drop-in compatibility is only guaranteed for the public C++ OpenAccess API. Applications that call the Tcl bindings from C++ must be recompiled for each release of OpenAccess. Note however that OpenAccess API compatibility means that Tcl scripts using the oaTcl command bindings will not require changes due to future releases.

Other limitations of the OpenAccess API in Tcl are: