An Introduction to OpenAccess Scripting

James D. Masters Corp

Design Automation Conference June 6, 2011

1 What is it?

• Standalone direct interface to OpenAccess (OA) – No dependencies beyond OA and no licensing fees – Performance and memory usage is good for a scripting language • Matches C++ API with some melding to native language features – Existing C++ API documentation can be referenced – Auto conversions to/from native types (e.g. strings, integers, floats) • Includes convenience functions to reduce code and improve productivity – More natural interface; e.g. native array of (1.234, 9.876) instead of oaPoint(1234, 9876)

2 How does it work?

Perl API Python API Ruby API Tcl API C# API Language-Specific Bindings

Type Mapping Type Mapping Type Mapping Type Mapping Type Mapping Common Wrapper Architecture Interface Common SWIG Framework

OA API C++ Programming Interface

• Common interface through SWIG ensures cross-language consistency and reuse • All languages interface OA through the official OA API

3 Basic type mapping

• Some basic OA types are mapped to native types in the target language

Perl Python Ruby Tcl C#

oaBoolean integer bool Boolean integer bool

oa*Int integer int Fixnum integer int, uint, long,ulong oaFloat/Double Float float Float float float/double

oaString string string String string string

oaArray array array Array list IList

oaTime oaTime oaTime Time oaTime DateTime

oaTimestamp integer int Fixnum integer uint

oaComplex oaComplex complex OaComplex oaComplex oaComplex

oaPoint oaPoint/array oaPoint/array OaPoint/Array oaPoint/list oaPoint

oaBox oaBox/array oaBox/array OaBox/Array oaBox/list oaBox

oaTransform oaTransform/ oaTransform/ OaTransform/ oaTransform/ oaTransform array array Array list

4 Input string / scalarName values

• All oaScript languages allow a native string to be used in place of an oaScalarName

C++ oaNativeNS nns(); oaString str("mylib"); oaScalarName sname(nns, str); oaLib *lib = oaLib::find(sname); Perl $lib = oaLib::find("mylib"); Python lib = oaLib.find("mylib") Ruby lib = OaLib.find("mylib") Tcl set lib [oaLib_find mylib] C# oaLib lib = oaLib.find("mylib");

5 Mapping to OA API documentation

• Similar syntax to the C++ API Static Public Methods oaLib * oaLib::create (const oaScalarName &name, const oaString &libPath, oaLibMode mode=oacSharedLibMode, const oaString &dmSystem="oaDMSystem", const oaDMAttrArray *dmAttrList=NULL)

Perl oa::oaLib::create(oaScalarName|string, string, oaLibMode, string, array|undef) Python oa.oaLib.create(oaScalarName|string, oaString, oaLibMode, oaString, array|None) Ruby Oa::OaLib.create(oaScalarName|String, String, oaLibMode|symbol, String, Array|nil) Tcl oa::oaLib_create oaScalarName|string string|oaLibMode string list|"NULL" C# OpenAccess_4.oaLib.create(oaScalarName|string, string, oaLibMode, string, oaDMAttrArray)

6 Mapping to OA API documentation

• Sample documentation map to target language

Public Methods oaBoolean getAccess (oaLibAccess accessType, oaUInt4 timeout=0)

Perl $lib->getAccess(new oa::oaLibAccess('read')); $lib->getAccess($oa::oacReadLibAccess); Python lib.getAccess(oa.oaLibAccess('read')) lib.getAccess(oa.oaLibAccess(oa.oacReadLibAccess)) Ruby lib.getAccess(Oa::OaLibAccess.new('read')) lib.getAccess(Oa::OaLibAccess.new(Oa::OacReadLibAccess)) lib.getAccess(:read) Tcl $lib getAccess [oa::oaLibAccess "read"] $lib getAccess [oa::oaLibAccess $oa::oacReadLibAccess] $lib getAccess $oa::oacReadLibAccess C# lib.getAccess(oaLibAccess.oacReadLibAccess);

7 Enumerated wrappers • Enumerated wrappers (e.g. oaLibMode) are mapped differently in each language

Perl Input: Integer Output: Integer Python Input: Wrapped object, integer, or string Output: Wrapped object (can cast to integer value with “__int__”) Ruby Input: Wrapped object, integer, or string Output: Wrapped object (can cast to integer value with “to_i” or string with “to_s”) Tcl Input: Wrapped object or integer Output: Wrapped object (can cast to integer value with “$enumWrapper typeEnum”) C# Input: Native C# enum Output: Native C# enum

Note: all languages have the enum constants available (e.g. oacReadLibAccess)

8 Collections / Iterators • Map collections/iterators natively in target language; allow native loops when possible

Perl $iter = new oa::oaIter::oaNet($block->getNets()); while ($net = $iter->getNext()) { ... } Python for net in block.getNets(): ... Ruby block.getNets.each do |net| ... end Tcl oa::foreach net [$block getNets] { ... } C# foreach(oaNet net in block.getNets()) { ... }

9 Unique behaviors

