From: Luke Kenneth Casson Leighton Date: Fri, 28 Feb 2020 18:35:36 +0000 (+0000) Subject: successful ring created around add.ap X-Git-Tag: partial-core-ls180-gdsii~187 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=03282bb68fc43a32e146d972714b21ecb3e65b96;p=soclayout.git successful ring created around add.ap --- diff --git a/experiments5/doAlu16.py b/experiments5/doAlu16.py index e827f79..177967c 100755 --- a/experiments5/doAlu16.py +++ b/experiments5/doAlu16.py @@ -105,7 +105,7 @@ Cfg.getParamBool ( 'misc.bug' ).setBool ( False ) Cfg.getParamBool ( 'misc.logMode' ).setBool ( True ) Cfg.getParamBool ( 'misc.verboseLevel1' ).setBool ( True ) Cfg.getParamBool ( 'misc.verboseLevel2' ).setBool ( True ) -#Cfg.getParamInt ( 'misc.minTraceLevel' ).setInt ( 159 ) +Cfg.getParamInt ( 'misc.minTraceLevel' ).setInt ( 159 ) #Cfg.getParamInt ( 'misc.maxTraceLevel' ).setInt ( 160 ) Cfg.getParamEnumerate ( 'etesian.effort' ).setInt ( 2 ) Cfg.getParamPercentage( 'etesian.spaceMargin' ).setPercentage( 20.0 ) @@ -245,17 +245,17 @@ def add ( **kw ): UpdateSession.open() #net = cell.getNet('b(%d)' % 0) net = cell.getNet('vdd') - build_downtrace(net, VIA23, metal3, 5, 10, 20) - build_downtrace(net, VIA23, metal3, 10, 10, 20) - build_crosstrace(net, VIA23, metal3, 5, 10, 10) - build_crosstrace(net, VIA23, metal3, 5, 10, 20) + build_downtrace(net, VIA23, metal2, -5, -10, -20) + build_downtrace(net, VIA23, metal2, -10, -10, -20) + build_crosstrace(net, VIA23, metal2, -5, -10, -10) + build_crosstrace(net, VIA23, metal2, -5, -10, -20) for i in range(16): if False: net = cell.getNet('b(%d)' % i) x = 20.0*i + 10.0 + 10 y = height-10 build_downtrace(net, metal2, x, y, y+10) - ab.inflate ( l(2.0) ) + ab.inflate ( l(30.0) ) cell.setAbutmentBox( ab ) UpdateSession.close() diff --git a/experiments5/ringoscillator.py b/experiments5/ringoscillator.py new file mode 100755 index 0000000..8451eb5 --- /dev/null +++ b/experiments5/ringoscillator.py @@ -0,0 +1,714 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import re +import traceback +import os.path +import optparse +import Cfg +import Hurricane +from Hurricane import DbU +from Hurricane import DataBase +from Hurricane import UpdateSession +from Hurricane import Breakpoint +from Hurricane import Box +from Hurricane import Transformation +from Hurricane import Instance +from Hurricane import Contact +from Hurricane import Vertical +from Hurricane import Horizontal +from Hurricane import Pin +from Hurricane import Net +from Hurricane import NetExternalComponents +import Viewer +import CRL +import Etesian +import Anabatic +import Katana +import Unicorn +from helpers import l, u, n +import clocktree.ClockTree +import plugins.RSavePlugin +import plugins.ClockTreePlugin +import symbolic.cmos + +af = CRL.AllianceFramework.get() + + +def build_crosstrace(net, via, layer, x, x1, y): + + contacts = \ + [ Contact.create( net, via, l(x), l(y), l(1.0), l(1.0) ) + , Contact.create( net, via, l(x1), l(y), l(1.0), l(1.0) ) + ] + + createHorizontal( contacts, l(y), layer ) + print "slaves", contacts[-1].getSlaveComponents() + for component in contacts[-1].getSlaveComponents(): + NetExternalComponents.setExternal(component) + +def build_downtrace(net, via, layer, x, y, y1): + + contacts = \ + [ Contact.create( net, via, l(x), l(y), l(1.0), l(1.0) ) + , Contact.create( net, via, l(x), l(y1), l(1.0), l(1.0) ) + ] + + createVertical( contacts, l(x), layer ) + print "slaves", contacts[-1].getSlaveComponents() + for component in contacts[-1].getSlaveComponents(): + NetExternalComponents.setExternal(component) + +#print "af", dir(af) +#sys.exit(0) + +Cfg.Configuration.pushDefaultPriority( Cfg.Parameter.Priority.UserFile ) + +cellsTop = '~/alliance-check-toolkit/cells' +env = af.getEnvironment() +env.addSYSTEM_LIBRARY( library=cellsTop+'/nsxlib', mode=CRL.Environment.Prepend ) +env.addSYSTEM_LIBRARY( library=cellsTop+'/mpxlib', mode=CRL.Environment.Prepend ) + + +Cfg.getParamBool ( 'misc.catchCore' ).setBool ( False ) +Cfg.getParamBool ( 'misc.info' ).setBool ( False ) +Cfg.getParamBool ( 'misc.paranoid' ).setBool ( False ) +Cfg.getParamBool ( 'misc.bug' ).setBool ( False ) +Cfg.getParamBool ( 'misc.logMode' ).setBool ( True ) +Cfg.getParamBool ( 'misc.verboseLevel1' ).setBool ( True ) +Cfg.getParamBool ( 'misc.verboseLevel2' ).setBool ( True ) +Cfg.getParamInt ( 'misc.minTraceLevel' ).setInt ( 159 ) +#Cfg.getParamInt ( 'misc.maxTraceLevel' ).setInt ( 160 ) +Cfg.getParamEnumerate ( 'etesian.effort' ).setInt ( 2 ) +Cfg.getParamPercentage( 'etesian.spaceMargin' ).setPercentage( 20.0 ) +Cfg.getParamPercentage( 'etesian.aspectRatio' ).setPercentage( 100.0 ) +Cfg.getParamBool ( 'etesian.uniformDensity' ).setBool ( True ) +Cfg.getParamInt ( 'anabatic.edgeLenght' ).setInt ( 24 ) +Cfg.getParamInt ( 'anabatic.edgeWidth' ).setInt ( 8 ) +Cfg.getParamString ( 'anabatic.topRoutingLayer' ).setString ( 'METAL5') +Cfg.getParamInt ( 'katana.eventsLimit' ).setInt ( 1000000 ) +Cfg.getParamInt ( 'katana.hTracksReservedLocal' ).setInt ( 7 ) +Cfg.getParamInt ( 'katana.vTracksReservedLocal' ).setInt ( 6 ) +#Cfg.getParamInt ( 'clockTree.minimumSide' ).setInt ( l(1000) ) + +env = af.getEnvironment() +env.setCLOCK( '^clk$|m_clock' ) +env.setPOWER( 'vdd' ) +env.setGROUND( 'vss' ) + +Cfg.Configuration.popDefaultPriority() + +################### +# add + +def add ( cell, **kw ): + editor = None + if kw.has_key('editor') and kw['editor']: + editor = kw['editor'] + + db = DataBase.getDB() + print db, dir(db) + metal2 = DataBase.getDB().getTechnology().getLayer( 'metal2' ) + metal3 = DataBase.getDB().getTechnology().getLayer( 'metal3' ) + metal5 = DataBase.getDB().getTechnology().getLayer( 'metal5' ) + + #cell = af.getCell( 'add', CRL.Catalog.State.Logical ) + print cell.getNet('a(0)') + + if not cell: + print '[ERROR] Unable to load cell "alu16.vst", aborting .' + return False + kw[ 'cell' ] = cell + + width = 350.0 + height = 405.0 + + ab = Box( l( 0.0 ) + , l( 0.0 ) + , l( width ) + , l( height ) ) + + cellGauge = af.getCellGauge() + spaceMargin = (Cfg.getParamPercentage('etesian.spaceMargin').asPercentage()+5) / 100.0 + aspectRatio = Cfg.getParamPercentage('etesian.aspectRatio').asPercentage() / 100.0 + clocktree.ClockTree.computeAbutmentBox( cell, + spaceMargin, aspectRatio, cellGauge ) + ab2 = cell.getAbutmentBox() + print "box", ab, ab.getHeight(), ab.getWidth() + print "calc box", ab2, ab2.getHeight(), ab2.getWidth() + + #height = ab.getHeight() + #width = ab.getWidth() + + #UpdateSession.open() + cell.setAbutmentBox( ab ) + + for i in range(16): + if True: + x = 20.0*i + 10.0 + y = height + net = cell.getNet('a(%d)' % i) + print "net", net + Pin.create( net + , 'a(%d).0' % i + , Pin.Direction.NORTH + , Pin.PlacementStatus.FIXED + , metal3 + , l( x ), l( y - 0 ) # Position. + , l( 2.0 ) , l( 2.0 ) # Size. + ) + for i in range(16): + if True: + Pin.create( cell.getNet('o(%d)' % i) + , 'o(%d).0' % i + , Pin.Direction.SOUTH + , Pin.PlacementStatus.FIXED + , metal3 + , l( 10.0*i + 100.0 ), l( 0) # Position. + , l( 2.0 ) , l( 2.0 ) # Size. + ) + + for i in range(16): + if True: + net = cell.getNet('b(%d)' % i) + x = 20.0*i + 10.0 + 10 + y = height - 0 + #build_downtrace(net, metal3, x, y+11, y) + #continue + Pin.create( net + , 'b(%d).0' % i + , Pin.Direction.NORTH + , Pin.PlacementStatus.FIXED + , metal3 + , l( x ), l( y - 0 ) # Position. + , l( 2.0 ) , l( 2.0 ) # Size. + ) + if False: + Pin.create( cell.getNet('rst') + , 'p_reset.0' + , Pin.Direction.WEST + , Pin.PlacementStatus.FIXED + , metal2 + , l( 0.0 ) + , l( 140.0 ) + , l( 2.0 ) + , l( 2.0 ) + ) + #UpdateSession.close() + + if True: + if editor: editor.setCell( cell ) + + etesian = Etesian.EtesianEngine.create(cell) + etesian.place() + + katana = Katana.KatanaEngine.create(cell) + katana.digitalInit () + #katana.runNegociatePreRouted() + print dir(katana) + katana.runGlobalRouter (0) + katana.loadGlobalRouting ( Anabatic.EngineLoadGrByNet ) + katana.layerAssign ( Anabatic.EngineNoNetLayerAssign ) + katana.runNegociate ( Katana.Flags.NoFlags ) + katana.finalizeLayout () + print dir(katana) + success = katana.getSuccessState() + katana.destroy() + + if False: + VIA23 = DataBase.getDB().getTechnology().getLayer( 'VIA23' ) + UpdateSession.open() + #net = cell.getNet('b(%d)' % 0) + net = cell.getNet('vdd') + build_downtrace(net, VIA23, metal2, -5, -10, -20) + build_downtrace(net, VIA23, metal2, -10, -10, -20) + build_crosstrace(net, VIA23, metal2, -5, -10, -10) + build_crosstrace(net, VIA23, metal2, -5, -10, -20) + for i in range(16): + if False: + net = cell.getNet('b(%d)' % i) + x = 20.0*i + 10.0 + 10 + y = height-10 + build_downtrace(net, metal2, x, y, y+10) + ab.inflate ( l(30.0) ) + cell.setAbutmentBox( ab ) + UpdateSession.close() + + #af.saveCell( cell, CRL.Catalog.State.Views ) + #plugins.RSavePlugin.ScriptMain( **kw ) + + + +#def toDbU(v): return DbU.fromLambda(v) +def toDbU(v): return l(v) + + + +def doBreak(level, message): + UpdateSession.close() + Breakpoint.stop(level, message) + UpdateSession.open() + + +class Model (object): + + HorizontalAccess = 1 + VerticalAccess = 2 + + def __init__(self, modelName): + UpdateSession.open() + self.fillerCount = 0 + self.af = CRL.AllianceFramework.get() + #self.cell = af.createCell(modelName) + self.cell = af.getCell( modelName, CRL.Catalog.State.Logical ) + self.createNet('vss', direction=Net.Direction.IN, + isExternal=True, isGlobal=True, type=Net.Type.POWER) + self.createNet('vdd', direction=Net.Direction.IN, + isExternal=True, isGlobal=True, type=Net.Type.GROUND) + + self.build() + UpdateSession.close() + return + + def createNet(self, netName, **attributes): + net = self.cell.getNet(netName) + if not net: + net = Net.create(self.cell, netName) + + if 'direction' in attributes: + net.setDirection(attributes['direction']) + if 'isExternal' in attributes: + net.setExternal(attributes['isExternal']) + if 'isGlobal' in attributes: + net.setGlobal(attributes['isGlobal']) + if 'type' in attributes: + net.setType(attributes['type']) + return net + + def getNet(self, netName): + return self.createNet(netName) + + def connect(self, instanceRef, pin, netRef): + if isinstance(instanceRef, str): + instance = self.getInstance(instanceRef) + else: + instance = instanceRef + + if isinstance(netRef, str): + net = self.getNet(netRef) + else: + net = netRef + + masterNet = instance.getMasterCell().getNet(pin) + if not masterNet: + print '[ERROR] Master cell "%s" of instance "%s" ' \ + 'has no connector named "%s".' \ + % (instance.getMasterCell().getName(), instance.getName(), pin) + + instance.getPlug(instance.getMasterCell().getNet(pin)).setNet(net) + return + + def place(self, instanceRef, x, y, orient): + if isinstance(instanceRef, str): + instance = self.getInstance(instanceRef) + else: + instance = instanceRef + + instance.setTransformation(Transformation(x, y, orient)) + instance.setPlacementStatus(Instance.PlacementStatus.PLACED) + return + + def createInstance(self, instanceName, modelRef, portmap={}, transf=None): + instance = self.cell.getInstance(instanceName) + if not instance: + if isinstance(modelRef, str): + model = af.getCell(modelRef, CRL.Catalog.State.Views) + else: + model = modelRef + instance = Instance.create(self.cell, instanceName, model) + for pin, net in portmap.items(): + self.connect(instance, pin, net) + + if transf: + self.place(instance, transf[0], transf[1], transf[2]) + return instance + + def createAccess(self, termPath, x, y, flags): + insName, pinName = termPath.split('.') + instance = self.cell.getInstance(insName) + if not instance: + print '[ERROR] Model "%s" has no instance named "%s"' \ + % (self.cell.getName(), insName) + try: + plug = instance.getPlug(instance.getMasterCell().getNet(pinName)) + except BaseException: + print '[ERROR] Model "%s" of instance "%s" has ' \ + 'no terminal named "%s"' \ + % (instance.getMasterCell().getName(), + instance.getName(), pinName) + + net = plug.getNet() + VIA12 = self.getLayer('VIA12') + VIA23 = self.getLayer('VIA23') + METAL2 = self.getLayer('METAL2') + + rp = RoutingPad.create( + net, Occurrence(plug), RoutingPad.BiggestArea) + rpCenter = rp.getPosition() + + if y is None: + y = rpCenter.getY() + contact1 = Contact.create(rp, VIA12, toDbU(0.0), y - rpCenter.getY()) + + if flags & Model.VerticalAccess: + contact2 = contact1 + contact1 = Contact.create(net, VIA23, x, y) + Horizontal.create(contact2, contact1, METAL2, y, toDbU(2.0)) + return contact1 + + def createVertical(self, contacts, x, width=None, layer=None): + def yincrease(lhs, rhs): return int(lhs.getY() - rhs.getY()) + + contacts.sort(yincrease) + + if width is None: + width = toDbU(2.0) + + if layer is None: + layer = self.getLayer("METAL3") + for i in range(1, len(contacts)): + Vertical.create(contacts[i - 1], contacts[i], layer, x, width) + return + + def createHorizontal(self, contactPaths, y, width=None, layer=None): + def xincrease(lhs, rhs): return int(lhs.getX() - rhs.getX()) + + if isinstance(contactPaths[0], str): + contacts = [] + for termPath in contactPaths: + contacts.append(self.createAccess( + termPath, None, y, Model.HorizontalAccess)) + else: + contacts = contactPaths + + if width is None: + width = toDbU(2.0) + + contacts.sort(xincrease) + + if layer is None: + layer = self.getLayer("METAL2") + for i in range(1, len(contacts)): + Horizontal.create(contacts[i - 1], contacts[i], layer, y, width) + return + + def createSerpentine( + self, contactPaths, ymin, ymax, width=None, layer=None): + def xincrease(lhs, rhs): return int(lhs.getX() - rhs.getX()) + + if isinstance(contactPaths[0], str): + contacts = [] + for termPath in contactPaths: + contacts.append(self.createAccess( + termPath, None, None, Model.HorizontalAccess)) + else: + contacts = contactPaths + + if len(contacts) != 2: + print '[ERROR] Model.createSerpentine() takes exactly ' \ + 'two points, not %d.' % len( contacts) + + if layer is None: + layer = self.getLayer("METAL2") + if width is None: + width = toDbU(2.0) + + contacts.sort(xincrease) + + turn0 = contacts[0] + trackPitch = toDbU(5.0) + for i in range((contacts[1].getX() - contacts[0].getX()) / trackPitch): + y = ymin + if i % 2: + y = ymax + + x = turn0.getX() + turn1 = Contact.create( + turn0.getNet(), layer, x, y, width, width) + turn2 = Contact.create( + turn0.getNet(), layer, x + trackPitch, y, width, width) + Vertical .create(turn0, turn1, layer, x, width) + Horizontal.create(turn1, turn2, layer, y, width) + + turn0 = turn2 + + Vertical.create(turn0, contacts[1], layer, contacts[1].getX(), width) + + return + + def addFillersRow(self, x, y, orient, length): + tieWidth = self.getMasterCell("tie_x0").getAbutmentBox().getWidth() + i = 0 + for i in range(length / tieWidth): + self.createInstance( + "filler_%d_i" % + self. fillerCount, "tie_x0", transf=( + x + tieWidth * i, y, orient)) + self.fillerCount += 1 + if length % tieWidth: + delta = 0 + if length > tieWidth: + delta = 1 + self.createInstance("filler_%d_i" % self.fillerCount, "rowend_x0", + transf=(x + tieWidth * (i + delta), y, orient)) + self.fillerCount += 1 + return + + def getLayer(self, name): + return DataBase.getDB().getTechnology().getLayer(name) + + def getCell(self): return self.cell + + def getMasterCell( self, name): + return self.af.getCell(name, CRL.Catalog.State.Views) + + def setAbutmentBox(self, ab): self.cell.setAbutmentBox(ab) + + def getAbutmentBox(self): return self.cell.getAbutmentBox() + + def getCellWidth(self, name): + return self.getMasterCell(name).getAbutmentBox().getWidth() + + def save(self): + self.af.saveCell(self.cell, CRL.Catalog.State.Physical) + + def build(self): + print '[ERROR] Model.build() base class method should never be called.' + + +class Add (Model): + + def build(self): + #self.setAbutmentBox( + #Box(toDbU(0.0), toDbU(0.0), toDbU(1595.0), toDbU(450.0))) + add(self.cell) + self.buildPower() + + def addFillers(self): + self.addFillersRow(toDbU(1580.0), toDbU(0.0), + Transformation.Orientation.ID, toDbU(15.0)) + self.addFillersRow(toDbU(1570.0), toDbU(100.0), + Transformation.Orientation.MY, toDbU(5.0)) + self.addFillersRow(toDbU(1570.0), toDbU(100.0), + Transformation.Orientation.ID, toDbU(25.0)) + self.addFillersRow(toDbU(1530.0), toDbU(200.0), + Transformation.Orientation.MY, toDbU(45.0)) + self.addFillersRow(toDbU(1550.0), toDbU(200.0), + Transformation.Orientation.ID, toDbU(10.0)) + self.addFillersRow(toDbU(1550.0), toDbU(300.0), + Transformation.Orientation.MY, toDbU(25.0)) + self.addFillersRow(toDbU(1570.0), toDbU(300.0), + Transformation.Orientation.ID, toDbU(25.0)) + self.addFillersRow(toDbU(1550.0), toDbU(400.0), + Transformation.Orientation.MY, toDbU(25.0)) + + def buildPower(self): + METAL1 = self.getLayer("METAL1") + METAL2 = self.getLayer("METAL2") + METAL3 = self.getLayer("METAL3") + VIA12 = self.getLayer("VIA12") + VIA23 = self.getLayer("VIA23") + powerWidth = toDbU(2.0) + powerSpacing = toDbU(5.0) + ab = self.getAbutmentBox() + vdd = self.getNet("vdd") + vss = self.getNet("vss") + vddAxis = Box(ab).inflate(powerSpacing + powerWidth / 2) + vssAxis = Box(ab).inflate( + powerSpacing + powerWidth / 2 + powerWidth + toDbU(5.0)) + + # Building "vdd" power ring. + westContactsVdd = [ + Contact.create( vdd, VIA23, vddAxis.getXMin(), vddAxis.getYMin(), + powerWidth, powerWidth), + Contact.create( vdd, VIA23, vddAxis.getXMin(), vddAxis.getYMax(), + powerWidth, powerWidth)] + eastContactsVdd = [ + Contact.create( vdd, VIA23, vddAxis.getXMax(), vddAxis.getYMin(), + powerWidth, powerWidth), + Contact.create( vdd, VIA23, vddAxis.getXMax(), vddAxis.getYMax(), + powerWidth, powerWidth)] + + for i in range(0): + ywidth = toDbU(12.0) + if i == 4: + ywidth = toDbU(6.0) + yaxis = ab.getXMin() + toDbU(50.0) * (1 + i * 2) + + westContact = Contact.create( vdd, VIA12, vddAxis.getXMin(), + yaxis, powerWidth, ywidth) + eastContact = Contact.create( vdd, VIA12, vddAxis.getXMax(), + yaxis, powerWidth, ywidth) + self.createHorizontal( [westContact, eastContact], + yaxis, ywidth, layer=METAL1) + + westContact = Contact.create( + vdd, VIA23, vddAxis.getXMin(), yaxis, powerWidth, ywidth) + eastContact = Contact.create( + vdd, VIA23, vddAxis.getXMax(), yaxis, powerWidth, ywidth) + + westContactsVdd.insert(-1, westContact) + eastContactsVdd.insert(-1, eastContact) + + self.createVertical(westContactsVdd, vddAxis.getXMin(), powerWidth) + self.createVertical(eastContactsVdd, vddAxis.getXMax(), powerWidth) + + xcenter = vddAxis.getCenter().getX() + powerWidth / 2 + toDbU(5.0) + if False: + accessContactsVdd = [ + Contact.create( + vdd, + VIA23, + xcenter, + vddAxis.getYMax(), + powerWidth, + powerWidth), + Contact.create( + vdd, + METAL3, + xcenter, + toDbU(528.0), + powerWidth, + toDbU(2.0))] + + northContactsVdd = \ + [westContactsVdd[-1], + #accessContactsVdd[0], + eastContactsVdd[-1] + ] + southContactsVdd = \ + [westContactsVdd[0], eastContactsVdd[0] + ] + self.createHorizontal( + southContactsVdd, vddAxis.getYMin(), powerWidth) + self.createHorizontal( + northContactsVdd, vddAxis.getYMax(), powerWidth) + #self.createVertical( + #accessContactsVdd, xcenter, powerWidth) + #for component in accessContactsVdd[-1].getSlaveComponents(): + #NetExternalComponents.setExternal(component) + + # Building "vss" power ring. + westContactsVss = [ + Contact.create( + vss, + VIA23, + vssAxis.getXMin(), + vssAxis.getYMin(), + powerWidth, + powerWidth), + Contact.create( + vss, + VIA23, + vssAxis.getXMin(), + vssAxis.getYMax(), + powerWidth, + powerWidth)] + eastContactsVss = [ + Contact.create( + vss, + VIA23, + vssAxis.getXMax(), + vssAxis.getYMin(), + powerWidth, + powerWidth), + Contact.create( + vss, + VIA23, + vssAxis.getXMax(), + vssAxis.getYMax(), + powerWidth, + powerWidth)] + + for i in range(5): + ywidth = toDbU(12.0) + if i == 0: + ywidth = toDbU(6.0) + yaxis = ab.getXMin() + toDbU(50.0) * (i * 2) + + westContact = Contact.create( + vss, VIA12, vssAxis.getXMin(), yaxis, powerWidth, ywidth) + eastContact = Contact.create( + vss, VIA12, vssAxis.getXMax(), yaxis, powerWidth, ywidth) + self.createHorizontal( + [westContact, eastContact], yaxis, ywidth, layer=METAL1) + + westContact = Contact.create( + vss, VIA23, vssAxis.getXMin(), yaxis, powerWidth, ywidth) + eastContact = Contact.create( + vss, VIA23, vssAxis.getXMax(), yaxis, powerWidth, ywidth) + + westContactsVss.insert(-1, westContact) + eastContactsVss.insert(-1, eastContact) + + self.createVertical(westContactsVss, vssAxis.getXMin(), powerWidth) + self.createVertical(eastContactsVss, vssAxis.getXMax(), powerWidth) + + xcenter = vssAxis.getCenter().getX() - powerWidth / 2 - toDbU(5.0) + if False: + accessContactsVss = [ + Contact.create( + vss, + VIA23, + xcenter, + vssAxis.getYMax(), + powerWidth, + powerWidth), + Contact.create( + vss, + METAL3, + xcenter, + toDbU(528.0), + powerWidth, + toDbU(2.0))] + northContactsVss = \ + [westContactsVss[-1], + # accessContactsVss[0], + eastContactsVss[-1] + ] + southContactsVss = \ + [westContactsVss[0], eastContactsVss[0] + ] + + self.createHorizontal( + southContactsVss, vssAxis.getYMin(), powerWidth) + self.createHorizontal( + northContactsVss, vssAxis.getYMax(), powerWidth) + #self.createVertical( + # accessContactsVss, xcenter, powerWidth) + #for component in accessContactsVss[-1].getSlaveComponents(): + #NetExternalComponents.setExternal(component) + + ab.inflate(powerSpacing + powerWidth * 2 + toDbU(20.0)) + self.setAbutmentBox(ab) + + return + + +def ScriptMain(**kw): + editor = None + if "editor" in kw and kw["editor"]: + editor = kw["editor"] + + ringo = Add('add') + ringo.save() + if editor: + editor.setCell(ringo.getCell()) + editor.fit() + return True + + +if __name__ == "__main__": + ScriptMain() + sys.exit(0)