• For safety, all languages except C# check for validity of an OA object first using oaObject::isValid() • Return strings, oaPoint, oaBox, and oaArray instead of requiring pre-allocation (example in Tcl): puts [$net getName] set boxlist [$fig getBBox] • Override default name space used in oaName type of conversions (example in Ruby): Oa::OaNameSpace.push(Oa::OaCdbaNS.new) # ... Default NS is OaCdbaNS in this section Oa::OaNameSpace.pop

10 C++: Dump Nets

#include #include "oaDesignDB.h"

int main( int argc, char *argv[] ) {

oa::oaDesignInit(); oa::oaLibDefList::openLibs(); oa::oaNativeNS nns;

oa::oaScalarName slib(nns, argv[1]), scell(nns, argv[2]), sview(nns, argv[3]);

oa::oaDesign *design = oa::oaDesign::open( slib, scell, sview, 'r' ); oa::oaBlock *block = design->getTopBlock();

oa::oaIter iter(block->getNets()); while (oa::oaNet *net = iter.getNext()) { oa::oaString str; std::cout << (net->getName(nns,str),str) << std::endl; }

}

11 Perl: Dump Nets

use oa::design;

oa::oaLibDefList::openLibs();

$design = oa::oaDesign::open($ARGV[0], $ARGV[1], $ARGV[2], "r"); $block = $design->getTopBlock();

$iter = new oa::oaIter::oaNet($block->getNets()); while ($net = $iter->getNext()) { print($net->getName()."\n"); }

12 Python: Dump Nets

import sys import oa.design

oa.oaLibDefList.openLibs()

design = oa.oaDesign.open(sys.argv[1], sys.argv[2], sys.argv[3], 'r') block = design.getTopBlock()

for net in block.getNets(): print net.getName()

13 Ruby: Dump Nets

require 'oa'

Oa::OaLibDefList.openLibs

design = Oa::OaDesign.open(ARGV[0], ARGV[1], ARGV[2], 'r') block = design.getTopBlock

block.getNets.each {|net| puts net.getName }

14 Tcl: Dump Nets

package require oa

oa::oaLibDefList_openLibs

set design [oa::oaDesign_open [lindex $argv 0] [lindex $argv 1] [lindex $argv 2] "r"] set block [$design getTopBlock]

oa::foreach net [$block getNets] { puts [$net getName] }

15 C#: Dump Nets

using System; using OpenAccess_4;

namespace DumpNets {

class NetDumper { static void Main(string[] args) { oaLibDefList.openLibs(); oaNameSpace.push(new oaNativeNS());

oaDesign design = oaDesign.open(args[0], args[1], args[2], 'r'); oaBlock block = design.getTopBlock();

foreach(oaNet net in block.getNets()) { Console.WriteLine("{0}", net.getName()); } } } }

16 Comparison of oasPython to pyoa

• Existing Python wrappers (LSI Python; “pyoa”) http://www.si2.org/openeda.si2.org/projects/python4oa • Performance problems previously seen are now resolved and oasPython is 2~4X faster than pyoa (SWIG 2.0.4) • Slight syntax differences (a fix-it module is provided to allow most pyoa code to be compatible with OAS Python) – Drop “_static” on static methods: oaDesign.static_find => oaDesign.find – Drop “Iter” methods (collections can become an iterator): oaBlock.getInstsIter => oaBlock.getInsts

17 Comparison of oasTcl to oaTcl

• Existing Tcl wrappers (Cadence Tcl; “oaTcl”) • Name differences – Slight differences in static method names: DesignOpen  oaDesign_open – Differences in OOP structure for method calls: [getTopBlock $design]  [$design getTopBlock] • Other: – oaTcl uses “user units” (float); oasTcl uses “DB units” (integer) – the use of user units as a float is currently being enabled in oasTcl – oaTcl lists of floats for oaPoint, oaBox; oasTcl returns the wrapped class which allows method calls: $box1 contains $box2 set point3 [$point1 + $point2] puts [$point toStr]

18 Future usability ideas

• Philosophical Question: – How closely should we tie ourselves with C++ API? – How should we differentiate convenience methods from the pure C++ API? Use a separate module? – Note: some convenience functions are already built-in (e.g. string and user unit conversions) • Prototype: quickly get/set oaObject properties (Ruby): shape.props[:foo] = 'bar' shape.props[:number] = 99 shape.props[:foo] shape.props[:number] • Idea: pull lib.def entries into a hash array

19 Future goals

• 2011 goals – 8/11 – oaAppDef support for Perl and C# (already in Tcl, Python, Ruby) – 10/11 – Finalize on special oaScript features (UUDBU conversion) – 12/11 – Production release (v1.0)

• Future goals – oaObserver support – Region query support – Enable plugins in scripting languages – Add convenience functions, extensions. – Additional languages?

20 Usage to date

• Current usage – Hierarchy traverser – Simple schematic/layout GUI interface – Library utilities (e.g. create library, attach to techlib) – Create DM properties on lib, cell, view, and/or cellview from YAML – Design statistics reporting – Interacting with design with embedded OA scripting in EDA tools – OA-based design migration software

• Future usage – Real-time web reporting? – Simple open-source design editor?

21 Usage within OpenPDK

• Used in Si2 OpenPDK working group to extract symbol information and export to SVG and YAML

22