diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index ba922c57..6247a414 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -61,6 +61,13 @@ ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py ) + set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/power.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/corona.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/pads.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/chip.py + ) install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus ) install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins ) @@ -70,4 +77,5 @@ install ( FILES ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha ) install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block ) install ( FILES ${pyPluginAlphaC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/core2chip ) + install ( FILES ${pyPluginAlphaChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/chip ) #install ( PROGRAMS ${pyTools} DESTINATION bin ) diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index b746854a..988960fe 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -56,7 +56,8 @@ from alpha.block.clocktree import ClockTree #from alpha.block.hfns2 import BufferTree from alpha.block.hfns3 import BufferTree from alpha.block.configuration import IoPin -from alpha.block.configuration import BlockState +from alpha.block.configuration import BlockConf +from alpha.block.configuration import GaugeConf timing.staticInit() @@ -70,8 +71,8 @@ class Side ( object ): and perform pins creation & placement. """ - def __init__ ( self, state, side ): - self.state = state + def __init__ ( self, conf, side ): + self.conf = conf self.side = side self.pinSpecs = [] self.expandPins = True @@ -99,25 +100,25 @@ class Side ( object ): box has been setup. """ if self.side & IoPin.WEST: - self.gauge = self.state.gaugeConf.hDeepRG - self.ubegin = self.state.yMin - self.uend = self.state.yMax - self.sidePos = self.state.xMin + self.gauge = self.conf.hDeepRG + self.ubegin = self.conf.yMin + self.uend = self.conf.yMax + self.sidePos = self.conf.xMin elif self.side & IoPin.EAST: - self.gauge = self.state.gaugeConf.hDeepRG - self.ubegin = self.state.yMin - self.uend = self.state.yMax - self.sidePos = self.state.xMax + self.gauge = self.conf.hDeepRG + self.ubegin = self.conf.yMin + self.uend = self.conf.yMax + self.sidePos = self.conf.xMax elif self.side & IoPin.SOUTH: - self.gauge = self.state.gaugeConf.vDeepRG - self.ubegin = self.state.xMin - self.uend = self.state.xMax - self.sidePos = self.state.yMin + self.gauge = self.conf.vDeepRG + self.ubegin = self.conf.xMin + self.uend = self.conf.xMax + self.sidePos = self.conf.yMin elif self.side & IoPin.NORTH: - self.gauge = self.state.gaugeConf.vDeepRG - self.ubegin = self.state.xMin - self.uend = self.state.xMax - self.sidePos = self.state.yMax + self.gauge = self.conf.vDeepRG + self.ubegin = self.conf.xMin + self.uend = self.conf.xMax + self.sidePos = self.conf.yMax def getNextPinPosition ( self, flags, upos, ustep ): """ @@ -179,26 +180,26 @@ class Side ( object ): status = 0 if self.side & (IoPin.NORTH | IoPin.SOUTH): - gauge = self.state.gaugeConf.vDeepRG + gauge = self.conf.vDeepRG upos = ioPin.upos for index in ioPin.indexes: pinName = ioPin.stem.format( index ) - net = self.state.cell.getNet( pinName ) + net = self.conf.cell.getNet( pinName ) if net is None: print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) continue - if net.isClock() and self.state.useClockTree: + if net.isClock() and self.conf.useClockTree: print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) )) continue - pinName += '.{}'.format(self.state.getIoPinsCounts(net)) + pinName += '.{}'.format(self.conf.getIoPinsCounts(net)) pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) - if pinPos.getX() > self.state.xMax or pinPos.getX() < self.state.xMin: + if pinPos.getX() > self.conf.xMax or pinPos.getX() < self.conf.xMin: print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside north or south abutment box side.' \ .format(pinName) , '(x:{}, xAB: [{}:{}])' \ .format( DbU.getValueString(pinPos.getX()) - , DbU.getValueString(self.state.xMin) - , DbU.getValueString(self.state.xMax) ) ] )) + , DbU.getValueString(self.conf.xMin) + , DbU.getValueString(self.conf.xMax) ) ] )) status += 1 trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) pin = Pin.create( net @@ -213,26 +214,26 @@ class Side ( object ): ) NetExternalComponents.setExternal( pin ) self.append( pin ) - self.state.incIoPinsCounts( net ) + self.conf.incIoPinsCounts( net ) if upos: upos += ioPin.ustep else: - gauge = self.state.gaugeConf.hDeepRG + gauge = self.conf.hDeepRG upos = ioPin.upos for index in ioPin.indexes: pinName = ioPin.stem.format(index) - net = self.state.cell.getNet( pinName ) + net = self.conf.cell.getNet( pinName ) if net is None: print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) continue - pinName += '.{}'.format(self.state.getIoPinsCounts(net)) + pinName += '.{}'.format(self.conf.getIoPinsCounts(net)) pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) - if pinPos.getY() > self.state.yMax or pinPos.getY() < self.state.yMin: + if pinPos.getY() > self.conf.yMax or pinPos.getY() < self.conf.yMin: print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside east or west abutment box side.' \ .format(pinName) , '(y:{}, yAB: [{}:{}])' \ .format( DbU.getValueString(pinPos.getY()) - , DbU.getValueString(self.state.yMin) - , DbU.getValueString(self.state.yMax)) ] )) + , DbU.getValueString(self.conf.yMin) + , DbU.getValueString(self.conf.yMax)) ] )) status += 1 trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) pin = Pin.create( net @@ -247,7 +248,7 @@ class Side ( object ): ) NetExternalComponents.setExternal( pin ) self.append( pin ) - self.state.incIoPinsCounts( net ) + self.conf.incIoPinsCounts( net ) if upos: upos += ioPin.ustep return status @@ -257,7 +258,7 @@ class Side ( object ): of the abutment box. THey will stick out for one pitch. """ if not self.expandPins: return - rg = self.state.gaugeConf.routingGauge + rg = self.conf.routingGauge for pinsAtPos in self.pins.values(): for pin in pinsAtPos: for lg in rg.getLayerGauges(): @@ -285,7 +286,7 @@ class Side ( object ): for pin in self.pins[upos][1:]: pinNames += ', ' + pin.getName() print( ErrorMessage( 1, [ 'Side.checkOverlap(): On {} side of block "{}", {} pins ovelaps.' \ - .format(sideName,self.state.cell.getName(),count) + .format(sideName,self.conf.cell.getName(),count) , '(@{}: {})' \ .format(DbU.getValueString(upos),pinNames) ] ) ) @@ -308,34 +309,31 @@ class Block ( object ): if Block.LUT.has_key(cell): return Block.LUT[cell] return None - @staticmethod - def create ( cell, ioPins=[], ioPads=[] ): - """Create a Block and it's configuration object.""" - block = Block( BlockState( cell, ioPins, ioPads ) ) - Block.LUT[ cell ] = block - return block - - def __init__ ( self, state ): - """Not to be used directly, please see Block.create().""" + def __init__ ( self, conf ): + """ + Create a Block object. The only parameter ``conf`` must be a BlockConf + object which contains the complete block configuration. + """ self.flags = 0 - self.state = state + self.conf = conf self.spares = Spares( self ) self.clockTrees = [] self.hfnTrees = [] self.blockInstances = [] - self.sides = { IoPin.WEST : Side( self.state, IoPin.WEST ) - , IoPin.EAST : Side( self.state, IoPin.EAST ) - , IoPin.SOUTH : Side( self.state, IoPin.SOUTH ) - , IoPin.NORTH : Side( self.state, IoPin.NORTH ) + self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST ) + , IoPin.EAST : Side( self.conf, IoPin.EAST ) + , IoPin.SOUTH : Side( self.conf, IoPin.SOUTH ) + , IoPin.NORTH : Side( self.conf, IoPin.NORTH ) } - if not self.state.cell.getAbutmentBox().isEmpty(): + if not self.conf.cell.getAbutmentBox().isEmpty(): print( ' o Block "{}" is already done, reusing layout.' \ - .format(self.state.cell.getName()) ) - self.state.cell.setTerminalNetlist( True ) - self.state.isBuilt = True + .format(self.conf.cell.getName()) ) + self.conf.cell.setTerminalNetlist( True ) + self.conf.isBuilt = True else: print( ' o Block "{}" will be generated.' \ - .format(self.state.cell.getName()) ) + .format(self.conf.cell.getName()) ) + Block.LUT[ self.conf.cell ] = self def setUnexpandPins ( self, sides ): """ @@ -359,48 +357,57 @@ class Block ( object ): various configuration parameters (aspect ratio, space margin, fixed height or width, ...). """ - if not self.state.cell.getAbutmentBox().isEmpty(): + trace( 550, '\tBlockConf.setupAb() {}\n'.format(self.conf.cell) ) + if not self.conf.cell.getAbutmentBox().isEmpty(): pass + elif not self.conf.coreAb.isEmpty(): + self.conf.core.setAbutmentBox( self.conf.coreAb ) elif len(self.blockInstances): with UpdateSession(): - ab = Box( 0, 0, self.state.fixedWidth, self.state.fixedHeight ) - self.state.cell.setAbutmentBox( ab ) - for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences(): + ab = Box( 0, 0, self.conf.fixedWidth, self.conf.fixedHeight ) + self.conf.cell.setAbutmentBox( ab ) + for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences(): instance = occurrence.getEntity() subCell = instance.getMasterCell() subCell.setAbutmentBox( ab ) - for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences(): + for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences(): instance = occurrence.getEntity() instance.setTransformation( Transformation() ) for blockInstance in self.blockInstances: blockInstance.place() else: - sysSpaceMargin = self.state.cfg.etesian.spaceMargin + sysSpaceMargin = self.conf.cfg.etesian.spaceMargin blockSpaceMargin = sysSpaceMargin + self.spares.getSpareSpaceMargin() - self.state.cfg.etesian.spaceMargin = blockSpaceMargin - self.state.cfg.apply() + self.conf.cfg.etesian.spaceMargin = blockSpaceMargin + self.conf.cfg.apply() with UpdateSession(): - etesian = Etesian.EtesianEngine.create( self.state.cell ) - if self.state.fixedWidth: etesian.setFixedAbWidth ( self.state.fixedWidth ) - if self.state.fixedHeight: etesian.setFixedAbHeight( self.state.fixedHeight ) + etesian = Etesian.EtesianEngine.create( self.conf.cell ) + if self.conf.fixedWidth: etesian.setFixedAbWidth ( self.conf.fixedWidth ) + if self.conf.fixedHeight: etesian.setFixedAbHeight( self.conf.fixedHeight ) etesian.setDefaultAb() etesian.destroy() - self.state.cfg.etesian.spaceMargin = sysSpaceMargin - self.state.cfg.apply() + self.conf.cfg.etesian.spaceMargin = sysSpaceMargin + self.conf.cfg.apply() + ab = self.conf.cell.getAbutmentBox() + self.conf.coreSize = (ab.getWidth(), ab.getHeight()) + trace( 550, '\tSetting core ab from Cell:{}\n'.format(self.conf.coreAb) ) for side in self.sides.values(): side.setupAb() + trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) ) + if self.conf.isCoreBlock: + self.conf.setupICore() def addClockTrees ( self ): """Create the trunk of all the clock trees (recursive H-Tree).""" print( ' o Building clock tree(s).' ) af = CRL.AllianceFramework.get() clockNets = [] - for net in self.state.cell.getNets(): + for net in self.conf.cell.getNets(): if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net) if net.isClock(): trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) ) clockNets.append( net ) if not clockNets: - raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.state.cell.getName()) ) + raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.conf.cell.getName()) ) with UpdateSession(): for clockNet in clockNets: print( ' - "{}".'.format(clockNet.getName()) ) @@ -421,12 +428,12 @@ class Block ( object ): """Create the trunk of all the high fanout nets.""" print( ' o Building high fanout nets trees.' ) if self.spares: - maxSinks = timing.tech.getSinksEstimate( self.state.bufferConf.name ) + maxSinks = timing.tech.getSinksEstimate( self.conf.bufferConf.name ) dots( 82 - , ' - Max sinks for buffer "{}"'.format(self.state.bufferConf.name) + , ' - Max sinks for buffer "{}"'.format(self.conf.bufferConf.name) , ' {}'.format(maxSinks) ) nets = [] - for net in self.state.cell.getNets(): + for net in self.conf.cell.getNets(): sinksCount = 0 for rp in net.getRoutingPads(): sinksCount += 1 if sinksCount > maxSinks: @@ -459,7 +466,7 @@ class Block ( object ): """ faileds = 0 with UpdateSession(): - for ioPin in self.state.ioPins: + for ioPin in self.conf.ioPins: if ioPin.flags & IoPin.SOUTH: side = self.sides[IoPin.SOUTH] elif ioPin.flags & IoPin.NORTH: side = self.sides[IoPin.NORTH] elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ] @@ -467,7 +474,7 @@ class Block ( object ): faileds += side.place( ioPin ) if faileds: raise ErrorMessage( 3, 'Block.placeIoPins(): Cell "{}" has {} badly placed pins.' \ - .format(self.state.cell.getName(),faileds) ) + .format(self.conf.cell.getName(),faileds) ) def checkIoPins ( self ): """ @@ -475,7 +482,7 @@ class Block ( object ): """ for side in self.sides.values(): side.checkOverlaps() - for net in self.state.cell.getNets(): + for net in self.conf.cell.getNets(): if not net.isExternal(): continue if net.isSupply(): continue hasPins = False @@ -496,12 +503,17 @@ class Block ( object ): side.expand() def place ( self ): - etesian = Etesian.EtesianEngine.create( self.state.cell ) + if self.conf.isCoreBlock: + etesian = Etesian.EtesianEngine.create( self.conf.corona ) + etesian.setBlock( self.conf.icore ) + else: + etesian = Etesian.EtesianEngine.create( self.conf.cell ) etesian.place() etesian.destroy() def route ( self ): - katana = Katana.KatanaEngine.create( self.state.cell ) + routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell + katana = Katana.KatanaEngine.create( routedCell ) #katana.printConfiguration () katana.digitalInit () #katana.runNegociatePreRouted() @@ -519,9 +531,9 @@ class Block ( object ): def addBlockages ( self ): with UpdateSession(): - net = self.state.cell.getNet( 'blockagenet' ) - ab = self.state.cell.getAbutmentBox() - rg = self.state.gaugeConf.routingGauge + net = self.conf.cell.getNet( 'blockagenet' ) + ab = self.conf.cell.getAbutmentBox() + rg = self.conf.routingGauge for lg in rg.getLayerGauges(): if lg.getType() == RoutingLayerGauge.PinOnly: continue blockage = lg.getBlockageLayer() @@ -545,44 +557,46 @@ class Block ( object ): , ab.getYMax() - dyBorder ) - def build ( self ): + def doPnR ( self ): """ Perform all the steps required to build the layout of the block. The first step is to build all the blockInstance it depends upon, so they will appear as ``NetListTerminal`` and we can place them in their parent cell. """ - editor = self.state.editor - print( ' o Builing block "{}".'.format(self.state.cell.getName()) ) + editor = self.conf.editor + print( ' o Builing block "{}".'.format(self.conf.cell.getName()) ) for blockInstance in self.blockInstances: - blockInstance.block.state.editor = editor - if not blockInstance.block.state.isBuilt: + blockInstance.block.conf.editor = editor + if not blockInstance.block.conf.isBuilt: print( ' - Build sub-block "{}".' \ - .format(blockInstance.block.state.cell.getName()) ) + .format(blockInstance.block.conf.cell.getName()) ) blockInstance.block.build() - if editor: editor.setCell( self.state.cell ) - self.state.cfg.apply() + if editor: editor.setCell( self.conf.cell ) + self.conf.cfg.apply() iteration = -1 while True: iteration += 1 if iteration > 0: break self.setupAb() - self.placeIoPins() - self.checkIoPins() + if not self.conf.isCoreBlock: + self.placeIoPins() + self.checkIoPins() self.spares.build() - if self.state.useClockTree: self.addClockTrees() + if self.conf.useClockTree: self.addClockTrees() self.addHfnBuffers() if editor: editor.fit() #Breakpoint.stop( 0, 'Clock tree(s) done.' ) self.place() self.findHfnTrees() break - if self.state.useClockTree: self.splitClocks() + if self.conf.useClockTree: self.splitClocks() + if self.conf.isCoreBlock: self.doConnectCore() status = self.route() - self.addBlockages() - self.expandIoPins() - self.state.isBuilt = True - plugins.rsave.rsave( self.state.cell ) + if not self.conf.isCoreBlock: + self.addBlockages() + self.expandIoPins() + self.conf.isBuilt = True return status def useBlockInstance ( self, instancePathName , transf ): @@ -602,7 +616,7 @@ class Block ( object ): iNames = instancePathName.split('.') path = Path() for iName in iNames: - if path.isEmpty(): parentCell = self.state.cell + if path.isEmpty(): parentCell = self.conf.cell else: parentCell = path.getTailInstance().getMasterCell() instance = parentCell.getInstance( iName ) if not instance: @@ -620,6 +634,11 @@ class Block ( object ): return blockIns = BlockInstance( tailInstance, transf ) self.blockInstances.append( blockIns ) + + def save ( self ): + if not self.conf.validated: + raise ErrorMessage( 1, 'block.save(): Chip is not valid, aborting.' ) + self.spares.save() # ---------------------------------------------------------------------------- diff --git a/cumulus/src/plugins/alpha/block/clocktree.py b/cumulus/src/plugins/alpha/block/clocktree.py index af256cf7..b18757c6 100644 --- a/cumulus/src/plugins/alpha/block/clocktree.py +++ b/cumulus/src/plugins/alpha/block/clocktree.py @@ -42,7 +42,7 @@ from helpers.io import WarningMessage from helpers.io import catch from helpers.overlay import UpdateSession from plugins import getParameter -from plugins import utils +from plugins.alpha import utils from plugins.alpha.block.configuration import GaugeConf from plugins.alpha.block.spares import Spares @@ -97,11 +97,10 @@ class ClockTree ( object ): trace( 550, '-' ) return False - gaugeConf = self.spares.state.gaugeConf - bufferConf = self.spares.state.bufferConf + gaugeConf = self.spares.conf + bufferConf = self.spares.conf.bufferConf ckNet = qt.bOutputPlug.getNet() self.subNets.append( ckNet ) - leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 ) rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 ) blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet ) @@ -110,7 +109,6 @@ class ClockTree ( object ): trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet ) leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 ) rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 ) - leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 ) leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 ) rightSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightSourceContact.getX(), 0 ) @@ -119,26 +117,22 @@ class ClockTree ( object ): rightX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightContact.getX(), 0 ) tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 ) blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 ) - gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY ) gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY ) gaugeConf.setStackPosition( tlContact, leftX, tlY ) gaugeConf.setStackPosition( blContact, leftX, blY ) gaugeConf.setStackPosition( trContact, rightX, tlY ) gaugeConf.setStackPosition( brContact, rightX, blY ) - leftContact .setX( leftX ) leftContact .setY( leftSourceY ) rightContact.setX( rightX ) rightContact.setY( rightSourceY ) - gaugeConf.createHorizontal( leftContact , leftSourceContact, leftSourceY , 0 ) gaugeConf.createHorizontal( rightSourceContact, rightContact , rightSourceY, 0 ) gaugeConf.createVertical ( leftContact , blContact , leftX , 0 ) gaugeConf.createVertical ( tlContact , leftContact , leftX , 0 ) gaugeConf.createVertical ( rightContact , brContact , rightX , 0 ) gaugeConf.createVertical ( trContact , rightContact , rightX , 0 ) - if qt.isRoot(): ckNet = self.clockNet trace( 550, '\tRemoving any previous pin...\n' ) @@ -147,24 +141,23 @@ class ClockTree ( object ): for pin in pins: print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) ) pin.destroy() - - layerGauge = gaugeConf.vRoutingGauge - rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 ) - x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 ) - y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 ) - rootPin = Pin.create( ckNet - , ckNet.getName()+'.0' - , Pin.Direction.NORTH - , Pin.PlacementStatus.FIXED - , layerGauge.getLayer() - , x - , qt.area.getYMax() - , layerGauge.getViaWidth() - , layerGauge.getViaWidth() - ) - gaugeConf.setStackPosition( rootContact, x, y ) - gaugeConf.createVertical( rootContact, rootPin, x, 0 ) - + if not self.spares.conf.isCoreBlock: + layerGauge = gaugeConf.vRoutingGauge + rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 ) + x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 ) + y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 ) + rootPin = Pin.create( ckNet + , ckNet.getName()+'.0' + , Pin.Direction.NORTH + , Pin.PlacementStatus.FIXED + , layerGauge.getLayer() + , x + , qt.area.getYMax() + , layerGauge.getViaWidth() + , layerGauge.getViaWidth() + ) + gaugeConf.setStackPosition( rootContact, x, y ) + gaugeConf.createVertical( rootContact, rootPin, x, 0 ) for leaf in qt.leafs: self._rrouteHTree( leaf ) trace( 550, '-' ) @@ -189,6 +182,7 @@ class ClockTree ( object ): Disconnect the registers from the main clock and reconnect them to the leaf buffers of the clock tree. """ + bufferConf = self.spares.conf.bufferConf quadTree = self.spares.quadTree quadTree.bufferTag = self.clockNet.getName() quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 ) @@ -197,3 +191,10 @@ class ClockTree ( object ): for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences(): quadTree.attachToLeaf( plugOccurrence ) quadTree.rsplitNetlist() + if self.spares.conf.isCoreBlock: + plug = utils.getPlugByName( quadTree.buffer, bufferConf.input ) + plug.setNet( self.clockNet ) + trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) ) + trace( 550, '\tPlug of "{}"\n'.format(self.clockNet.getName()) ) + for plug in self.clockNet.getPlugs(): + trace( 550, '\t| {}\n'.format(plug) ) diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index e006852b..b39836d5 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -12,6 +12,7 @@ # | Python : "./plugins/block/configuration.py" | # +-----------------------------------------------------------------+ +from __future__ import print_function import sys import re import os.path @@ -36,6 +37,7 @@ from Hurricane import Instance import CRL from CRL import RoutingLayerGauge from helpers import trace, l, u, n +from helpers.utils import classdecorator from helpers.io import ErrorMessage from helpers.io import WarningMessage from helpers.io import catch @@ -128,8 +130,8 @@ class GaugeConf ( object ): self.topLayerDepth = layerGauge.getDepth() break if not self.topLayerDepth: - print WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \ - .format(self._routingGauge.getDepth()) ) + print( WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \ + .format(self._routingGauge.getDepth()) )) self._topLayerDepth = self._routingGauge.getDepth() - 1 self.horizontalDepth = -1 @@ -157,10 +159,11 @@ class GaugeConf ( object ): return def _loadIoPadGauge ( self, ioPadGaugeName ): + trace( 550, ',+', '\tGaugeConf._loadIoPadGauge(): "{}".\n'.format(ioPadGaugeName) ) self._ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName ) if not self._ioPadGauge: - print WarningMessage( 'IO pad gauge "%s" not found.' % ioPadGaugeName ) - return + print( WarningMessage( 'IO pad gauge "{}" not found.'.format(ioPadGaugeName) )) + trace( 550, '-' ) def isHorizontal ( self, layer ): mask = layer.getMask() @@ -169,8 +172,8 @@ class GaugeConf ( object ): if lg.getDirection() == RoutingLayerGauge.Horizontal: return True return False - print ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "%s" is not part of gauge "%s", cannot know preferred direction.' \ - % (layer.getName(), self._routingGauge.getName()) ) + print( ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "{}" is not part of gauge "{}", cannot know preferred direction.' \ + .format(layer.getName(), self._routingGauge.getName()) )) return False def isVertical ( self, layer ): return not self.isHorizontal( layer ) @@ -310,7 +313,7 @@ class GaugeConf ( object ): trace( 550, '-' ) return contact1 - + def rpByOccurrence ( self, occurrence, net ): plug = occurrence.getEntity() if self._plugToRp.has_key(plug): @@ -327,7 +330,7 @@ class GaugeConf ( object ): else: rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea ) self._plugToRp[plug] = rp - return self.rpAccess( self._rpByOccurrence(occurrence,net), flags ) + return self.rpAccess( self.rpByOccurrence(occurrence,net), flags ) def rpByPlug ( self, plug, net ): if self._plugToRp.has_key(plug): @@ -356,7 +359,7 @@ class GaugeConf ( object ): segment = component count += 1 if count > 1: - message = [ 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count) + message = [ 'GaugeConf::setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count) , '+ {}'.format(topContact) ] for component in topContact.getSlaveComponents(): message.append( '| {}'.format(component) ) @@ -434,8 +437,8 @@ class IoPadConf ( object ): self.flags = 0 self.index = None self._datas = list( datas ) - while len(self._datas) < 7: - self._datas.append( None ) + if len(self._datas) == 5: self._datas += [ None, None ] + elif len(self._datas) == 6: self._datas.insert( 5, None ) self._datas.append( [] ) reSpecialPads = re.compile( r'^(?P.+)_(?P[\d+])$' ) m = reSpecialPads.match( self.instanceName ) @@ -447,6 +450,7 @@ class IoPadConf ( object ): else: if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE + trace( 550, '\tIoPadConf._datas: {}\n'.format(self._datas) ) @property def side ( self ): return self._datas[0] @@ -482,7 +486,7 @@ class IoPadConf ( object ): def coreClockNetName ( self ): return self._datas[5] @property - def nets ( self ): return self._datas[4:6] + def nets ( self ): return self._datas[4:7] @property def pads ( self ): return self._datas[7] @@ -494,9 +498,11 @@ class IoPadConf ( object ): def isBidir ( self ): return self.flags & IoPadConf.BIDIR def __repr__ ( self ): - s = ' block.state.xMax or pinPos.getX() < block.state.xMin: +# if pinPos.getX() > block.conf.xMax or pinPos.getX() < block.conf.xMin: # print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside north or south abutment box side.'.format(pinName) -# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.state.xMax)) ] )) +# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.conf.xMax)) ] )) # status += 1 # trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) # pin = Pin.create( net @@ -692,21 +704,21 @@ class IoPin ( object ): # ) # NetExternalComponents.setExternal( pin ) # side.append( self.flags, pin ) -# block.state.incIoPinsCounts( net ) +# block.conf.incIoPinsCounts( net ) # if self.upos: self.upos + self.ustep # else: -# gauge = block.state.gaugeConf.hDeepRG +# gauge = block.conf.gaugeConf.hDeepRG # for index in indexes: # pinName = self.stem.format(index) -# net = block.state.cell.getNet( pinName ) +# net = block.conf.cell.getNet( pinName ) # if net is None: # print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] )) # continue -# pinName += '.{}'.format(block.state.getIoPinsCounts(net)) +# pinName += '.{}'.format(block.conf.getIoPinsCounts(net)) # pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep ) -# if pinPos.getY() > block.state.yMax or pinPos.getY() < block.state.yMin: +# if pinPos.getY() > block.conf.yMax or pinPos.getY() < block.conf.yMin: # print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside east or west abutment box side.'.format(pinName) -# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.state.yMax)) ] )) +# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.conf.yMax)) ] )) # status += 1 # trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) # pin = Pin.create( net @@ -721,18 +733,18 @@ class IoPin ( object ): # ) # NetExternalComponents.setExternal( pin ) # side.append( self.flags, pin ) -# block.state.incIoPinsCounts( net ) +# block.conf.incIoPinsCounts( net ) # if self.upos: self.upos + self.ustep # return status # ---------------------------------------------------------------------------- -# Class : "configuration.BlockState". +# Class : "configuration.BlockConf". -class BlockState ( object ): +class BlockConf ( GaugeConf ): """ - BlockState centralize all the configurations informations related to a - given block. + BlockConf centralize all the configurations informations related to a + given block. It must be derived/build upon a GaugeConf class. It contains: @@ -748,15 +760,19 @@ class BlockState ( object ): """ def __init__ ( self, cell, ioPins=[], ioPads=[] ): + super(BlockConf,self).__init__() + self.validated = True self.editor = None self.framework = CRL.AllianceFramework.get() self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive) - self.gaugeConf = GaugeConf() self.bufferConf = BufferInterface( self.framework ) - self.chip = ChipConf() + self.chipConf = ChipConf( self ) self.bColumns = 2 self.bRows = 2 self.cell = cell + self.icore = None + self.icorona = None + self.chip = None self.fixedWidth = None self.fixedHeight = None self.deltaAb = [ 0, 0, 0, 0 ] @@ -768,12 +784,14 @@ class BlockState ( object ): for ioPinSpec in ioPins: self.ioPins.append( IoPin( *ioPinSpec ) ) for line in range(len(ioPads)): - self.chip.addIoPad( ioPads[line], line ) - + self.chipConf.addIoPad( ioPads[line], line ) self.cfg.etesian.aspectRatio = None self.cfg.etesian.spaceMargin = None self.cfg.block.spareSide = None + @property + def isCoreBlock ( self ): return self.chip is not None + @property def bufferWidth ( self ): return self.bufferConf.width @@ -792,8 +810,38 @@ class BlockState ( object ): @property def yMax ( self ): return self.cell.getAbutmentBox().getYMax() + @property + def coreAb ( self ): + if not hasattr(self,'coreSize'): return Box() + trace( 550, '\tcoreAb:[{} {}]\n'.format( DbU.getValueString(self.coreSize[0]) + , DbU.getValueString(self.coreSize[1]) )) + return Box( 0, 0, self.coreSize[0], self.coreSize[1] ) + + @property + def coronaAb ( self ): + if self.corona is None: return Box() + return self.corona.getAbutmentBox() + + @property + def chipAb ( self ): + if not hasattr(self,'chipSize'): return Box() + return Box( 0, 0, self.chipSize[0], self.chipSize[1] ) + + @property + def corona ( self ): return self.icorona.getMasterCell() + + @property + def core ( self ): return self.cell + def setEditor ( self, editor ): self.editor = editor + def refresh ( self, cell=None ): + if not self.editor: return + if cell is not None: + if cell != self.editor.getCell(): + self.editor.setCell( cell ) + self.editor.fit() + def createBuffer ( self ): return self.bufferConf.createBuffer( self.cell ) diff --git a/cumulus/src/plugins/alpha/block/hfns1.py b/cumulus/src/plugins/alpha/block/hfns1.py index 98736bb0..b0618ad0 100644 --- a/cumulus/src/plugins/alpha/block/hfns1.py +++ b/cumulus/src/plugins/alpha/block/hfns1.py @@ -78,7 +78,7 @@ class SlicedArea ( object ): but closest to the parent's center area (so, ideally, on the cluster's edge). """ - state = cluster.bufferTree.spares.state + state = cluster.bufferTree.spares.conf self.cluster = cluster self.rows = {} self.iposition = None @@ -96,20 +96,20 @@ class SlicedArea ( object ): @property def bInputPlug ( self ): """The input Plug of the buffer.""" - return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input ) + return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input ) @property def bOutputPlug ( self ): """The output Plug of the buffer.""" - return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output ) + return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output ) def buildSlicesUnder ( self ): """ UNUSED. Kept as reference example. Rebuild slices structure under a specific area (must be small). """ - state = self.cluster.bufferTree.spares.state - sliceHeight = state.gaugeConf.sliceHeight + state = self.cluster.bufferTree.spares.conf + sliceHeight = state.sliceHeight cell = state.cell cellAb = cell.getAbutmentBox() insertArea = Box( self.cluster.getCenter() ) @@ -141,7 +141,7 @@ class SlicedArea ( object ): """ global af catalog = af.getCatalog() - bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width + bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width for key in self.rows.keys(): row = self.rows[ key ] trace( 550, '\t+ Row:\n' ) @@ -189,9 +189,9 @@ class SlicedArea ( object ): """ if self.iposition is None: raise ErrorMessage( 2, 'SlicedArea.insertBuffer(): No position defined to wedge the buffer.' ) - state = self.cluster.bufferTree.spares.state + state = self.cluster.bufferTree.spares.conf catalog = af.getCatalog() - bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width + bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width tieLength = 0 transf = None if self.iposition[2] & SlicedArea.REPLACE: @@ -460,7 +460,7 @@ class Cluster ( object ): def show ( self ): """Select the RoutingPad of the cluster in the editor.""" - editor = self.bufferTree.spares.state.editor + editor = self.bufferTree.spares.conf.editor if not editor: return False editor.unselectAll() editor.setCumulativeSelection( True ) @@ -531,7 +531,7 @@ class BufferTree ( object ): self.isDeepNet = True self.clusterDepth = 0 self.clusters = [ [] ] - self.bufName = self.spares.state.bufferConf.name + self.bufName = self.spares.conf.bufferConf.name self.netCount = 0 self.netName = self.net.getName() self.netIndex = None @@ -570,7 +570,7 @@ class BufferTree ( object ): subNetName = '{}_hfns_{}'.format( self.netName, self.netCount ) else: subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount ) - net = Net.create( self.spares.state.cell, subNetName ) + net = Net.create( self.spares.conf.cell, subNetName ) self.netCount += 1 return net @@ -689,7 +689,7 @@ class BufferTree ( object ): self.clusters[-1].append( Cluster(self,cluster,self.clusterDepth+1) ) #if cluster.show(): # Breakpoint.stop( 0, 'Showing cluster of {} RoutingPads'.format(cluster.size) ) - editor = self.spares.state.editor + editor = self.spares.conf.editor if editor: editor.unselectAll() editor.setCumulativeSelection( False ) @@ -723,7 +723,7 @@ class BufferTree ( object ): driverRpOcc = self.rpDriver.getPlugOccurrence() topNetName = self.net.getName() self.net.destroy() - self.net = Net.create( self.spares.state.cell, topNetName ) + self.net = Net.create( self.spares.conf.cell, topNetName ) deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() ) deepDriverNet = deepPlug.getMasterNet() driverRpOcc.getEntity().setNet( deepDriverNet ) diff --git a/cumulus/src/plugins/alpha/block/hfns2.py b/cumulus/src/plugins/alpha/block/hfns2.py index 139ce288..97db35d3 100644 --- a/cumulus/src/plugins/alpha/block/hfns2.py +++ b/cumulus/src/plugins/alpha/block/hfns2.py @@ -89,12 +89,12 @@ class Cluster ( object ): @property def bInputPlug ( self ): """The input Plug of the buffer.""" - return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.input ) + return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.input ) @property def bOutputPlug ( self ): """The output Plug of the buffer.""" - return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.output ) + return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.output ) def createBufInputRp ( self, net ): """Create a RoutingPad for the buffer input Plug (terminal).""" @@ -194,7 +194,7 @@ class BufferTree ( object ): subNetName = '{}_hfns_{}'.format( self.netName, self.netCount ) else: subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount ) - net = Net.create( self.spares.state.cell, subNetName ) + net = Net.create( self.spares.conf.cell, subNetName ) self.netCount += 1 return net @@ -254,7 +254,7 @@ class BufferTree ( object ): driverRpOcc = self.rpDriver.getPlugOccurrence() topNetName = self.net.getName() self.net.destroy() - self.net = Net.create( self.spares.state.cell, topNetName ) + self.net = Net.create( self.spares.conf.cell, topNetName ) deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() ) deepDriverNet = deepPlug.getMasterNet() driverRpOcc.getEntity().setNet( deepDriverNet ) diff --git a/cumulus/src/plugins/alpha/block/hfns3.py b/cumulus/src/plugins/alpha/block/hfns3.py index 66f25643..10ba4a06 100644 --- a/cumulus/src/plugins/alpha/block/hfns3.py +++ b/cumulus/src/plugins/alpha/block/hfns3.py @@ -77,7 +77,7 @@ class SlicedArea ( object ): but closest to the parent's center area (so, ideally, on the cluster's edge). """ - state = cluster.bufferTree.spares.state + state = cluster.bufferTree.spares.conf self.cluster = cluster if cluster.parent is None: attractor = cluster.getCenter() @@ -93,12 +93,12 @@ class SlicedArea ( object ): @property def bInputPlug ( self ): """The input Plug of the buffer.""" - return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input ) + return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input ) @property def bOutputPlug ( self ): """The output Plug of the buffer.""" - return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output ) + return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output ) # ---------------------------------------------------------------------------- @@ -328,21 +328,21 @@ class Cluster ( object ): graph.addNode( self , driverCenter.getX() , self.bufferTree.spares.toYGCellGrid(driverCenter.getY()) - + self.bufferTree.spares.state.gaugeConf.sliceHeight / 2 + + self.bufferTree.spares.conf.sliceHeight / 2 , rsmt.Node.Driver ) for anchor in self.mergedAnchors: sinkCenter = anchor.bInputRp.getPosition() graph.addNode( anchor , sinkCenter.getX() , self.bufferTree.spares.toYGCellGrid(sinkCenter.getY()) - + self.bufferTree.spares.state.gaugeConf.sliceHeight / 2 ) + + self.bufferTree.spares.conf.sliceHeight / 2 ) #graph.doIteratedOneSteiner() graph.doFlute() graph.createGRSegments() def show ( self ): """Select the RoutingPad of the cluster in the editor.""" - editor = self.bufferTree.spares.state.editor + editor = self.bufferTree.spares.conf.editor if not editor: return False editor.unselectAll() editor.setCumulativeSelection( True ) @@ -421,7 +421,7 @@ class BufferTree ( object ): self.isDeepNet = True self.clusterDepth = 0 self.clusters = [ [] ] - self.bufName = self.spares.state.bufferConf.name + self.bufName = self.spares.conf.bufferConf.name self.netCount = 0 self.netName = self.net.getName() self.netIndex = None @@ -460,7 +460,7 @@ class BufferTree ( object ): subNetName = '{}_hfns_{}'.format( self.netName, self.netCount ) else: subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount ) - net = Net.create( self.spares.state.cell, subNetName ) + net = Net.create( self.spares.conf.cell, subNetName ) self.netCount += 1 return net @@ -604,7 +604,7 @@ class BufferTree ( object ): driverRpOcc = self.rpDriver.getPlugOccurrence() topNetName = self.net.getName() self.net.destroy() - self.net = Net.create( self.spares.state.cell, topNetName ) + self.net = Net.create( self.spares.conf.cell, topNetName ) deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() ) deepDriverNet = deepPlug.getMasterNet() driverRpOcc.getEntity().setNet( deepDriverNet ) diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index 96fe9b41..75f0d451 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -59,8 +59,8 @@ class BufferPool ( object ): def __init__ ( self, quadTree ): self.quadTree = quadTree - self.columns = quadTree.spares.state.bColumns - self.rows = quadTree.spares.state.bRows + self.columns = quadTree.spares.conf.bColumns + self.rows = quadTree.spares.conf.bRows self.area = Box() self.buffers = [] self.selectedIndex = None @@ -145,12 +145,12 @@ class BufferPool ( object ): """Create the matrix of instances buffer.""" trace( 540, ',+', '\tBufferPool.createBuffers()\n' ) - state = self.quadTree.spares.state - sliceHeight = state.gaugeConf.sliceHeight + conf = self.quadTree.spares.conf + sliceHeight = conf.sliceHeight x = self.quadTree.onXPitch( self.quadTree.area.getXCenter() - - (state.bufferConf.width * self.columns)/2 ) + - (conf.bufferConf.width * self.columns)/2 ) y = self.quadTree.onYSlice( self.quadTree.area.getYCenter() - - (state.bufferConf.height * self.rows)/2 ) + - (conf.bufferConf.height * self.rows)/2 ) slice = y / sliceHeight trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) ) @@ -163,8 +163,8 @@ class BufferPool ( object ): y += sliceHeight for column in range(self.columns): index = self.toIndex(column,row) - transf = Transformation( x + column*state.bufferConf.width, y, orientation ) - instance = state.createBuffer() + transf = Transformation( x + column*conf.bufferConf.width, y, orientation ) + instance = conf.createBuffer() instance.setTransformation( transf ) instance.setPlacementStatus( Instance.PlacementStatus.FIXED ) self.buffers[ index ][1] = instance @@ -213,7 +213,7 @@ class QuadTree ( object ): @staticmethod def create ( spares ): - root = QuadTree( spares, None, spares.state.cell.getAbutmentBox() ) + root = QuadTree( spares, None, spares.conf.cell.getAbutmentBox() ) root.rpartition() return root @@ -277,7 +277,7 @@ class QuadTree ( object ): catalog = framework.getCatalog() instancesNb = 0 bufNb = 0 - for occurrence in self.spares.state.cell.getTerminalNetlistInstanceOccurrences(): + for occurrence in self.spares.conf.cell.getTerminalNetlistInstanceOccurrences(): cellName = occurrence.getEntity().getMasterCell().getName() cstate = catalog.getState( cellName ) if cstate and cstate.isFeed(): continue @@ -291,10 +291,10 @@ class QuadTree ( object ): if rtotal: print( ' o Detailed use of spare buffers.' ) dots( 82 - , ' - Useds: ' + , ' - Useds ' , ' {}/{} ({:.1%})'.format(rused,rtotal,float(rused)/float(rtotal)) ) dots( 82 - , ' - Buffer ratio: ' + , ' - Buffer ratio ' , ' {}/{} ({:.1%})'.format( rtotal , instancesNb+bufNb , float(rtotal)/float(instancesNb+bufNb)) ) @@ -347,21 +347,21 @@ class QuadTree ( object ): @property def bInputPlug ( self ): """The input Plug of the currently selected buffer in the pool.""" - return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.input ) + return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.input ) @property def bOutputPlug ( self ): """The output Plug of the currently selected buffer in the pool.""" - return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.output ) + return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.output ) def onYSlice ( self, y ): """Returns the coordinate of the slice immediately inferior to Y.""" - modulo = (y - self.area.getYMin()) % self.spares.state.gaugeConf.sliceHeight + modulo = (y - self.area.getYMin()) % self.spares.conf.sliceHeight return y - modulo def onXPitch ( self, x ): """Returns the coordinate of the pitch immediately inferior to X.""" - modulo = (x - self.area.getXMin()) % self.spares.state.gaugeConf.sliceStep + modulo = (x - self.area.getXMin()) % self.spares.conf.sliceStep return x - modulo def selectFree ( self ): @@ -382,7 +382,7 @@ class QuadTree ( object ): trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) ) plug = self.bOutputPlug if not plug.getNet(): - outputNetBuff = Net.create( self.spares.state.cell,'{}_{}' \ + outputNetBuff = Net.create( self.spares.conf.cell,'{}_{}' \ .format(self.root.bufferTag,self.rtag) ) plug.setNet( outputNetBuff ) trace( 540, '\t| {}\n'.format(plug) ) @@ -417,10 +417,10 @@ class QuadTree ( object ): quad-tree, but only a vertical or horizontal bi-partition. """ trace( 540, ',+', '\tQuadTree.partition(): {} (spareSide:{})\n' \ - .format(self.area, DbU.getValueString(self.spares.state.cfg.block.spareSide)) ) + .format(self.area, DbU.getValueString(self.spares.conf.cfg.block.spareSide)) ) - spareSide = self.spares.state.cfg.block.spareSide - sliceHeight = self.spares.state.gaugeConf.sliceHeight + spareSide = self.spares.conf.cfg.block.spareSide + sliceHeight = self.spares.conf.sliceHeight side = float(spareSide) aspectRatio = float(self.area.getWidth()) / float(self.area.getHeight()) @@ -684,7 +684,7 @@ class QuadTree ( object ): trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) ) plug.getEntity().setNet( deepNetBuff ) - maxSinks = self.spares.state.bufferConf.maxSinks + maxSinks = self.spares.conf.bufferConf.maxSinks if len(self.plugs) > maxSinks: print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \ .format(maxSinks,len(self.plugs),netBuff.getName())) ) @@ -713,7 +713,7 @@ class Spares ( object ): MARK_USED = 0x00020000 def __init__ ( self, block ): - self.state = block.state + self.conf = block.conf self.quadTree = None self.cloneds = [] self.strayBuffers = [] @@ -725,36 +725,36 @@ class Spares ( object ): self.quadTree = None self.cloneds = [] self.strayBuffers = [] - self.state.resetBufferCount() + self.conf.resetBufferCount() def getSpareSpaceMargin ( self ): """ Compute the percentage of margin space to compensate for the spare buffers (row*columns) with a supplemental margin factor of 1.3 or 1.4. """ - if not self.state.useSpares: return 0.0 - spareSide = self.state.cfg.block.spareSide + if not self.conf.useSpares: return 0.0 + spareSide = self.conf.cfg.block.spareSide if not spareSide: raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): "block.spareSide" parameter is zero ({}).' \ .format(spareSide) ) - areaLength = spareSide * spareSide / self.state.gaugeConf.sliceHeight - bufferLength = self.state.bufferConf.width * self.state.bColumns * self.state.bRows + areaLength = spareSide * spareSide / self.conf.sliceHeight + bufferLength = self.conf.bufferConf.width * self.conf.bColumns * self.conf.bRows if not areaLength: raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' ) return (float(bufferLength) * 1.4) / float(areaLength) def toXGCellGrid ( self, x ): """Find the nearest X (inferior) on the Cell gauge grid (sliceStep).""" - dx = x - self.state.xMin - return self.state.xMin + (dx - dx % self.state.gaugeConf.sliceStep) + dx = x - self.conf.xMin + return self.conf.xMin + (dx - dx % self.conf.sliceStep) def toYGCellGrid ( self, y ): """Find the nearest Y (inferior) on the Cell gauge grid (sliceHeight).""" - dy = y - self.state.yMin - return self.state.yMin + (dy - dy % self.state.gaugeConf.sliceHeight) + dy = y - self.conf.yMin + return self.conf.yMin + (dy - dy % self.conf.sliceHeight) def build ( self ): - if not self.state.useSpares: return + if not self.conf.useSpares: return trace( 540, ',+', '\tSpares.build()\n' ) with UpdateSession(): self.quadTree = QuadTree.create( self ) @@ -768,7 +768,7 @@ class Spares ( object ): """Add a new stray buffer at ``position``.""" trace( 540, ',+', '\tSpares.addStrayBuffer()\n' ) - sliceHeight = self.state.gaugeConf.sliceHeight + sliceHeight = self.conf.sliceHeight x = self.quadTree.onXPitch( position.getX() ) y = self.quadTree.onYSlice( position.getY() ) slice = y / sliceHeight @@ -778,7 +778,7 @@ class Spares ( object ): orientation = Transformation.Orientation.MY y += sliceHeight transf = Transformation( x, y, orientation ) - instance = self.state.createBuffer() + instance = self.conf.createBuffer() instance.setTransformation( transf ) instance.setPlacementStatus( Instance.PlacementStatus.FIXED ) unoverlapDx = self.quadTree.getUnoverlapDx( instance.getAbutmentBox() ) @@ -801,7 +801,9 @@ class Spares ( object ): return leaf.selectFree() def addClonedCell ( self, masterCell ): - if not masterCell in self.cloneds: self.cloneds.append( masterCell ) + if not masterCell in self.cloneds: + trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) ) + self.cloneds.append( masterCell ) return def raddTransNet ( self, topNet, path ): @@ -839,8 +841,9 @@ class Spares ( object ): *plug master net* and the *tail path*. """ - if path.isEmpty(): return None - + if path.isEmpty(): + self.addClonedCell( topNet.getCell() ) + return None tailPath = path.getTailPath() headInstance = path.getHeadInstance() headPlug = utils.getPlugByNet(headInstance,topNet) @@ -856,9 +859,9 @@ class Spares ( object ): % (topNet.getName(),headInstance.getName(),masterCell.getName()) ) headPlug.setNet( topNet ) self.addClonedCell( masterCell ) + self.addClonedCell( headInstance.getCell() ) else: masterNet = headPlug.getMasterNet() - if tailPath.isEmpty(): return headPlug return self.raddTransNet( masterNet, tailPath ) @@ -880,13 +883,14 @@ class Spares ( object ): if not masterCell.isTerminal(): self.rsave( masterCell ) - def save ( self, topCell ): + def save ( self ): """ Frontend to Spares.rsave(). Append the "_cts" suffix to the cloned cells, then call rsave(). """ + trace( 550,'\tSpares.save() on "{}"\n'.format(self.conf.cell.getName()) ) for cell in self.cloneds: + trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) ) cell.setName( cell.getName()+'_cts' ) - self.rsave( topCell ) + self.rsave( self.conf.cell ) return - diff --git a/cumulus/src/plugins/alpha/chip/__init__.py b/cumulus/src/plugins/alpha/chip/__init__.py new file mode 100644 index 00000000..6231dda2 --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/__init__.py @@ -0,0 +1,56 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) UPMC 2014-2018, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/__init__.py" | +# +-----------------------------------------------------------------+ + +""" +Define constants to be used through all "chip" plugin modules, along +with the importConstants() function to import then directly in the +dictionnary of other modules. + +* For corona sides: North, South, East & West. +* For corona corners: SouthWest, SouthEast, NorthWest & NorthEast. +* For rounding operation: Superior, Inferior, Inwards, + OnHorizontalPitch & OnVerticalPitch. +""" + +from __future__ import print_function +from helpers.io import WarningMessage + +North = 0x0001 +South = 0x0002 +East = 0x0004 +West = 0x0008 +SouthWest = South|West +SouthEast = South|East +NorthWest = North|West +NorthEast = North|East + +Superior = 0x0010 +Inferior = 0x0020 +Inwards = 0x0040 +OnHorizontalPitch = 0x0080 +OnVerticalPitch = 0x0100 + + +def importConstants ( symbols ): + """ + Import chip module symbol constants in the another module dictionnary + (i.e. globals()). + """ + if not isinstance(symbols,dict): + print( WarningMessage( 'plugins.chip.__init__.importConstants(), argument is not a symbol table.' )) + return + for symbol in globals().items(): + if isinstance(symbol[1],int) or isinstance(symbol[1],long): + if not symbols.has_key(symbol[0]): + symbols[ symbol[0] ] = symbol[1] diff --git a/cumulus/src/plugins/alpha/chip/chip.py b/cumulus/src/plugins/alpha/chip/chip.py new file mode 100644 index 00000000..120f380d --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/chip.py @@ -0,0 +1,153 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) SU 2014-2020, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/chip.py" | +# +-----------------------------------------------------------------+ + + +from __future__ import print_function +from __future__ import absolute_import +import sys +import traceback +import os.path +import optparse +import math +import cProfile +import pstats +import Cfg +import Hurricane +from Hurricane import DataBase +from Hurricane import DbU +from Hurricane import Point +from Hurricane import Transformation +from Hurricane import Box +from Hurricane import Path +from Hurricane import Occurrence +from Hurricane import UpdateSession +from Hurricane import Breakpoint +from Hurricane import Net +from Hurricane import RoutingPad +from Hurricane import Contact +from Hurricane import Horizontal +from Hurricane import Vertical +from Hurricane import Instance +from Hurricane import HyperNet +from Hurricane import Query +import Viewer +import CRL +from CRL import RoutingLayerGauge +import helpers +from helpers import trace +from helpers.io import ErrorMessage +from helpers.io import WarningMessage +from helpers.overlay import UpdateSession +import Etesian +import Anabatic +import Katana +import Unicorn +import plugins +import plugins.rsave +from plugins.alpha.block.block import Block +import plugins.alpha.chip.pads +import plugins.alpha.chip.power +import plugins.alpha.chip.corona + + +# -------------------------------------------------------------------- +# Class : "chip.Chip" + +class Chip ( Block ): + + def __init__ ( self, conf ): + super(Chip,self).__init__( conf ) + print( 'Core: {}'.format(self.conf.core) ) + print( '| AB: {}'.format(self.conf.core.getAbutmentBox()) ) + + def validate ( self ): + self.conf.validated = True + coreAb = self.conf.core.getAbutmentBox() + if (not coreAb.isEmpty()): + if coreAb.getWidth () <= self.conf.coreAb.getWidth() \ + and coreAb.getHeight() <= self.conf.coreAb.getHeight(): + self.conf.coreSize = (coreAb.getWidth(), coreAb.getHeight()) + else: + raise ErrorMessage( 1, [ 'Core "{}" already have an abutment box, bigger than the requested one:' \ + .format(self.conf.core.getName()) + , " Cell abutment box: {}".format(coreAb) + , " Maximum abutment box: {}".format(self.conf.coreAb) ] ) + self.conf.validated = False + return self.conf.validated + + def doCoronaFloorplan ( self ): + if not self.conf.validated: + raise ErrorMessage( 1, 'chip.doCoronaFloorplan(): Chip is not valid, aborting.' ) + return + minHCorona = self.conf.minHCorona + minVCorona = self.conf.minVCorona + innerBb = Box( self.conf.coreAb ) + innerBb.inflate( minHCorona, minVCorona ) + coronaAb = self.conf.corona.getAbutmentBox() + if innerBb.getWidth() > coronaAb.getWidth(): + raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \ + .format( DbU.getValueString(innerBb .getWidth()) + , DbU.getValueString(coronaAb.getWidth()) ) ) + if innerBb.getHeight() > coronaAb.getHeight(): + raise ErrorMessage( 1, 'Core is too tall to fit into the corona, needs {} but only has {}.' \ + .format( DbU.getValueString(innerBb .getHeight()) + , DbU.getValueString(coronaAb.getHeight()) ) ) + with UpdateSession(): + self.conf.core.setAbutmentBox( self.conf.coreAb ) + x = (coronaAb.getWidth () - self.conf.coreAb.getWidth ()) / 2 + y = (coronaAb.getHeight() - self.conf.coreAb.getHeight()) / 2 + x = x - (x % self.conf.sliceHeight) + y = y - (y % self.conf.sliceHeight) + self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) ) + self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED ) + + def doConnectCore ( self ): + power = plugins.alpha.chip.power.Builder( self.conf ) + power.connectPower() + power.connectClock() + power.doLayout() + self.conf.refresh() + corona = plugins.alpha.chip.corona.Builder( power ) + corona.connectPads( self.padsCorona ) + corona.connectCore() + corona.doLayout() + self.conf.refresh() + + def doPnR ( self ): + self.conf.computeCoronaBorder() + self.conf.chipValidate() + if not self.conf.validated: + raise ErrorMessage( 1, 'chip.doChipPnR(): Chip is not valid, aborting.' ) + self.conf.chip.setAbutmentBox( self.conf.chipAb ) + trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) ) + trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) ) + self.padsCorona = plugins.alpha.chip.pads.Corona( self.conf ) + self.conf.validated = self.padsCorona.validate() + if not self.conf.validated: + return False + self.padsCorona.doLayout() + self.validate() + self.doCoronaFloorplan() + self.conf.refresh() + super(Chip,self).doPnR() + self.conf.refresh( self.conf.chip ) + return self.conf.validated + + def save ( self ): + if not self.conf.validated: + raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' ) + super(Chip,self).save() + af = CRL.AllianceFramework.get() + af.saveCell( self.conf.corona, CRL.Catalog.State.Views ) + af.saveCell( self.conf.chip , CRL.Catalog.State.Views ) diff --git a/cumulus/src/plugins/alpha/chip/configuration.py b/cumulus/src/plugins/alpha/chip/configuration.py new file mode 100644 index 00000000..43c8d0d6 --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/configuration.py @@ -0,0 +1,665 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) SU 2014-2020, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/configuration.py" | +# +-----------------------------------------------------------------+ + +from __future__ import print_function +import sys +import os.path +import Cfg +from Hurricane import Breakpoint +from Hurricane import DbU +from Hurricane import Box +from Hurricane import Transformation +from Hurricane import Box +from Hurricane import Path +from Hurricane import Layer +from Hurricane import Occurrence +from Hurricane import Net +from Hurricane import RoutingPad +from Hurricane import Horizontal +from Hurricane import Vertical +from Hurricane import Contact +from Hurricane import Pin +from Hurricane import Plug +from Hurricane import Instance +import CRL +from CRL import RoutingLayerGauge +from helpers import trace +from helpers.utils import classdecorator +from helpers.overlay import UpdateSession +from helpers.io import ErrorMessage +from helpers.io import WarningMessage +from helpers.io import catch +from plugins import getParameter +import plugins.chip +from plugins.alpha.block.configuration import BlockConf + + +plugins.alpha.chip.importConstants( globals() ) + + +# ------------------------------------------------------------------- +# Class : "Configuration.ChipConf". + +class ChipConf ( BlockConf ): + + @staticmethod + def _toSymbolic ( u, rounding ): + """ + Pitch the coordinates ``u`` to the symbolic grid, according + to ``rounding`` (Superior or Inferior). + """ + oneLambda = DbU.fromLambda( 1.0 ) + remainder = u % oneLambda + if remainder: + if rounding == Superior: u = u + (oneLambda - remainder) + else: u = u - remainder + return u + + @staticmethod + def toSymbolic ( v, rounding ): + """ + Pitch the coordinates of object ``v`` to the symbolic grid, + according to ``rounding``. Were ``v`` can be: + + * A scalar, then rounding is Inferior or Superior. + * A Box, then rounding is: + + * Inwards: the pitched box will be fully enclosed in the + original box. + * Outwards: the pitched box will fully enclose the original + box. + """ + if isinstance(v,long): return ChipConf._toSymbolic( v, rounding ) + if isinstance(v,Box): + if rounding & Inwards: + roundings = [ Superior + , Superior + , Inferior + , Inferior ] + else: + roundings = [ Inferior + , Inferior + , Superior + , Superior ] + xMin = ChipConf._toSymbolic( v.getXMin(), roundings[0] ) + yMin = ChipConf._toSymbolic( v.getYMin(), roundings[1] ) + xMax = ChipConf._toSymbolic( v.getXMax(), roundings[2] ) + yMax = ChipConf._toSymbolic( v.getYMax(), roundings[3] ) + return Box( xMin, yMin, xMax, yMax ) + return v + + def __init__ ( self, cell, ioPins=[], ioPads=[] ): + trace( 550, ',+', 'ChipConf.__init__(): "{}"'.format(cell.getName()) ) + print( super(ChipConf,self).__init__ ) + super(ChipConf,self).__init__( cell, ioPins, ioPads ) +# trace( 550, '\tONE LAMBDA = %s\n' % DbU.getValueString(DbU.fromLambda(1.0)) ) + self.validated = True + # Block Corona parameters (triggers loading from disk). + self.cfg.chip.block.rails.count = None + self.cfg.chip.block.rails.hWidth = None + self.cfg.chip.block.rails.vWidth = None + self.cfg.chip.block.rails.hSpacing = None + self.cfg.chip.block.rails.vSpacing = None + self._railsCount = self.cfg.chip.block.rails.count + # Global Net names. + self.blockageName = "blockagenet" + # Global Nets. + self.coronaVdd = None + self.coronaVss = None + self.coronaCk = None + self.blockageNet = None + self.padsHavePosition = False + trace( 550, '-' ) + + @property + def railsCount ( self ): + return self._railsCount + + @railsCount.setter + def railsCount ( self, count ): + self._railsCount = count + + @property + def hRailWidth ( self ): + return self.cfg.chip.block.rails.hWidth + + @property + def vRailWidth ( self ): + return self.cfg.chip.block.rails.vWidth + + @property + def hRailSpace ( self ): + return self.cfg.chip.block.rails.hSpacing + + @property + def vRailSpace ( self ): + return self.cfg.chip.block.rails.vSpacing + + def computeCoronaBorder ( self ): + if self.useClockTree: + trace( 550, '\tcomputeCoronaBorder() useClockTree: {}\n'.format(self.useClockTree) ) + self.railsCount = self.cfg.chip.block.rails.count + 1 + trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) ) + self.minHCorona = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace + self.sliceHeight + self.minVCorona = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace + 10*self.sliceStep + + def chipValidate ( self ): + #self.checkPads() + #self.checkCorona() + #self.computeChipSize() + #self.checkChipSize() + self.findPowerAndClockNets() + return + + def getInstanceAb ( self, instance ): + ab = instance.getMasterCell().getAbutmentBox() + instance.getTransformation().applyOn( ab ) + if instance.getCell() == self.chip: return ab + if instance.getCell() != self.corona: + raise ErrorMessage( 1, 'ChipConf.getInstanceAb(): Instance "{}" neither belong to chip or corona.' \ + .format(instance.getName()) ) + return ab + self.icorona.getTransformation().applyOn( ab ) + return ab + + def setupICore ( self ): + """ + Setup the abutment box of the *core* master cell and position it's unique + instance (*icore*) in the center of the *corona* master cell. + """ + with UpdateSession(): + trace( 550, ',+', '\tChipConf.setupICore()\n' ) + ab = self.getInstanceAb( self.icorona ) + if ab.isEmpty(): + raise ErrorMessage( 1, 'ChipConf.setupICore(): Attempt to setup core *before* corona.' ) + return + #ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 ) + ab = self.toSymbolic( ab, Inwards ) + trace( 550, '\tself.coreAb:{}\n'.format(self.coreAb) ) + if self.core.getAbutmentBox().isEmpty(): + if not self.coreAb.isEmpty(): + trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) ) + ab = self.coreAb + else: + ab.inflate( -self.minHCorona, -self.minVCorona ) + self.coreSize = (ab.getWidth(), ab.getHeight()) + trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) ) + self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) ) + trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) ) + coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) / 2 + coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) / 2 + coreX = coreX - (coreX % self.sliceStep) + coreY = coreY - (coreY % self.sliceHeight) + self.icore.setTransformation( Transformation( coreX, coreY, Transformation.Orientation.ID ) ) + self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED ) + trace( 550, '-' ) + + def getCoronaNet ( self, chipNet ): + for plug in chipNet.getPlugs(): + if plug.getInstance() == self.icorona: + return plug.getMasterNet() + return None + + def toRoutingGauge ( self, uMin, uMax, layer ): + trace( 550, ',+', '\ttoRoutingGauge() [{} {}] {}\n' \ + .format(DbU.getValueString(uMin), DbU.getValueString(uMax), layer) ) + ab = self.corona.getAbutmentBox() + lg = None + mask = layer.getMask() + for layerGauge in self.routingGauge.getLayerGauges(): + if layerGauge.getLayer().getMask() == mask: + lg = layerGauge + trace( 550, '\tUsing layer gauge {}\n'.format(lg) ) + break + if uMax < uMin: uMin, uMax = uMax, uMin + if lg: + if lg.getDirection() == RoutingLayerGauge.Horizontal: + abMin = ab.getYMin() + abMax = ab.getYMax() + else: + abMin = ab.getXMin() + abMax = ab.getXMax() + if uMin <= abMin: + shiftRight = abMin - uMin + lg.getPitch() + uMin += shiftRight + uMax += shiftRight + if uMax >= abMax: + shiftLeft = uMax - abMax + lg.getPitch() + uMin -= shiftLeft + uMax -= shiftLeft + iTrackMin = lg.getTrackIndex( abMin, abMax, uMin, RoutingLayerGauge.Superior ) + iTrackMax = lg.getTrackIndex( abMin, abMax, uMax, RoutingLayerGauge.Inferior ) + if iTrackMax < iTrackMin: iTrackMax = iTrackMin + uTrackMin = lg.getTrackPosition( abMin, iTrackMin ) + uTrackMax = lg.getTrackPosition( abMin, iTrackMax ) + axis = (uTrackMax + uTrackMin) / 2 + width = (iTrackMax - iTrackMin) * lg.getPitch() + lg.getWireWidth() + if self.routingGauge.isSymbolic(): + oneLambda = DbU.fromLambda( 1.0 ) + if axis % oneLambda: + axis -= oneLambda / 2 + width -= oneLambda + trace( 550, '\t[{} {}]\n'.format(iTrackMin, iTrackMax) ) + trace( 550, '\taxis: {}l {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) ) + trace( 550, '\twidth: {}l {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) ) + else: + axis = (uMax + uMin) / 2 + width = (uMax - uMin) + trace( 550, '-' ) + return axis, width + + def toCoronaPitchInChip ( self, uCore, layer ): + trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {}l %s\n' \ + .format(DbU.toLambda(uCore), DbU.getValueString(uCore)) ) + coronaAb = self.getInstanceAb( self.icorona ) + lg = None + mask = layer.getMask() + for layerGauge in self.routingGauge.getLayerGauges(): + if layerGauge.getLayer().getMask() == mask: + lg = layerGauge + break + if not lg: + trace( 550, '-' ) + return 0 + trace( 550, '\t{}\n'.format(lg) ) + if lg: + if lg.getDirection() == RoutingLayerGauge.Horizontal: + uCorona = uCore - coronaAb.getYMin() + else: + uCorona = uCore - coronaAb.getXMin() + uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer ) + trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l {}\n' \ + .format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) ) + if lg: + if lg.getDirection() == RoutingLayerGauge.Horizontal: + uCore = uCorona + coronaAb.getYMin() + else: + uCore = uCorona + coronaAb.getXMin() + trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l %s\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) ) + trace( 550, '\ttoCoronaPitchInChip(): uCore: {}l %s\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) ) + trace( 550, '-' ) + return uCore + + def coronaHorizontal ( self, chipNet, layer, chipY, width, chipXMin, chipXMax ): + trace( 550, ',+', '\tChipConf.coronaHorizontal\n' ) + coronaAb = self.getInstanceAb( self.icorona ) + coronaNet = self.getCoronaNet ( chipNet ) + if not coronaNet: return None + coronaY = chipY - coronaAb.getYMin() + dxMin = ChipConf.toSymbolic( chipXMin - coronaAb.getXMin(), Superior ) + dxMax = ChipConf.toSymbolic( chipXMax - coronaAb.getXMin(), Inferior ) + trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) ) + trace( 550, '\t| Real\n' ) + trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaY)) ) + trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) ) + trace( 550, '\t| dxMin:{} ({}l)\n' \ + .format( DbU.getValueString(chipXMin - coronaAb.getXMin()) + , DbU.toLambda(chipXMin - coronaAb.getXMin()) ) ) + trace( 550, '\t| dxMax:{}\n'.format(DbU.getValueString(chipXMax - coronaAb.getXMin())) ) + coronaY, width = self.toRoutingGauge( coronaY - width/2, coronaY + width/2, layer ) + trace( 550, '\t| On Grid\n' ) + trace( 550, '\t| axis: {}l or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) ) + trace( 550, '\t| width:{}l or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) ) + trace( 550, '\t| dxMin:{}l\n'.format(DbU.toLambda(dxMin)) ) + trace( 550, '\t| dxMax:{}l\n'.format(DbU.toLambda(dxMax)) ) + h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax ) + trace( 550, '\t| {}\n'.format(h) ) + trace( 550, '-' ) + return h + + def coronaVertical ( self, chipNet, layer, chipX, width, chipYMin, chipYMax ): + trace( 550, ',+', '\tChipConf.coronaVertical\n' ) + coronaAb = self.getInstanceAb( self.icorona ) + coronaNet = self.getCoronaNet( chipNet ) + if not coronaNet: return None + coronaX = chipX - coronaAb.getXMin() + dyMin = ChipConf.toSymbolic( chipYMin - coronaAb.getYMin(), Superior ) + dyMax = ChipConf.toSymbolic( chipYMax - coronaAb.getYMin(), Inferior ) + trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) ) + trace( 550, '\t| Real\n' ) + trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaX)) ) + trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) ) + coronaX, width = self.toRoutingGauge( coronaX - width/2, coronaX + width/2, layer ) + trace( 550, '\t| On Grid\n' ) + trace( 550, '\t| axis: {} or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) ) + trace( 550, '\t| width:{} or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) ) + v = Vertical.create( coronaNet, layer, coronaX, width, dyMin, dyMax ) + trace( 550, '\t| {}\n'.format(v) ) + trace( 550, '-' ) + return v + + def coronaContact ( self, chipNet, layer, chipX, chipY, width, height, flags=0 ): + trace( 550, ',+', '\tChipConf.coronaContact\n' ) + coronaAb = self.getInstanceAb( self.icorona ) + coronaNet = self.getCoronaNet( chipNet ) + if not coronaNet: return None + coronaX = chipX - coronaAb.getXMin() + coronaY = chipY - coronaAb.getYMin() + trace( 550, '\t| chipNet: {} {}\n'.format(chipNet,layer) ) + trace( 550, '\t| Real\n' ) + trace( 550, '\t| center: {:>12} {:>12}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) ) + trace( 550, '\t| WxH: {:>12} {:>12}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) ) + topLayer = layer.getTop() + if self.isHorizontal(topLayer): + coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, layer.getBottom() ) + coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, topLayer ) + else: + coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, topLayer ) + coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, layer.getBottom() ) + if not (flags & OnHorizontalPitch): + trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' ) + coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior ) + if not (flags & OnVerticalPitch ): + trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' ) + coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior ) + trace( 550, '\t| On Grid\n' ) + trace( 550, '\t| X axis: {:>12} or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) ) + trace( 550, '\t| Y axis: {:>12} or {:>12}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) ) + trace( 550, '\t| center: {:>12} {:>12}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) ) + trace( 550, '\t| WxH: {:>12} {:>12}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) ) + c = Contact.create( coronaNet + , layer + , coronaX + , coronaY + , width + , height + ) + trace( 550, '\t| {}\n'.format(c) ) + trace( 550, '-' ) + return c + + def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ): + trace( 550, ',+', '\tChipConf.coronaContactArray\n' ) + viaPitch = layer.getMinimalSize() + layer.getMinimalSpacing() + coronaAb = self.getInstanceAb( self.icorona ) + coronaNet = self.getCoronaNet( chipNet ) + if not coronaNet: return None + trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) ) + coronaX = chipX - coronaAb.getXMin() + coronaY = chipY - coronaAb.getYMin() + topLayer = layer.getTop() + if self.isHorizontal(topLayer): + coronaX, width = self.toRoutingGauge( coronaX, coronaX, layer.getBottom() ) + coronaY, height = self.toRoutingGauge( coronaY, coronaY, topLayer ) + else: + coronaX, width = self.toRoutingGauge( coronaX, coronaX, topLayer ) + coronaY, height = self.toRoutingGauge( coronaY, coronaY, layer.getBottom() ) + if not (flags & OnHorizontalPitch): + trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' ) + coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior ) + if not (flags & OnVerticalPitch ): + trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' ) + coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior ) + contacts = [] + xContact = coronaX - viaPitch * (array[0]-1)/2 + yContact = coronaY - viaPitch * (array[1]-1)/2 + contactSize = layer.getMinimalSize() + trace( 550, '\txContact:{}l yContact:{}l\n'.format(DbU.toLambda(xContact),DbU.toLambda(yContact)) ) + for i in range(array[0]): + for j in range(array[1]): + c = Contact.create( coronaNet + , layer + , xContact + i*viaPitch + , yContact + j*viaPitch + , contactSize + , contactSize + ) + trace( 550, '\t+ {}\n'.format(c) ) + contacts.append( c ) + trace( 550, '-' ) + return contacts + + def coronaPin ( self, chipNet, count, direction, layer, chipX, chipY, width, height ): + trace( 550, ',+', '\tChipConf.coronaPin\n' ) + coronaAb = self.getInstanceAb( self.icorona ) + coronaNet = self.getCoronaNet( chipNet ) + if not coronaNet: return None + coronaX = chipX - coronaAb.getXMin() + coronaY = chipY - coronaAb.getYMin() + trace( 550, '\t| chipNet: {} ({}) {}\n'.format(chipNet, count, layer) ) + trace( 550, '\t| Real\n' ) + trace( 550, '\t| center: {} {}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) ) + trace( 550, '\t| WxH: {} {}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) ) + topLayer = layer.getTop() + if self.isHorizontal(topLayer): + coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, layer.getBottom() ) + coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, topLayer ) + else: + coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, topLayer ) + coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, layer.getBottom() ) + if direction == Pin.Direction.NORTH or direction == Pin.Direction.SOUTH: + trace( 550, '\tEast/West not on horizontal routing pitch, Y on lambda only.\n' ) + coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior ) + if direction == Pin.Direction.EAST or direction == Pin.Direction.WEST: + trace( 550, '\tNorth/South not on vertical routing pitch, X on lambda only.\n' ) + coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior ) + trace( 550, '\t| On Grid\n' ) + trace( 550, '\t| X axis: {} or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) ) + trace( 550, '\t| Y axis: {} or {}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) ) + trace( 550, '\t| center: {} {}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) ) + trace( 550, '\t| WxH: {} {}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) ) + c = Pin.create( coronaNet + , '{}.{}'.format(coronaNet.getName(),count) + , direction + , Pin.PlacementStatus.FIXED + , layer + , coronaX + , coronaY + , width + , height + ) + trace( 550, '\t| {}\n'.format(c) ) + trace( 550, '-' ) + return c + + def checkPads ( self ): + + def contains ( padList, side, padInstance ): + for i in range(len(padList)): + if padList[i][1] == padInstance.getName(): + if (padInstance.getMasterCell().getAbutmentBox().getHeight() != self.ioPadHeight): + raise ErrorMessage( 1, 'The pad [{}] {} ({}) on {} side is not an instance of a pad cell.' \ + .format(i,padInstance.getName(),padInstance.getMasterCell().getName(),side) ) + padList[i][1] = padInstance + return True + return False + + def checkNotFounds ( padList, side ): + for i in range(len(padList)): + if not isinstance(padList[i][1],Instance): + print( ErrorMessage( 1, 'The pad [{}] ({}) of list {} do not exists in netlist (skipped).' + .format(i,padList[i][1],side) )) + return + + af = CRL.AllianceFramework.get() + cellPads = [] + for instance in self.chip.getInstances(): + if contains(self.southPads,'south',instance): continue + if contains(self.northPads,'north',instance): continue + if contains(self.eastPads ,'east' ,instance): continue + if contains(self.westPads ,'west' ,instance): continue + if (instance.getMasterCell().getAbutmentBox().getHeight() == self.ioPadHeight): + raise ErrorMessage( 1, 'Pad "{}" is not on any side (N/S/E/W).'.format(instance.getName()) ) + self.validated = False + else: + self.coronas.append( instance ) + checkNotFounds( self.southPads, 'south' ) + checkNotFounds( self.northPads, 'north' ) + checkNotFounds( self.eastPads , 'east' ) + checkNotFounds( self.westPads , 'west' ) + if len(self.coronas) > 1: + message = [ 'Chip "{}" have more than one corona:'.format(self.chip.getName()) ] + for i in range(len(self.coronas)): + message.append( '{}: {}'.format(i,self.coronas[i].getName()) ) + raise ErrorMessage( 1, message ) + self.validated = False + if len(self.coronas) < 1: + raise ErrorMessage( 1, 'Chip "{}" doesn\'t seems to have a corona.' \ + .format(self.chip.getName()) ) + self.validated = False + else: + for instance in self.corona.getInstances(): + self.cores.append( instance ) + if len(self.cores) > 1: + message = [ 'Chip "{}" have more than one core:'.format(self.chip.getName()) ] + for i in range(len(self.cores)): + message.append( '{}: {}'.format(i,self.cores[i].getName()) ) + raise ErrorMessage( 1, message ) + self.validated = False + + if len(self.cores) < 1: + raise ErrorMessage( 1, 'Chip "{} doesn\'t seems to have a core.' \ + .format(self.chip.getName()) ) + self.validated = False + return + + def findPowerAndClockNets ( self ): + if self.icore: + for plug in self.icore.getPlugs(): + masterNet = plug.getMasterNet() + netType = masterNet.getType() + if netType != Net.Type.POWER \ + and netType != Net.Type.GROUND \ + and netType != Net.Type.CLOCK: + continue + net = plug.getNet() + if not net: + net = self.corona.getNet( masterNet.getName() ) + if not net: + raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Missing global net "{}" at corona level.' \ + .format(asterNet.getName()) ) + self._validated = False + continue + if netType == Net.Type.GROUND: + if self.coronaVss and self.coronaVss != net: + raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple ground nets "{}" and "{}" at corona level.' \ + .format(self.coronaVss.getName(), net.getName()) ) + self._validated = False + continue + else: + self.coronaVss = net + + if netType == Net.Type.POWER: + if self.coronaVdd and self.coronaVdd != net: + raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple power nets "{}" and "{}" at corona level.' \ + .format(self.coronaVdd.getName(), net.getName()) ) + self._validated = False + continue + else: + self.coronaVdd = net + + if netType == Net.Type.CLOCK: + if self.coronaCk and self.coronaCk != net: + raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple clock nets "{}" and "{}" at corona level.' \ + .format(self.coronaCk.getName(), net.getName()) ) + self._validated = False + continue + else: + self.coronaCk = net + for net in self.corona.getNets(): + if net.getType() == Net.Type.BLOCKAGE: + self.blockageNet = net + self.blockageName = net.getName() + if not self.blockageNet: + self.blockageNet = Net.create( self.corona, self.blockageName ) + self.blockageNet.setType( Net.Type.BLOCKAGE ) + return + + def checkChipSize ( self ): + #if self._coreSize.isEmpty(): return + # + #minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight + #minHeight = self._coreSize.getHeight() + self._minCorona + 2*self._padHeight + # + #if self._chipSize.getWidth() < minWidth: + # raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \ + # % ( DbU.toLambda(minWidth), DbU.toLambda(self._chipSize.getWidth()) ) ) + # self._validated = False + # + #if self._chipSize.getHeight() < minHeight: + # raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \ + # % ( DbU.toLambda(minHeight), DbU.toLambda(self._chipSize.getHeight()) ) ) + # self._validated = False + return + + def checkCorona ( self ): + trace( 550, ',+', 'Configuration.checkCorona()\n' ) + netPads = {} + for plug in self.icorona.getPlugs(): + padNet = plug.getNet() + coronaNet = plug.getMasterNet() + if not padNet and coronaNet.isGlobal(): + padNet = self.chip.getNet( coronaNet.getName() ) + if padNet: + if not netPads.has_key(padNet): + trace( 550, '\t{:>20} <-> {:<20}\n'.format(padNet.getName(),coronaNet.getName()) ) + netPads[ padNet ] = coronaNet + else: + raise ErrorMessage( 1, 'ChipConf.checkCorona(): Corona nets "{}" and "{}" connected to the same pad net "{}".' \ + .format(coronaNet.getName(),netPads[padNet].getName(),padNet.getName()) ) + self._validated = False + trace( 550, '-' ) + return + + def computeChipSize ( self ): + + def getSideLength ( pads ): + sideLength = self.ioPadHeight * 2 + for pad in pads: sideLength += pad.getMasterCell().getAbutmentBox().getWidth() + return sideLength + + if not self.chipSize.isEmpty(): return + southPadsLength = getSideLength( self.southPads ) + northPadsLength = getSideLength( self.northPads ) + eastPadsLength = getSideLength( self.eastPads ) + westPadsLength = getSideLength( self.westPads ) + horizontalPads = max( len(self.southPads), len(self.northPads) ) + verticalPads = max( len(self.eastPads ), len(self.westPads ) ) + self.chipSize = ( max( southPadsLength, northPadsLength ) + , max( westPadsLength, eastPadsLength ) ) + + def setupCorona ( self, gapX1, gapY1, gapX2, gapY2 ): + ab = self.chip.getAbutmentBox() + ab.inflate ( -gapX1, -gapY1, -gapX2, -gapY2 ) + ab.inflate ( - self.ioPadHeight ) + ab.translate( - self.ioPadHeight, - self.ioPadHeight) + ab = self.toSymbolic( ab, Inwards ) + + self. corona.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) ) + self.icorona.setTransformation( + Transformation( self.toSymbolic( self.ioPadHeight + ab.getXMin(), Superior ) + , self.toSymbolic( self.ioPadHeight + ab.getYMin(), Superior ) + , Transformation.Orientation.ID ) ) + self.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED ) + + def setupCore ( self, gapX1, gapY1, gapX2, gapY2 ): + trace( 550, ',+', '\tChipConf.setupCore()\n' ) + ab = self.getInstanceAb( self.icorona ) + if ab.isEmpty(): + raise ErrorMessage( 1, 'ChipConf.setupCore(): Attempt to setup core *before* corona.' ) + return + ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 ) + ab = self.toSymbolic( ab, Inwards ) + tracee( 550, '\tself.coreAb:{}\n'.format(self.coreAb) ) + if not self.coreAb.isEmpty(): + trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) ) + ab = self.coreAb + trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) ) + self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) ) + self.icore.setTransformation( + Transformation( ChipConf.toSymbolic(ab.getXMin(),Inferior) - self.icorona.getTransformation().getTx() + , ChipConf.toSymbolic(ab.getYMin(),Inferior) - self.icorona.getTransformation().getTy() + , Transformation.Orientation.ID ) ) + self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED ) + trace( 550, '-' ) diff --git a/cumulus/src/plugins/alpha/chip/corona.py b/cumulus/src/plugins/alpha/chip/corona.py new file mode 100644 index 00000000..f1fc2f61 --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/corona.py @@ -0,0 +1,628 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) SU 2014-2020, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/corona.py" | +# +-----------------------------------------------------------------+ + + +from __future__ import print_function +import bisect +from operator import methodcaller +import Cfg +from Hurricane import DbU +from Hurricane import Point +from Hurricane import Interval +from Hurricane import Box +from Hurricane import Transformation +from Hurricane import Path +from Hurricane import Occurrence +from Hurricane import Net +from Hurricane import Contact +from Hurricane import Horizontal +from Hurricane import Vertical +from Hurricane import Pad +import CRL +from CRL import RoutingLayerGauge +from helpers import trace +from helpers.io import ErrorMessage +from helpers.io import WarningMessage +from helpers.overlay import UpdateSession +import plugins +from plugins import StackedVia +import plugins.alpha.chip + + +plugins.alpha.chip.importConstants( globals() ) + + +# -------------------------------------------------------------------- +# Class : "corona.IntervalSet" + +class IntervalSet ( object ): + + def __init__ ( self ): + self.chunks = [] + return + + def merge ( self, min, max ): + toMerge = Interval( min, max ) + imerge = len(self.chunks) + length = len(self.chunks) + i = 0 + while i < length: + if imerge >= length: + if toMerge.getVMax() < self.chunks[i].getVMin(): + self.chunks.insert( i, toMerge ) + length += 1 + imerge = 0 + break + if toMerge.intersect(self.chunks[i]): + imerge = i + self.chunks[imerge].merge( toMerge ) + else: + if toMerge.getVMax() >= self.chunks[i].getVMin(): + self.chunks[imerge].merge( self.chunks[i] ) + del self.chunks[ i ] + length -= 1 + continue + else: + break + i += 1 + if imerge >= length: + self.chunks.insert( length, toMerge ) + + +# -------------------------------------------------------------------- +# Class : "corona.Rail" + +class Rail ( object ): + + def __init__ ( self, side, order, axis ): + self.side = side + self.order = order + self.axis = axis + self.vias = {} # Key:pos Element:[pos,railContact,blockContact] + + @property + def net ( self ): return self.side.getRailNet(self.order) + + +# -------------------------------------------------------------------- +# Class : "corona.HorizontalRail" + +class HorizontalRail ( Rail ): + + def __init__ ( self, side, order, axis ): + Rail.__init__( self, side, order, axis ) + trace( 550, '\t{}\n'.format(self) ) + + def __str__ ( self ): + return ''.format( self.side.getRailNet(self.order) + , self.order + , DbU.getValueString(self.axis) ) + + def connect ( self, contact ): + contactBb = contact.getBoundingBox() + if contactBb.getXMin() < self.side.innerBb.getXMin() \ + or contactBb.getXMax() > self.side.innerBb.getXMax(): + raise ErrorMessage( 1, [ '{} is outside rail/corona X range,'.format(contact) + , 'power pad is likely to be to far off west or east.' + , '(core:{})'.format(self.side.innerBb) ] ) + if self.vias.has_key(contact.getX()): return False + keys = self.vias.keys() + keys.sort() + insertIndex = bisect.bisect_left( keys, contact.getX() ) + + if len(keys) > 0: + if insertIndex < len(keys): + insertPosition = keys[ insertIndex ] + if contactBb.getXMax() >= self.vias[insertPosition][2].getBoundingBox().getXMin(): + return False + if insertIndex > 0: + if self.vias[keys[insertIndex-1]][2].getBoundingBox().getXMax() >= contactBb.getXMin(): + return False + self.vias[ contact.getX() ] = [ contact.getX() + , StackedVia( self.net + , self.side.getLayerDepth(self.side.getHLayer()) + , contact.getX() + , self.axis + , contact.getWidth() - DbU.fromLambda(1.0) + , self.side.hRailWidth - DbU.fromLambda(1.0) + ) + , contact ] + trace( 550, '\tADD "{}" contact "{}" @ [{} {}]\n' \ + .format( contact.getNet().getName() + , contact.getLayer().getName() + , DbU.getValueString(contact.getX()) + , DbU.getValueString(self.axis)) ) + self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) + return True + + def doLayout ( self ): + trace( 550, ',+', '\tHorizontalRail.doLayout() order:{} @{}\n' \ + .format( self.order,DbU.getValueString(self.axis ))) + railVias = [ self.side.corner0(self.order) + , self.side.corner1(self.order) ] + for via in self.vias.values(): + if via[1].getNet() != via[2].getNet(): continue + via[1].mergeDepth( self.side.getLayerDepth(self.side.getVLayer()) ) + via[1].doLayout() + Vertical.create( via[1].getVia( via[2].getLayer() ) + , via[2] + , via[2].getLayer() + , via[2].getX() + , via[2].getWidth() + ) + railVias.append( via[1].getVia( self.side.getVLayer()) ) + for i in range(1,len(railVias)): + h = Horizontal.create( railVias[i-1] + , railVias[i] + , self.side.getHLayer() + , self.axis + , self.side.hRailWidth + ) + trace( 550, '\t| {}\n'.format(h) ) + trace( 550, '-' ) + + +# -------------------------------------------------------------------- +# Class : "corona.VerticalRail" + +class VerticalRail ( Rail ): + + def __init__ ( self, side, order, axis ): + Rail.__init__( self, side, order, axis ) + trace( 550, '\t{}\n'.format(self) ) + + def __str__ ( self ): + return ''.format( self.side.getRailNet(self.order) + , self.order + , DbU.getValueString(self.axis) ) + + def doLayout ( self ): + railVias = [ self.side.corner0(self.order) + , self.side.corner1(self.order) ] + for via in self.vias.values(): + if via[1].getNet() != via[2].getNet(): continue + via[1].doLayout() + Horizontal.create( via[1].getVia( via[2].getLayer() ) + , via[2] + , via[2].getLayer() + , via[2].getY() + , via[2].getHeight() + ) + railVias.append( via[1].getVia(self.side.getVLayer()) ) + railVias.sort( key=methodcaller('getY') ) + for i in range(1,len(railVias)): + Vertical.create( railVias[i-1] + , railVias[i] + , self.side.getVLayer() + , self.axis + , self.side.vRailWidth + ) + + def connect ( self, contact ): + contactBb = contact.getBoundingBox() + if contactBb.getYMin() < self.side.innerBb.getYMin() \ + or contactBb.getYMax() > self.side.innerBb.getYMax(): + raise ErrorMessage( 1, [ '{} is outside rail/corona Y range'.format(contact) + , 'power pad is likely to be to far off north or south.' + , '(core:{})'.format(self.side.innerBb) ] ) + if self.vias.has_key(contact.getY()): return False + trace( 550, ',+', '\tVerticalRail.connect() [{}] @{}\n'.format(self.order,DbU.toLambda(self.axis)) ) + trace( 550, '\t{}\n'.format(contact) ) + keys = self.vias.keys() + keys.sort() + insertIndex = bisect.bisect_left( keys, contact.getY() ) + trace( 550, ',+', '\tkeys:' ) + for key in keys: + trace( 550, ' {}'.format(DbU.toLambda(key)) ) + trace( 550, '\n' ) + + if len(keys) > 0: + if insertIndex < len(keys): + insertPosition = keys[ insertIndex ] + trace( 550, '\tinsertIndex:{}'.format(insertIndex) ) + trace( 550, '\tCheck NEXT contactBb:{} via:{}\n' \ + .format( contactBb + , self.vias[insertPosition][2].getBoundingBox()) ) + if contactBb.getYMax() >= self.vias[insertPosition][2].getBoundingBox().getYMin(): + trace( 550, ',--', '\tReject {} intersect NEXT\n'.format(contact) ) + return False + if insertIndex > 0: + trace( 550, '\tcheck PREVIOUS contactBb:{} via:{}\n' \ + .format( contactBb + , self.vias[keys[insertIndex-1]][2].getBoundingBox()) ) + if self.vias[keys[insertIndex-1]][2].getBoundingBox().getYMax() >= contactBb.getYMin(): + trace( 550, ',--', '\tReject {} intersect PREVIOUS\n'.format(contact) ) + return False + self.vias[ contact.getY() ] = [ contact.getY() + , StackedVia( self.net + , self.side.getLayerDepth(self.side.getVLayer()) + , self.axis + , contact.getY() + , self.side.vRailWidth - DbU.fromLambda(1.0) + , contact.getHeight() - DbU.fromLambda(1.0) + ) + , contact ] + trace(550, ',--' '\tADD {}\n'.format(contact) ) + self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) + return True + + +# -------------------------------------------------------------------- +# Class : "corona.Side" + +class Side ( object ): + + def __init__ ( self, corona ): + self.corona = corona + + @property + def railsCount ( self ): return self.corona.railsCount + + @property + def innerBb ( self ): return self.corona.innerBb + + @property + def hRailWidth ( self ): return self.corona.hRailWidth + + @property + def hRailSpace ( self ): return self.corona.hRailSpace + + @property + def vRailWidth ( self ): return self.corona.vRailWidth + + @property + def vRailSpace ( self ): return self.corona.vRailSpace + + @property + def corners ( self ): return self.corona.corners + + @property + def horizontalDepth ( self ): return self.corona.horizontalDepth + + @property + def verticalDepth ( self ): return self.corona.verticalDepth + + @property + def blockageNet ( self ): return self.corona.blockageNet + + def getLayerDepth ( self, metal ): return self.corona.getLayerDepth(metal) + def getRail ( self, i ): return self.rails[i] + def getRailNet ( self, i ): return self.corona.getRailNet(i) + def getHLayer ( self ): return self.corona.getHLayer() + def getVLayer ( self ): return self.corona.getVLayer() + + def getRailAxis ( self, i ): + raise ErrorMessage( 1, 'Side.getRailAxis(): Must never be called on base class.' ) + + def getInnerRail ( self, i ): + if i >= len(self.rails): + raise ErrorMessage( 1, 'Side.getInnerRail(): no rail {} (only:{}).' \ + .format(i,len(self.rails)) ) + return self.rails[i] + + def getOuterRail ( self, i ): + if i >= len(self.rails): + raise ErrorMessage( 1, 'Side.getOuterRail(): no rail {} (only: {}).' \ + .format(i,len(self.rails)) ) + return self.rails[-(i+1)] + + def connect ( self, blockSide ): + for terminal in blockSide.terminals: + trace( 550, '\tterminal:{}\n'.format(terminal) ) + for rail in self.rails: + rail.connect( terminal[1] ) + + def connectPads ( self, padSide ): + for contact in padSide.pins: + if contact.getNet().isClock(): + for i in range(len(self.rails)): + trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) ) + self.getOuterRail(i).connect( contact ) + elif contact.getNet().isSupply(): + self.getOuterRail( 0 ).connect( contact ) + halfRails = (len(self.rails)-1)/2 + trace( 550, '\thalfRails:{}\n'.format(halfRails) ) + for contact in padSide.pins: + if not contact.getNet().isSupply() and not contact.getNet().isClock(): continue + trace( 550, ',+', '\tConnect pad contact {}\n'.format(contact) ) + for i in range(halfRails): + trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) ) + self.getOuterRail(i).connect( contact ) + trace( 550, '-' ) + + def doLayout ( self ): + for rail in self.rails: rail.doLayout() + + +# -------------------------------------------------------------------- +# Class : "corona.HorizontalSide" + +class HorizontalSide ( Side ): + + def __init__ ( self, corona ): + Side.__init__( self, corona ) + self.rails = [] + for i in range(self.railsCount): + self.rails.append( HorizontalRail(self,i,self.getRailAxis(i)) ) + return + + +# -------------------------------------------------------------------- +# Class : "corona.SouthSide" + +class SouthSide ( HorizontalSide ): + + def __init__ ( self, corona ): + HorizontalSide.__init__( self, corona ) + return + + def getRailAxis ( self, i ): + return self.innerBb.getYMin() - self.hRailWidth/2 - self.hRailSpace \ + - i*(self.hRailWidth + self.hRailSpace) + + def corner0 ( self, i ): return self.corners[SouthWest][i] + def corner1 ( self, i ): return self.corners[SouthEast][i] + + +# -------------------------------------------------------------------- +# Class : "corona.NorthSide" + +class NorthSide ( HorizontalSide ): + + def __init__ ( self, corona ): + HorizontalSide.__init__( self, corona ) + return + + def getRailAxis ( self, i ): + return self.innerBb.getYMax() + self.hRailWidth/2 + self.hRailSpace \ + + i*(self.hRailWidth + self.hRailSpace) + + def corner0 ( self, i ): return self.corners[NorthWest][i] + def corner1 ( self, i ): return self.corners[NorthEast][i] + + +# -------------------------------------------------------------------- +# Class : "corona.VerticalSide" + +class VerticalSide ( Side ): + + def __init__ ( self, corona ): + Side.__init__( self, corona ) + + self.rails = [] + for i in range(self.railsCount): + self.rails.append( VerticalRail(self,i,self.getRailAxis(i)) ) + return + + def addBlockages ( self, sideXMin, sideXMax ): + spans = IntervalSet() + for rail in self.rails: + for via in rail.vias.values(): + if via[1].getNet() != via[2].getNet(): continue + spans.merge( via[1]._y - via[1]._height/2, via[1]._y + via[1]._height/2 ) + routingGauge = self.corona.routingGauge + for depth in range(self.getInnerRail(0).vias.values()[0][1].bottomDepth + ,self.getInnerRail(0).vias.values()[0][1].topDepth ): + blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer() + pitch = routingGauge.getLayerPitch(depth) + for chunk in spans.chunks: + Horizontal.create( self.blockageNet + , blockageLayer + , (chunk.getVMax() + chunk.getVMin())/2 + , chunk.getVMax() - chunk.getVMin() + pitch*2 + , sideXMin + , sideXMax + ) + depth -= 2 + if depth > 0: + blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer() + pitch = routingGauge.getLayerPitch(depth) + for chunk in spans.chunks: + Horizontal.create( self.blockageNet + , blockageLayer + , (chunk.getVMax() + chunk.getVMin())/2 + , chunk.getVMax() - chunk.getVMin() + pitch*2 + , sideXMin + , sideXMax + ) + + +# -------------------------------------------------------------------- +# Class : "corona.WestSide" + +class WestSide ( VerticalSide ): + + def __init__ ( self, corona ): + VerticalSide.__init__( self, corona ) + + def getRailAxis ( self, i ): + return self.innerBb.getXMin() - self.vRailWidth/2 - self.vRailSpace \ + - i*(self.vRailWidth + self.vRailSpace) + + def corner0 ( self, i ): return self.corners[SouthWest][i] + def corner1 ( self, i ): return self.corners[NorthWest ][i] + + def addBlockages ( self ): + sideXMin = self.getOuterRail(0).axis - self.vRailWidth + sideXMax = self.getInnerRail(0).axis + self.vRailWidth + VerticalSide.addBlockages( self, sideXMin, sideXMax ) + + +# -------------------------------------------------------------------- +# Class : "corona.EastSide" + +class EastSide ( VerticalSide ): + + def __init__ ( self, corona ): + VerticalSide.__init__( self, corona ) + + def getRailAxis ( self, i ): + return self.innerBb.getXMax() + self.vRailWidth/2 + self.vRailSpace \ + + i*(self.vRailWidth + self.vRailSpace) + + def corner0 ( self, i ): return self.corners[SouthEast][i] + def corner1 ( self, i ): return self.corners[NorthEast ][i] + + def addBlockages ( self ): + sideXMin = self.getInnerRail(0).axis - self.vRailWidth + sideXMax = self.getOuterRail(0).axis + self.vRailWidth + VerticalSide.addBlockages( self, sideXMin, sideXMax ) + + +# -------------------------------------------------------------------- +# Class : "corona.Builder" + +class Builder ( object ): + + def __init__ ( self, block ): + self.block = block + self.innerBb = self.block.bb + self.block.path.getTransformation().applyOn( self.innerBb ) + self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 ) + self.southSide = SouthSide( self ) + self.northSide = NorthSide( self ) + self.westSide = WestSide ( self ) + self.eastSide = EastSide ( self ) + + @property + def conf ( self ): return self.block.conf + + @property + def routingGauge ( self ): return self.conf.routingGauge + + @property + def topLayerDepth ( self ): return self.conf.topLayerDepth + + @property + def horizontalDepth ( self ): return self.conf.horizontalDepth + + @property + def verticalDepth ( self ): return self.conf.verticalDepth + + @property + def blockageNet ( self ): return self.conf.blockageNet + + @property + def railsCount ( self ): return self.conf.railsCount + + @property + def hRailWidth ( self ): return self.conf.cfg.chip.block.rails.hWidth + + @property + def vRailWidth ( self ): return self.conf.cfg.chip.block.rails.vWidth + + @property + def hRailSpace ( self ): return self.conf.cfg.chip.block.rails.hSpacing + + @property + def vRailSpace ( self ): return self.conf.cfg.chip.block.rails.vSpacing + + def getLayerDepth ( self, metal ): + return self.conf.routingGauge.getLayerDepth( metal ) + + def getRailNet ( self, i ): + if self.conf.useClockTree and i == 0: return self.conf.coronaCk + if i % 2: return self.conf.coronaVss + return self.conf.coronaVdd + + def getHLayer ( self ): + return self.routingGauge.getLayerGauge( self.horizontalDepth ).getLayer() + + def getVLayer ( self ): + return self.routingGauge.getLayerGauge( self.verticalDepth ).getLayer() + + def connectCore ( self ): + for plane in self.block.planes.values(): + for side in plane.sides.values(): + self.southSide.connect( side[South] ) + self.northSide.connect( side[North] ) + self.westSide .connect( side[West ] ) + self.eastSide .connect( side[East ] ) + + def connectPads ( self, padsCorona ): + self.southSide.connectPads( padsCorona.southSide ) + self.northSide.connectPads( padsCorona.northSide ) + self.eastSide .connectPads( padsCorona.eastSide ) + self.westSide .connectPads( padsCorona.westSide ) + return + + def doLayout ( self ): + self.corners = { SouthWest : [] + , SouthEast : [] + , NorthWest : [] + , NorthEast : [] + } + contactDepth = self.horizontalDepth + if self.horizontalDepth > self.verticalDepth: + contactDepth = self.verticalDepth + with UpdateSession(): + blBox = Box() + brBox = Box() + tlBox = Box() + trBox = Box() + for i in range(self.railsCount): + xBL = self.westSide .getRail(i).axis + yBL = self.southSide.getRail(i).axis + xTR = self.eastSide .getRail(i).axis + yTR = self.northSide.getRail(i).axis + net = self.getRailNet( i ) + blBox.merge( xBL, yBL ) + brBox.merge( xTR, yBL ) + tlBox.merge( xBL, yTR ) + trBox.merge( xTR, yTR ) + self.routingGauge.getContactLayer(contactDepth) + self.corners[SouthWest].append( + Contact.create( net + , self.routingGauge.getContactLayer(contactDepth) + , xBL, yBL + , self.hRailWidth + , self.vRailWidth + ) ) + self.corners[NorthWest].append( + Contact.create( net + , self.routingGauge.getContactLayer(contactDepth) + , xBL, yTR + , self.hRailWidth + , self.vRailWidth + ) ) + self.corners[SouthEast].append( + Contact.create( net + , self.routingGauge.getContactLayer(contactDepth) + , xTR, yBL + , self.hRailWidth + , self.vRailWidth + ) ) + self.corners[NorthEast].append( + Contact.create( net + , self.routingGauge.getContactLayer(contactDepth) + , xTR, yTR + , self.hRailWidth + , self.vRailWidth + ) ) + self.southSide.doLayout() + self.northSide.doLayout() + self.westSide .doLayout() + self.eastSide .doLayout() + self.westSide.addBlockages() + self.eastSide.addBlockages() + blBox.inflate( self.hRailWidth, self.vRailWidth ) + brBox.inflate( self.hRailWidth, self.vRailWidth ) + tlBox.inflate( self.hRailWidth, self.vRailWidth ) + trBox.inflate( self.hRailWidth, self.vRailWidth ) + for depth in range( 1, self.conf.topLayerDepth + 1 ): + blockageLayer = self.routingGauge.getRoutingLayer(depth).getBlockageLayer() + Pad.create( self.blockageNet, blockageLayer, blBox ) + Pad.create( self.blockageNet, blockageLayer, brBox ) + Pad.create( self.blockageNet, blockageLayer, tlBox ) + Pad.create( self.blockageNet, blockageLayer, trBox ) diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py new file mode 100644 index 00000000..5e4eb809 --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -0,0 +1,1059 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) SU 2014-2020, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/pads.py" | +# +-----------------------------------------------------------------+ + + +from __future__ import print_function +import sys +import re +from operator import itemgetter +import Cfg +from Hurricane import DbU +from Hurricane import Point +from Hurricane import Transformation +from Hurricane import Interval +from Hurricane import Box +from Hurricane import Path +from Hurricane import Occurrence +from Hurricane import UpdateSession +from Hurricane import Layer +from Hurricane import BasicLayer +from Hurricane import Net +from Hurricane import Pin +from Hurricane import Contact +from Hurricane import Segment +from Hurricane import Horizontal +from Hurricane import Vertical +from Hurricane import RoutingPad +from Hurricane import Instance +import CRL +from CRL import RoutingLayerGauge +import helpers +from helpers import trace +from helpers.io import ErrorMessage +from helpers.io import WarningMessage +from helpers.overlay import UpdateSession +import plugins.alpha.chip + +plugins.alpha.chip.importConstants( globals() ) + + +# -------------------------------------------------------------------- +# Class : "pads.Corner" + +class Corner ( object ): + + def __init__ ( self, corona, cornerType ): + self.type = cornerType + self.corona = corona + self.padCorner = None + + @property + def conf ( self ): return self.corona.conf + + def _getPoints ( self, axis ): + if self.type == SouthWest: + xCorner = self.conf.chipAb.getXMin() + axis + yCorner = self.conf.chipAb.getYMin() + axis + xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight + yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight + elif self.type == SouthEast: + xCorner = self.conf.chipAb.getXMax() - axis + yCorner = self.conf.chipAb.getYMin() + axis + xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight + yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight + elif self.type == NorthEast: + xCorner = self.conf.chipAb.getXMax() - axis + yCorner = self.conf.chipAb.getYMax() - axis + xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight + yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight + elif self.type == NorthWest: + xCorner = self.conf.chipAb.getXMin() + axis + yCorner = self.conf.chipAb.getYMax() - axis + xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight + yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight + return xCorner, yCorner, xBb, yBb + + def _createCorner ( self ): + for rail in self.corona.padRails: + net = rail[0] + layer = rail[1] + axis = rail[2] + width = rail[3] + xCorner, yCorner, xBb, yBb = self._getPoints( axis ) + Contact .create( net, layer, xCorner, yCorner, width, width ) + Horizontal.create( net, layer, yCorner, width, xCorner, xBb ) + Vertical .create( net, layer, xCorner, width, yCorner, yBb ) + + def _getTransformation ( self ): + if self.type == SouthWest: + name = 'padcorner_sw' + x = self.conf.chipAb.getXMin() + y = self.conf.chipAb.getYMin() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.ID + else: + orientation = Transformation.Orientation.R1 + x += self.padCorner.getAbutmentBox().getWidth() + elif self.type == SouthEast: + name = 'padcorner_se' + x = self.conf.chipAb.getXMax() + y = self.conf.chipAb.getYMin() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R1 + else: + orientation = Transformation.Orientation.R2 + x += self.padCorner.getAbutmentBox().getWidth() + y += self.padCorner.getAbutmentBox().getHeight() + elif self.type == NorthEast: + name = 'padcorner_ne' + x = self.conf.chipAb.getXMax() + y = self.conf.chipAb.getYMax() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R2 + else: + orientation = Transformation.Orientation.R3 + x -= self.padCorner.getAbutmentBox().getwidth() + y -= self.padCorner.getAbutmentBox().getHeight() + elif self.type == NorthWest: + name = 'padcorner_nw' + x = self.conf.chipAb.getXMin() + y = self.conf.chipAb.getYMax() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R3 + else: + orientation = Transformation.Orientation.ID + y -= self.padCorner.getAbutmentBox().getHeight() + return name, Transformation( self.corona.toGrid(x), self.corona.toGrid(y), orientation ) + + def _instanciateCorner ( self ): + name, transformation = self._getTransformation() + corner = Instance.create( self.conf.cell + , name, self.corona.padCorner + , transformation + , Instance.PlacementStatus.FIXED + ) + + def doLayout ( self ): + if self.corona.padCorner: self._instanciateCorner() + else: self._createCorner() + + +# -------------------------------------------------------------------- +# Class : "pads.Side" + +class Side ( object ): + + def __init__ ( self, corona, sideType ): + self.type = sideType + self.corona = corona + self.pins = [] + self.u = self.conf.ioPadHeight + self.spacerCount = 0 + self.gap = 0 + self.coreWires = [] + if self.type == North: + self.pads = self.corona.northPads + self.sideName = 'north' + self.sideLength = self.conf.chipAb.getWidth() + elif self.type == South: + self.pads = self.corona.southPads + self.sideName = 'south' + self.sideLength = self.conf.chipAb.getWidth() + elif self.type == East: + self.pads = self.corona.eastPads + self.sideName = 'east' + self.sideLength = self.conf.chipAb.getHeight() + elif self.type == West: + self.pads = self.corona.westPads + self.sideName = 'west' + self.sideLength = self.conf.chipAb.getHeight() + else: + raise ErrorMessage( 1, 'Pads.Side.__init__(): Invalid value for sideType ({})'.format(sideType)) + self.spacerNames = 'padspacer_' + self.sideName + '_%d' + + @property + def conf ( self ): return self.corona.conf + + def toGrid ( self, u ): return self.corona.toGrid( u ) + + def getAxis ( self, i ): + if self.type == North: return self.conf.chipAb.getYMax() - self.conf.ioPadHeight + self.corona.powerRails[i][2] + elif self.type == South: return self.conf.chipAb.getYMin() + self.conf.ioPadHeight - self.corona.powerRails[i][2] + elif self.type == East: return self.conf.chipAb.getXMax() - self.conf.ioPadHeight + self.corona.powerRails[i][2] + elif self.type == West: return self.conf.chipAb.getXMin() + self.conf.ioPadHeight - self.corona.powerRails[i][2] + else: + raise ErrorMessage( 1, 'Pads.Side.__init__(): Invalid value for sideType ({})'.format(sideType)) + return 0 + + def hasPad ( self, padInstance ): + for pad in self.pads: + if pad[1] == padInstance: + return True + return False + + def addCoreWire ( self, coreWire ): + self.coreWires.append( coreWire ) + return + + def updateGap ( self, gapWidth ): + self.gap = max( self.gap, gapWidth ) + return + + def _check ( self, checkSize, checkName ): + sideName = 'unknown' + chipSize = 0 + if self.type == North or self.type == South: + chipSize = self.conf.chipAb.getWidth() + sideName = 'wide' + elif self.type == East or self.type == West: + chipSize = self.conf.chipAb.getHeight() + sideName = 'tall' + if checkSize > chipSize: + sliceHeight = self.conf.sliceHeight + if checkSize % sliceHeight != 0: + checkSize += sliceHeight - (checkSize % sliceHeight) + raise ErrorMessage( 1, [ 'Chip is not {} enought to accomodate the {},' \ + .format(sideName,checkName) + , 'needs {}, but only has {}.' \ + .format( DbU.getValueString(checkSize), DbU.getValueString(chipSize) ) + ] ) + return False + return True + + def check ( self ): + self.validated = True + if self.type == North: + self.conf.validated = self._check \ + ( self.conf.coronaAb.getWidth() + 2*self.conf.ioPadHeight, 'core' ) + checkName = 'north pads' + elif self.type == East: + self.conf.validated = self._check \ + ( self.conf.coronaAb.getHeight() + 2*self.conf.ioPadHeight, 'core' ) + checkName = 'east pads' + elif self.type == South: checkName = 'south pads' + elif self.type == West: checkName = 'west pads' + self.conf.validated = self._check( len(self.pads) * self.conf.ioPadStep + + 2*self.conf.ioPadHeight + , checkName ) and self.conf.validated + return self.conf.validated + + def _fillPadSpacing ( self, gapWidth ): + + def _getWidth ( spacer ): return spacer.getAbutmentBox().getWidth() + + def _nextSpacer ( iPadSpacer ): + while iPadSpacer < len(self.corona.padSpacers) \ + and gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]): + iPadSpacer += 1 + return iPadSpacer + + if not self.corona.padSpacers: + self.u += gapWidth + return + iPadSpacer = 0 + iPadSpacer = _nextSpacer( iPadSpacer ) + while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0: + gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] ) + spacer = Instance.create( self.conf.cell + , self.spacerNames % self.spacerCount + , self.corona.padSpacers[iPadSpacer]) + self.spacerCount += 1 + self._placePad( spacer ) + if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]): + iPadSpacer = _nextSpacer( iPadSpacer ) + if gapWidth != 0: + raise ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \ + .format(self.sideName,DbU.getValueString(gapWidth)) ) + self.u += gapWidth + + def _placePad ( self, padInstance ): + if self.type == North: + x = self.conf.chipAb.getXMin() + self.u + y = self.conf.chipAb.getYMax() + + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.MY + else: + orientation = Transformation.Orientation.ID + y -= self.conf.ioPadHeight + + elif self.type == South: + x = self.conf.chipAb.getXMin() + self.u + y = self.conf.chipAb.getYMin() + + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.ID + else: + orientation = Transformation.Orientation.MY + y += self.conf.ioPadHeight + + elif self.type == West: + x = self.conf.chipAb.getXMin() + y = self.conf.chipAb.getYMin() + self.u + + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R3 + y += padInstance.getMasterCell().getAbutmentBox().getWidth() + else: + orientation = Transformation.Orientation.R1 + x += padInstance.getMasterCell().getAbutmentBox().getHeight() + + elif self.type == East: + x = self.conf.chipAb.getXMax() + y = self.conf.chipAb.getYMin() + self.u + + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R1 + else: + orientation = Transformation.Orientation.R3 + x -= padInstance.getMasterCell().getAbutmentBox().getHeight() + y += padInstance.getMasterCell().getAbutmentBox().getWidth() + + padInstance.setTransformation ( Transformation( self.toGrid(x), self.toGrid(y), orientation ) ) + padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED ) + + self.u += padInstance.getMasterCell().getAbutmentBox().getWidth() + + p = None + if self.conf.ioPadGauge.getName() == 'pxlib': + p = re.compile( r'p(?Pv[sd]{2}[ei])ck_px' ) + + if self.conf.ioPadGauge.getName().startswith('phlib'): + p = re.compile( r'p(?Pv[sd]{2})ck2_sp' ) + + if p: + m = p.match( padInstance.getMasterCell().getName() ) + + padName = 'pad' + if m: padName = m.group( 'power' ) + + padNet = padInstance.getMasterCell().getNet( padName ) + #print 'padName:', padName, 'padNet:', padNet + if padNet: + plug = padInstance.getPlug( padNet ) + chipNet = plug.getNet() + + if not chipNet and padNet.isGlobal(): + chipNet = padInstance.getCell().getNet( padNet.getName() ) + + if chipNet: + rp = RoutingPad.create( chipNet, Occurrence(plug), RoutingPad.BiggestArea ) + return + + def _placePads ( self ): + padLength = 0 + for pad in self.pads: padLength += pad[1].getMasterCell().getAbutmentBox().getWidth() + padSpacing = (self.sideLength - 2*self.conf.ioPadHeight - padLength) / (len(self.pads) + 1) + if self.conf.padsHavePosition: + position = self.u + for pad in self.pads: + trace( 550, '\tPlace pad {} @{}\n'.format(pad[1],DbU.getValueString(pad[0])) ) + if pad[0] < position: + pad[0] = position + trace( 550, '\tShift position @{}\n'.format(DbU.getValueString(pad[0])) ) + pad[0] = self.toGrid( pad[0] ) + position = pad[0] + pad[1].getMasterCell().getAbutmentBox().getWidth() + else: + position = self.u + for i in range(len(self.pads)): + position += padSpacing + self.pads[i][0] = self.toGrid( position ) + position += self.pads[i][1].getMasterCell().getAbutmentBox().getWidth() + for pad in self.pads: + self._fillPadSpacing( pad[0] - self.u ) + self._placePad( pad[1] ) + self._fillPadSpacing( self.sideLength - self.conf.ioPadHeight - self.u ) + + def _getUMin ( self, box ): + if self.type == North or self.type == South: + return box.getXMin() + return box.getYMin() + + def _getUMax ( self, box ): + if self.type == North or self.type == South: + return box.getXMax() + return box.getYMax() + + def _createSegment ( self, rail, uMin, uMax ): + net, layer, axis, width = rail + if self.conf.ioPadGauge.getName() == 'pxlib': + if net.isClock(): + uMin -= DbU.fromLambda(5.0) + uMax += DbU.fromLambda(5.0) + else: + uMin -= width/2 + uMax += width/2 + if self.type == North or self.type == South: + if self.type == North: + axis = self.conf.chipAb.getYMax() - axis + Horizontal.create( net, layer, axis, width, uMin, uMax ) + else: + if self.type == East: + axis = self.conf.chipAb.getXMax() - axis + Vertical.create( net, layer, axis, width, uMin, uMax ) + + def _routePads ( self ): + if self.type == South or self.type == North: + startCorner = self.conf.chipAb.getXMin() + stopCorner = self.conf.chipAb.getXMax() + elif self.type == West or self.type == East: + startCorner = self.conf.chipAb.getYMin() + stopCorner = self.conf.chipAb.getYMax() + else: + return + startCorner += self.conf.ioPadHeight + stopCorner -= self.conf.ioPadHeight + if len(self.pads) == 0: + return + padAb = self.conf.getInstanceAb( self.pads[0][1] ) + for irail in range(len(self.corona.padRails)): + self._createSegment( self.corona.padRails[ irail ] + , startCorner + , self._getUMin(padAb) ) + padAb = self.conf.getInstanceAb( self.pads[-1][1] ) + for irail in range(len(self.corona.padRails)): + self._createSegment( self.corona.padRails[ irail ] + , self._getUMax(padAb) + , stopCorner ) + for i in range(len(self.pads)-1): + padAb1 = self.conf.getInstanceAb( self.pads[i ][1] ) + padAb2 = self.conf.getInstanceAb( self.pads[i+1][1] ) + for rail in self.corona.padRails: + self._createSegment( rail, self._getUMax(padAb1), self._getUMin(padAb2) ) + + def doLayout ( self ): + self._placePads() + if not self.corona.padSpacers: + self._routePads() + + def drawCoreWires ( self ): + trace( 550, ',+', '\tSide.drawCoreWire()\n' ) + if self.type == West or self.type == East: + trace( 550, '\tSort East/West\n' ) + self.coreWires.sort( key=lambda wire: wire.bbSegment.getCenter().getY() ) + if self.type == North or self.type == South: + trace( 550, '\tSort North/South\n' ) + self.coreWires.sort( key=lambda wire: wire.bbSegment.getCenter().getX() ) + for wire in self.coreWires: + wire.updateInCorona() + size = len(self.coreWires) + offset = 0 + for i in range(size): + if self.coreWires[i].inCoronaRange: break + offset += 1 + for i in range(offset): + self.coreWires[i].setOffset( i+1, CoreWire.AtBegin ) + offset = 0 + for i in range(1,size+1): + if self.coreWires[-i].inCoronaRange: break + offset += 1 + for i in range(offset): + self.coreWires[ -(offset+1) ].setOffset( i+1, CoreWire.AtEnd ) + for wire in self.coreWires: + if self.type == West or self.type == East: + trace( 550, '\t| %s %s %d %s inRange:%s\n' % ( wire.chipNet.getName() + , DbU.getValueString(wire.bbSegment.getCenter().getY()) + , wire.count + , wire.padSegment.getLayer() + , wire.inCoronaRange ) ) + if self.type == North or self.type == South: + trace( 550, '\t| %s %s %d %s inRange:%s\n' % ( wire.chipNet.getName() + , DbU.getValueString(wire.bbSegment.getCenter().getX()) + , wire.count + , wire.padSegment.getLayer() + , wire.inCoronaRange ) ) + wire.drawWire() + trace( 550, '-' ) + + +# -------------------------------------------------------------------- +# Class : "pads.CoreWire" + +class CoreWire ( object ): + + # Should be read from the symbolic technology rules. + viaPitch = DbU.fromLambda( 4.0 ) + + NoOffset = 0x0000 + AtBegin = 0x0001 + AtEnd = 0x0002 + + def __init__ ( self, corona, chipNet, padSegment, bbSegment, side, preferredDir, count ): + self.corona = corona + self.chipNet = chipNet + self.padSegment = padSegment + self.bbSegment = bbSegment + self.offset = 0 + self.offsetType = CoreWire.NoOffset + self.side = side + self.preferredDir = preferredDir + self.inCoronaRange = True + self.arraySize = None + self.count = count + + @property + def conf ( self ): return self.corona.conf + + def updateInCorona ( self ): + coronaAb = self.conf.getInstanceAb( self.conf.icorona ) + if self.side == South or self.side == North: + xCoronaPin = self.bbSegment.getCenter().getX() + if xCoronaPin <= coronaAb.getXMin(): self.inCoronaRange = False + elif xCoronaPin >= coronaAb.getXMax(): self.inCoronaRange = False + if self.side == East or self.side == West: + yCoronaPin = self.bbSegment.getCenter().getY() + if yCoronaPin <= coronaAb.getYMin(): self.inCoronaRange = False + elif yCoronaPin >= coronaAb.getYMax(): self.inCoronaRange = False + + def setOffset ( self, offset, offsetType ): + self.offset = offset + self.offsetType = offsetType + + def _computeCoreLayers ( self ): + rg = self.conf.routingGauge + mask = self.padSegment.getLayer().getMask() + trace( 550, ',+', '\tCoreWire._computeCoreLayers()\n' ) + trace( 550, '\tbbSegment: {}\n'.format(self.bbSegment) ) + self.symSegmentLayer = None + for layerGauge in rg.getLayerGauges(): + if layerGauge.getDepth() > self.conf.topLayerDepth: break + if layerGauge.getLayer().getMask() == mask: + self.symSegmentLayer = layerGauge.getLayer() + if self.preferredDir: + self.symContactLayer = self.symSegmentLayer + if self.side & (West|East): + self.symContactSize = ( layerGauge.getWireWidth(), self.bbSegment.getHeight() ) + else: + self.symContactSize = ( self.bbSegment.getWidth(), layerGauge.getWireWidth() ) + else: + depth = layerGauge.getDepth() + if layerGauge.getDepth() + 1 > self.conf.topLayerDepth: + self.symSegmentLayer = rg.getLayerGauge( depth-1 ).getLayer() + depth -= 1 + else: + self.symSegmentLayer = rg.getLayerGauge( depth+1 ).getLayer() + self.symContactLayer = rg.getContactLayer( depth ) + if self.side & (West|East): + self.symContactSize = ( self.bbSegment.getHeight(), self.bbSegment.getHeight() ) + else: + self.symContactSize = ( self.bbSegment.getWidth(), self.bbSegment.getWidth() ) + + contactMinSize = 2*self.symContactLayer.getEnclosure( self.symSegmentLayer.getBasicLayer() + , Layer.EnclosureH|Layer.EnclosureV ) \ + + self.symContactLayer.getMinimalSize() + arrayWidth = self.symContactSize[0] + arrayCount = (arrayWidth - contactMinSize) / CoreWire.viaPitch + trace( 550, '\tCoreWire.viaPitch: {}l\n'.format(DbU.toLambda(CoreWire.viaPitch)) ) + trace( 550, '\tcontactMinSize: {}l, arrayWidth: {}l, arrayCount: {}\n' \ + .format(DbU.toLambda(contactMinSize),DbU.toLambda(arrayWidth),arrayCount) ) + if arrayCount < 0: arrayCount = 0 + if arrayCount < 3: + if self.side & (North|South): + self.arraySize = ( arrayCount+1, 2 ) + else: + self.arraySize = ( 2, arrayCount+1 ) + trace( 550, '\tarraySize = ({},{})\n'.format(self.arraySize[0], self.arraySize[1]) ) + trace( 550, ',-' ) + return + raise ErrorMessage( 1, 'CoreWire._computeCoreLayers(): Layer of IO pad segment "%s" is not in routing gauge.' \ + .format(self.chipNet.getName()) ) + trace( 550, ',-' ) + + def drawWire ( self ): + trace( 550, ',+', '\tCoreWire.drawWire(): chip:"{}"\n'.format(self.chipNet.getName()) ) + coronaAb = self.conf.getInstanceAb( self.conf.icorona ) + self._computeCoreLayers() + padLayer = self.padSegment.getLayer() + if not isinstance(padLayer,BasicLayer): + padLayer = padLayer.getBasicLayer() + if self.side == West or self.side == East: + flags = OnHorizontalPitch + hPitch = self.conf.getPitch( self.symSegmentLayer ) + vPitch = self.conf.getPitch( self.padSegment.getLayer() ) + yCore = self.conf.toCoronaPitchInChip( self.bbSegment.getCenter().getY(), self.symSegmentLayer ) + if self.offset: + if self.offsetType == CoreWire.AtBegin: + yCore += 2*hPitch*self.offset + else: + yCore -= 2*hPitch*self.offset + if self.side == West: + accessDirection = Pin.Direction.WEST + xPadMin = self.bbSegment.getXMin() + xContact = self.corona.coreSymBb.getXMin() - self.offset * 2*vPitch + xPadMax = xContact + xCore = coronaAb.getXMin() + if not self.preferredDir: + xPadMax += self.bbSegment.getHeight()/2 + else: + accessDirection = Pin.Direction.EAST + xPadMax = self.bbSegment.getXMax() + xContact = self.corona.coreSymBb.getXMax() + self.offset * 2*vPitch + xPadMin = xContact + xCore = coronaAb.getXMax() + if not self.preferredDir: + xPadMin -= self.bbSegment.getHeight()/2 + hReal = Horizontal.create( self.chipNet + , self.padSegment.getLayer() + , self.bbSegment.getCenter().getY() + , self.bbSegment.getHeight() + , xPadMin + , xPadMax + ) + trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) ) + if self.arraySize: + contacts = self.conf.coronaContactArray( self.chipNet + , self.symContactLayer + , xContact + , yCore + , self.arraySize + , flags + ) + vStrapBb = Box() + for contact in contacts: + vStrapBb.merge( contact.getBoundingBox() ) + else: + contact = self.conf.coronaContact( self.chipNet + , self.symContactLayer + , xContact + , yCore + , self.symContactSize[0] + , self.symContactSize[1] + , flags + ) + vStrapBb = contact.getBoundingBox( padLayer ) + hRealBb = hReal.getBoundingBox( padLayer ) + self.conf.icorona.getTransformation().applyOn( vStrapBb ) + vStrapBb.merge( vStrapBb.getXMin(), hRealBb.getYMin() ) + vStrapBb.merge( vStrapBb.getXMin(), hRealBb.getYMax() ) + if self.padSegment.getLayer().isSymbolic(): + vStrapBb.inflate( 0, -self.padSegment.getLayer().getExtentionCap() + , 0, -self.padSegment.getLayer().getExtentionCap() ) + Vertical.create( self.chipNet + , self.padSegment.getLayer() + , vStrapBb.getCenter().getX() + , vStrapBb.getWidth() + , vStrapBb.getYMin() + , vStrapBb.getYMax() + ) + if self.arraySize: + if self.side == West: xContact = min( xContact, vStrapBb.getXMin() ) + else: xContact = max( xContact, vStrapBb.getXMax() ) + self.conf.coronaHorizontal( self.chipNet + , self.symSegmentLayer + , yCore + , self.bbSegment.getHeight() + , xContact + , xCore + ) + trace( 550, '\tCORONA PIN: {} {}\n'.format(self.chipNet, self.count) ) + pin = self.conf.coronaPin( self.chipNet + , self.count + , accessDirection + , self.symSegmentLayer + , xCore + , yCore + , DbU.fromLambda( 1.0 ) + , self.bbSegment.getHeight() + ) + else: + flags = OnVerticalPitch + hPitch = self.conf.getPitch( self.padSegment.getLayer() ) + vPitch = self.conf.getPitch( self.symSegmentLayer ) + trace( 550, '\t%s translated of %s\n' % (self.symSegmentLayer, DbU.getValueString( 2*vPitch*self.offset )) ) + xCore = self.conf.toCoronaPitchInChip( self.bbSegment.getCenter().getX(), self.symSegmentLayer ) + if self.offset: + if self.offsetType == CoreWire.AtBegin: + xCore += 2*vPitch*self.offset + else: + xCore -= 2*vPitch*self.offset + if self.side == South: + accessDirection = Pin.Direction.SOUTH + yPadMin = self.bbSegment.getYMin() + yPadMax = self.corona.coreSymBb.getYMin() - self.offset * 2*hPitch + yContact = yPadMax + yCore = coronaAb.getYMin() + if not self.preferredDir: + yPadMax += self.bbSegment.getWidth()/2 + else: + accessDirection = Pin.Direction.NORTH + yPadMax = self.bbSegment.getYMax() + yPadMin = self.corona.coreSymBb.getYMax() + self.offset * 2*hPitch + yContact = yPadMin + yCore = coronaAb.getYMax() + if not self.preferredDir: + yPadMin -= self.bbSegment.getWidth()/2 + vReal = Vertical.create( self.chipNet + , self.padSegment.getLayer() + , self.bbSegment.getCenter().getX() + , self.bbSegment.getWidth() + , yPadMin + , yPadMax + ) + trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) ) + if self.arraySize: + contacts = self.conf.coronaContactArray( self.chipNet + , self.symContactLayer + , xCore + , yContact + , self.arraySize + , flags + ) + hStrapBb = Box() + for contact in contacts: + hStrapBb.merge( contact.getBoundingBox() ) + else: + contact = self.conf.coronaContact( self.chipNet + , self.symContactLayer + , self.bbSegment.getCenter().getX() + , yContact + , self.symContactSize[0] + , self.symContactSize[1] + , flags + ) + hStrapBb = contact.getBoundingBox( padLayer ) + vRealBb = vReal.getBoundingBox() + self.conf.icorona.getTransformation().applyOn( hStrapBb ) + hStrapBb.merge( vRealBb.getXMin(), hStrapBb.getYMin() ) + hStrapBb.merge( vRealBb.getXMax(), hStrapBb.getYMin() ) + if self.padSegment.getLayer().isSymbolic(): + hStrapBb.inflate( -self.padSegment.getLayer().getExtentionCap(), 0 + , -self.padSegment.getLayer().getExtentionCap(), 0 ) + Horizontal.create( self.chipNet + , self.padSegment.getLayer() + , hStrapBb.getCenter().getY() + , hStrapBb.getHeight() + , hStrapBb.getXMin() + , hStrapBb.getXMax() + ) + if self.arraySize: + if self.side == South: yContact = min( yContact, hStrapBb.getYMin() ) + else: yContact = max( yContact, hStrapBb.getYMax() ) + trace( 550, '\txCore: %sl %s\n' % (DbU.toLambda(xCore), DbU.getValueString(xCore)) ) + self.conf.coronaVertical( self.chipNet + , self.symSegmentLayer + , xCore + , self.bbSegment.getWidth() + , yContact + , yCore + ) + pin = self.conf.coronaPin( self.chipNet + , self.count + , accessDirection + , self.symSegmentLayer + , xCore + , yCore + , self.bbSegment.getWidth() + , DbU.fromLambda( 1.0 ) + ) + if self.side & North: self.corona.northSide.pins.append( pin ) + if self.side & South: self.corona.southSide.pins.append( pin ) + if self.side & East : self.corona.eastSide .pins.append( pin ) + if self.side & West : self.corona.westSide .pins.append( pin ) + trace( 550, '-' ) + + +# -------------------------------------------------------------------- +# Class : "pads.Corona" + +class Corona ( object ): + + def __init__ ( self, conf ): + + def _cmpPad ( pad1, pad2): + width1 = pad1.getAbutmentBox().getWidth() + width2 = pad2.getAbutmentBox().getWidth() + if width1 == width2: return 0 + if width1 > width2: return -1 + return 1 + + def _dupPads ( padsConf ): + duplicateds = [] + for ioPadConf in padsConf: + for padInstance in ioPadConf.pads: + position = 0 if ioPadConf.position is None else ioPadConf.position + duplicateds.append( [ position, padInstance ] ) + return duplicateds + + self.conf = conf + self.conf.validated = False + self.northPads = _dupPads( self.conf.chipConf.northPads ) + self.southPads = _dupPads( self.conf.chipConf.southPads ) + self.eastPads = _dupPads( self.conf.chipConf.eastPads ) + self.westPads = _dupPads( self.conf.chipConf.westPads ) + self.northSide = Side( self, North ) + self.southSide = Side( self, South ) + self.eastSide = Side( self, East ) + self.westSide = Side( self, West ) + self.corners = { SouthWest : Corner( self, SouthWest ) + , SouthEast : Corner( self, SouthEast ) + , NorthWest : Corner( self, NorthWest ) + , NorthEast : Corner( self, NorthEast ) + } + self.padLib = None + self.padOrient = Transformation.Orientation.ID + self.padSpacers = [] + self.padCorner = [] + self.padRails = [] # [ , [net, layer, axis, width] ] + if Cfg.hasParameter('chip.padCoreSide'): + if Cfg.getParamString('chip.padCoreSide').asString().lower() == 'south': + self.padOrient = Transformation.Orientation.MY + self._allPadsAnalysis() + if Cfg.hasParameter('chip.padSpacers'): + for spacerName in Cfg.getParamString('chip.padSpacers').asString().split(','): + spacerCell = self.padLib.getCell( spacerName ) + if spacerCell: self.padSpacers.append( spacerCell ) + else: + raise ErrorMessage( 1, 'Corona.__init__(): Missing spacer cell "{}"'.format(spacerName) ) + self.padSpacers.sort( _cmpPad ) + if Cfg.hasParameter('chip.padCorner'): + self.padCorner = self.padLib.getCell( Cfg.getParamString('chip.padCorner').asString() ) + + def toGrid ( self, u ): return u - (u % self.conf.ioPadPitch) + + def validate ( self ): + self._allPadsAnalysis() + self.conf.validated = self.northSide.check() + self.conf.validated = self.southSide.check() and self.conf.validated + self.conf.validated = self.eastSide.check() and self.conf.validated + self.conf.validated = self.westSide.check() and self.conf.validated + return self.conf.validated + + def hasNorthPad ( self, padInstance ): return self.northSide.hasPad(padInstance) + def hasSouthPad ( self, padInstance ): return self.southSide.hasPad(padInstance) + def hasEastPad ( self, padInstance ): return self.eastSide.hasPad(padInstance) + def hasWestPad ( self, padInstance ): return self.westSide.hasPad(padInstance) + + def hasPad ( self, padInstance ): + if self.hasNorthPad(padInstance): return True + if self.hasSouthPad(padInstance): return True + if self.hasEastPad (padInstance): return True + if self.hasWestPad (padInstance): return True + return False + + def _allPadsAnalysis ( self ): + for pad in self.southPads: + self._padAnalysis( pad[1] ) + if self.padRails: return + for pad in self.northPads: + self._padAnalysis( pad[1] ) + if self.padRails: return + for pad in self.eastPads: + self._padAnalysis( pad[1] ) + if self.padRails: return + for pad in self.westPads: + self._padAnalysis( pad[1] ) + if self.padRails: return + + def _padAnalysis ( self, padInstance ): + if self.padRails: return + padCell = padInstance.getMasterCell() + ab = padCell.getAbutmentBox() + if not self.padLib: self.padLib = padCell.getLibrary() + for plug in padInstance.getPlugs(): + for component in plug.getMasterNet().getComponents(): + if isinstance(component,Horizontal): + hspan = Interval( component.getBoundingBox().getXMin() + , component.getBoundingBox().getXMax() ) + # Specific hack for Alliance pxlib pad library. + if self.conf.ioPadGauge.getName() == 'pxlib': + if plug.getMasterNet().isClock(): + hspan.inflate( DbU.fromLambda(5.0) ) + else: + hspan.inflate( component.getWidth() / 2 ) + if hspan.contains( ab.getXMin() ) or hspan.contains( ab.getXMax() ): + duplicate = False + if self.padOrient == Transformation.Orientation.ID: + axis = component.getY() + else: + axis = self.conf.ioPadHeight - component.getY() + for rail in self.padRails: + if rail[0] == plug.getNet() \ + and rail[1] == component.getLayer() \ + and rail[2] == axis: + duplicate = True + break + if not duplicate: + net = plug.getNet() + if not net: + if plug.getMasterNet().isGlobal(): + net = self.conf.cell.getNet( plug.getMasterNet().getName() ) + if not net: + raise ErrorMessage( 1, 'PadsCorona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \ + % plug.getMasterNet().getName(), padCell.getName() ) + else: + raise ErrorMessage( 1, 'PadsCorona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \ + % plug.getMasterNet().getName(), padCell.getName() ) + if net: + self.padRails.append( ( net + , component.getLayer() + , axis + , component.getWidth() ) ) + + def _createCoreWire ( self, chipIntNet, padNet, padInstance, count ): + side = None + if self.hasSouthPad(padInstance): side = self.southSide + elif self.hasNorthPad(padInstance): side = self.northSide + elif self.hasEastPad (padInstance): side = self.eastSide + elif self.hasWestPad (padInstance): side = self.westSide + if not side: return count + innerBb = self.conf.chip.getAbutmentBox().inflate( -self.conf.ioPadHeight ) + rg = self.conf.routingGauge + hsegments = {} + vsegments = {} + trace( 550, '\tinnerBb: {}\n'.format(innerBb) ) + for component in padNet.getExternalComponents(): + if isinstance(component,Segment) or isinstance(component,Contact): + bb = component.getBoundingBox() + padInstance.getTransformation().applyOn( bb ) + trace( 550, '\t| External:{} bb:{}\n'.format(component,bb) ) + if bb.intersect(innerBb): + trace( 550, '\t| Accepted.\n' ) + lg = rg.getLayerGauge( component.getLayer() ) + depth = lg.getDepth() + if depth > self.conf.topLayerDepth: continue + if lg.getDirection() == RoutingLayerGauge.Vertical: + if not vsegments.has_key(depth): vsegments[ depth ] = [] + vsegments[ depth ].append( (component,bb) ) + else: + if not hsegments.has_key(depth): hsegments[ depth ] = [] + hsegments[ depth ].append( (component,bb) ) + gapWidth = 0 + segments = None + inPreferredDir = False + if side.type == North or side.type == South: + if len(vsegments): + inPreferredDir = True + segments = vsegments[ min(vsegments.keys()) ] + elif len(hsegments): + segments = hsegments[ min(hsegments.keys()) ] + else: + if len(hsegments): + inPreferredDir = True + segments = hsegments[ min(hsegments.keys()) ] + elif len(vsegments): + segments = vsegments[ min(vsegments.keys()) ] + coreWires = [] + if segments: + for segment, bb in segments: + if not inPreferredDir: + if side.type == North or side.type == South: + trace( 550, '\tNorth/South "{}" but RDir H, gapWidth: {}\n' \ + .format(chipIntNet.getName(),DbU.getValueString(bb.getWidth()) ) ) + side.updateGap( bb.getWidth() ) + else: + trace( 550, '\tEast/West "{}" but RDir V, gapWidth: {}\n' \ + .format(chipIntNet.getName(),DbU.getValueString(bb.getHeight())) ) + side.updateGap( bb.getHeight() ) + side.addCoreWire( CoreWire( self, chipIntNet, segment, bb, side.type, inPreferredDir, count ) ) + count += 1 + else: + if not (chipIntNet.isGlobal() or chipIntNet.isSupply() or chipIntNet.isClock()): + raise ErrorMessage( 1, [ 'PadsCorona._createCoreWire(): In I/O pad "{}" ({},{}),' \ + .format( padInstance.getMasterCell().getName() + , padInstance.getName(), padInstance.getTransformation() ) + , 'connector "{}" has no suitable segment for net "{}".' \ + .format( padNet, chipIntNet.getName() ) + ] ) + return count + + def _placeInnerCorona ( self ): + trace( 550, ',+', '\tCorona._placeInnerCorona()\n' ) + rg = self.conf.routingGauge + coronaSouthGap = 0 + for layerGauge in rg.getLayerGauges(): + self.southSide.gap = max( self.southSide.gap, layerGauge.getPitch() * 6 ) + self.northSide.gap = self.southSide.gap + self.eastSide.gap = self.southSide.gap + self.westSide.gap = self.southSide.gap + for coronaPlug in self.conf.icorona.getPlugs(): + chipIntNet = coronaPlug.getNet() + if not chipIntNet: + trace( 550, '-' ) + raise ErrorMessage( 1, 'PadsCorona._placeInnerCorona(): Corona net "{}" is not connected to a pad.' \ + .format(coronaPlug.getMasterNet().getName()) ) + continue + padConnected = 0 + doneInstances = [] + trace( 550, '\tConnexions on chipIntNet: {}\n'.format(chipIntNet) ) + for chipPlug in chipIntNet.getPlugs(): + trace( 550, '\t| chipPlug: {}\n'.format(chipPlug) ) + doneInstances.append( chipPlug.getInstance() ) + padNet = chipPlug.getMasterNet() + padConnected = self._createCoreWire( chipIntNet, padNet, doneInstances[-1], padConnected ) + if chipIntNet.isGlobal(): + for instance in self.conf.cell.getInstances(): + if instance in doneInstances: continue + doneInstances.append( instance ) + padNet = instance.getMasterCell().getNet( chipIntNet.getName() ) + if not padNet: continue + padConnected = self._createCoreWire( chipIntNet, padNet, doneInstances[-1], padConnected ) + if padConnected == 0: + trace( 550, '-' ) + raise ErrorMessage( 1, 'PadsCorona._placeInnerCorona(): Chip net "{}" is not connected to a pad.' \ + .format(chipIntNet.getName()) ) + self.conf.setupCorona( self.westSide.gap, self.southSide.gap, self.eastSide.gap, self.northSide.gap ) + self.coreSymBb = self.conf.getInstanceAb( self.conf.icorona ) + self.coreSymBb.inflate( self.conf.toSymbolic( self.westSide.gap /2, Superior ) + , self.conf.toSymbolic( self.southSide.gap/2, Superior ) + , self.conf.toSymbolic( self.eastSide.gap /2, Inferior ) + , self.conf.toSymbolic( self.northSide.gap/2, Inferior ) ) + self.southSide.drawCoreWires() + self.northSide.drawCoreWires() + self.eastSide .drawCoreWires() + self.westSide .drawCoreWires() + if len(self.southSide.coreWires) \ + and len(self.westSide .coreWires) \ + and not self.southSide.coreWires[0].inCoronaRange \ + and not self.westSide .coreWires[0].inCoronaRange: + print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on south-east corner are outside corona range.' + , 'This will generate a short-circuit between S:"{}" and W:"{}".' \ + .format( self.southSide.coreWires[0].chipNet.getName() + , self.westSide .coreWires[0].chipNet.getName()) ] )) + if len(self.southSide.coreWires) \ + and len(self.eastSide .coreWires) \ + and not self.southSide.coreWires[-1].inCoronaRange \ + and not self.eastSide .coreWires[ 0].inCoronaRange: + print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on south-west corner are outside corona range.' + , 'This will generate a short-circuit between S:"{}" and E:"{}.' \ + .format( self.southSide.coreWires[-1].chipNet.getName() + , self.eastSide .coreWires[ 0].chipNet.getName()) ] )) + if len(self.northSide.coreWires) \ + and len(self.westSide .coreWires) \ + and not self.northSide.coreWires[ 0].inCoronaRange \ + and not self.westSide .coreWires[-1].inCoronaRange: + print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on north-east corner are outside corona range.' + , 'This will generate a short-circuit between N:"%s" and W:"%s".' % \ + ( self.northSide.coreWires[ 0].chipNet.getName() + , self.westSide .coreWires[-1].chipNet.getName()) ] )) + if len(self.northSide.coreWires) \ + and len(self.eastSide .coreWires) \ + and not self.northSide.coreWires[-1].inCoronaRange \ + and not self.eastSide .coreWires[-1].inCoronaRange: + print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on north-west corner are outside corona range.' + , 'This will generate a short-circuit between N:"%s" and E:"%s.' % \ + ( self.northSide.coreWires[-1].chipNet.getName() + , self.eastSide .coreWires[-1].chipNet.getName()) ] )) + trace( 550, '-' ) + + def doLayout ( self ): + if not self.conf.validated: return + with UpdateSession(): + for corner in self.corners.values(): + corner.doLayout() + self.northSide.doLayout() + self.southSide.doLayout() + self.eastSide.doLayout() + self.westSide.doLayout() + self._placeInnerCorona() + self.conf.chip.setRouted( True ) diff --git a/cumulus/src/plugins/alpha/chip/power.py b/cumulus/src/plugins/alpha/chip/power.py new file mode 100644 index 00000000..90457839 --- /dev/null +++ b/cumulus/src/plugins/alpha/chip/power.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# +# This file is part of the Coriolis Software. +# Copyright (c) UPMC 2014-2018, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/chip/blockpower.py" | +# +-----------------------------------------------------------------+ + + +import sys +from Hurricane import DbU +from Hurricane import Point +from Hurricane import Transformation +from Hurricane import Box +from Hurricane import Interval +from Hurricane import Path +from Hurricane import Occurrence +from Hurricane import UpdateSession +from Hurricane import Net +from Hurricane import Contact +from Hurricane import Horizontal +from Hurricane import Vertical +from Hurricane import Query +import CRL +import helpers +from helpers import trace +from helpers.io import ErrorMessage +from helpers.io import WarningMessage +from helpers.overlay import UpdateSession +import plugins +import plugins.chip + +plugins.chip.importConstants( globals() ) + + +# -------------------------------------------------------------------- +# Class : "power.Side" + +class Side ( object ): + + def __init__ ( self, block, side, net, metal ): + self.block = block + self.side = side + self.net = net + self.metal = metal + self.deltaWidth = metal.getExtentionWidth()*2 + self.terminals = [] + + def addTerminal ( self, position, width ): + toMerge = Interval( position-width/2, position+width/2 ) + length = len(self.terminals) + imerge = length + ichunk = 0 + while ichunk < length: + if imerge == length: + if toMerge.getVMax() < self.terminals[ichunk][0].getVMin(): + self.terminals.insert( ichunk, [ toMerge, None ] ) + imerge = ichunk + length += 1 + break + if toMerge.intersect(self.terminals[ichunk][0]): + imerge = ichunk + self.terminals[ichunk][0].merge( toMerge ) + else: + if toMerge.getVMax() >= self.terminals[ichunk][0].getVMin(): + self.terminals[imerge][0].merge( self.terminals[ichunk][0] ) + del self.terminals[ichunk] + length -= 1 + continue + else: + break + ichunk += 1 + if ichunk == length: + self.terminals.append( [ toMerge, None ] ) + + def doLayout ( self ): + if self.side == West: + width = 0 + x = self.block.bb.getXMin() + elif self.side == East: + width = 0 + x = self.block.bb.getXMax() + elif self.side == South: + height = 0 + y = self.block.bb.getYMin() + elif self.side == North: + height = 0 + y = self.block.bb.getYMax() + minWidth = DbU.fromLambda( 6.0 ) + for terminal in self.terminals: + if self.side == West or self.side == East: + center = Point( x, terminal[0].getCenter() ) + height = terminal[0].getSize() - self.deltaWidth + if height < minWidth: height = minWidth + elif self.side == North or self.side == South: + center = Point( terminal[0].getCenter(), y ) + width = terminal[0].getSize() - self.deltaWidth + if width < minWidth: width = minWidth + self.block.path.getTransformation().applyOn( center ) + contact = Contact.create( self.net, self.metal, center.getX(), center.getY(), width, height ) + terminal[ 1 ] = contact + + +# -------------------------------------------------------------------- +# Class : "power.Plane" + +class Plane ( object ): + + Horizontal = 0001 + Vertical = 0002 + + def __init__ ( self, block, metal ): + self.block = block + self.metal = metal + self.sides = {} + + def addTerminal ( self, net, direction, bb ): + if not self.sides.has_key(net): + self.sides[ net ] = { North : Side(self.block,North,net,self.metal) + , South : Side(self.block,South,net,self.metal) + , East : Side(self.block,East ,net,self.metal) + , West : Side(self.block,West ,net,self.metal) + } + sides = self.sides[ net ] + if direction == Plane.Horizontal: + if bb.getXMin() <= self.block.bb.getXMin(): + sides[West].addTerminal( bb.getCenter().getY(), bb.getHeight() ) + if bb.getXMax() >= self.block.bb.getXMax(): + sides[East].addTerminal( bb.getCenter().getY(), bb.getHeight() ) + if direction == Plane.Vertical: + if bb.getYMin() <= self.block.bb.getYMin(): + sides[South].addTerminal( bb.getCenter().getX(), bb.getWidth() ) + if bb.getYMax() >= self.block.bb.getYMax(): + sides[North].addTerminal( bb.getCenter().getX(), bb.getWidth() ) + + def doLayout ( self ): + for sidesOfNet in self.sides.values(): + for side in sidesOfNet.values(): + side.doLayout() + + +# -------------------------------------------------------------------- +# Class : "power.Plane" + +class GoCb ( object ): + + def __init__ ( self, block ): + self.block = block + + def __call__ ( self, query, go ): + direction = None + if isinstance(go,Horizontal): direction = Plane.Horizontal + if isinstance(go,Vertical): direction = Plane.Vertical + if not direction: return + rootNet = None + if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.block.conf.coronaVdd + if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.block.conf.coronaVss + if not rootNet: return + if self.block.activePlane: + bb = go.getBoundingBox( self.block.activePlane.metal.getBasicLayer() ) + query.getPath().getTransformation().applyOn( bb ) + self.block.activePlane.addTerminal( rootNet, direction, bb ) + else: + print WarningMessage( 'BlockPower.GoCb() callback called without an active plane.' ) + return + + +# -------------------------------------------------------------------- +# Class : "power.Builder" + +class Builder ( object ): + + def __init__ ( self, conf ): + self.conf = conf + self.path = Path( self.conf.icore ) + self.block = self.path.getTailInstance().getMasterCell() + self.bb = self.block.getAbutmentBox() + self.planes = {} + self.activePlane = None + for layerGauge in self.conf.routingGauge.getLayerGauges(): + self.planes[ layerGauge.getLayer().getName() ] = Plane( self, layerGauge.getLayer() ) + + def connectPower ( self ): + if not self.conf.coronaVdd or not self.conf.coronaVss: + raise ErrorMessage( 1, 'Cannot build block power terminals as core vdd and/or vss are not known.' ) + return + goCb = GoCb( self ) + query = Query() + query.setGoCallback( goCb ) + query.setCell( self.block ) + query.setArea( self.block.getAbutmentBox() ) + query.setFilter( Query.DoComponents|Query.DoTerminalCells ) + for layerGauge in self.conf.routingGauge.getLayerGauges(): + self.activePlane = self.planes[ layerGauge.getLayer().getName() ] + query.setBasicLayer( layerGauge.getLayer().getBasicLayer() ) + query.doQuery() + self.activePlane = None + + def connectClock ( self ): + if not self.conf.useClockTree: + print WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." ) + return + if not self.conf.coronaCk: + raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' ) + return + blockCk = None + for plug in self.path.getTailInstance().getPlugs(): + if plug.getNet() == self.conf.coronaCk: + blockCk = plug.getMasterNet() + if not blockCk: + raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \ + .format(self.path.getTailInstance().getName(),self.ck.getName()) ) + return + htPlugs = [] + ffPlugs = [] + for plug in blockCk.getPlugs(): + if not plug.getInstance().isTerminalNetlist(): continue + htPlugs.append( plug ) + if len(htPlugs) != 1: + message = 'Clock "{}" of block "{}" is not organized as a H-Tree.' \ + .format(blockCk.getName(),self.path.getTailInstance().getName()) + for plug in htPlugs: + message += '\n - {}'.format(plug) + raise ErrorMessage( 1, message ) + return + with UpdateSession(): + bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], self.path) + , self.conf.coronaCk + , 0 ) + blockAb = self.block.getAbutmentBox() + self.path.getTransformation().applyOn( blockAb ) + layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth) + contact = Contact.create( self.conf.coronaCk + , self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth) + , bufferRp.getX() + , blockAb.getYMax() + , layerGauge.getViaWidth() + , layerGauge.getViaWidth() + ) + segment = self.conf.createVertical( bufferRp, contact, bufferRp.getX(), 0 ) + self.activePlane = self.planes[ layerGauge.getLayer().getName() ] + bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() ) + self.path.getTransformation().getInvert().applyOn( bb ) + self.activePlane.addTerminal( self.conf.coronaCk, Plane.Vertical, bb ) + + def doLayout ( self ): + with UpdateSession(): + for plane in self.planes.values(): + plane.doLayout() diff --git a/cumulus/src/plugins/alpha/core2chip/cmos.py b/cumulus/src/plugins/alpha/core2chip/cmos.py index 3cb62880..223c2a9e 100644 --- a/cumulus/src/plugins/alpha/core2chip/cmos.py +++ b/cumulus/src/plugins/alpha/core2chip/cmos.py @@ -88,18 +88,18 @@ class CoreToChip ( BaseCoreToChip ): coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName ) coronaNet.setExternal( True ) coronaNet.setGlobal ( True ) - coronaNet.setType ( Net.Type.POWER ) + coronaNet.setType ( Net.Type.GROUND ) self.icore.getPlug( coreNet ).setNet( coronaNet ) if not chipNet: chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName ) chipNet.setExternal( True ) - chipNet.setType ( Net.Type.POWER ) + chipNet.setType ( Net.Type.GROUND ) self.icorona.getPlug( coronaNet ).setNet( chipNet ) self.ringNetNames['vssi'] = chipNet if not padNet: padNet = Net.create( self.chip, ioPadConf.padSupplyNetName ) padNet.setExternal( True ) - padNet.setType ( Net.Type.POWER ) + padNet.setType ( Net.Type.GROUND ) self.ringNetNames['vsse'] = padNet ioPadConf.pads.append( Instance.create( self.chip , 'p_vssick_{}'.format(ioPadConf.index) diff --git a/cumulus/src/plugins/alpha/core2chip/core2chip.py b/cumulus/src/plugins/alpha/core2chip/core2chip.py index 63922a0a..7d818736 100644 --- a/cumulus/src/plugins/alpha/core2chip/core2chip.py +++ b/cumulus/src/plugins/alpha/core2chip/core2chip.py @@ -50,12 +50,13 @@ from Hurricane import Net from Hurricane import Instance from CRL import Catalog from CRL import AllianceFramework +from helpers import trace from helpers import netDirectionToStr from helpers.overlay import UpdateSession from helpers.io import ErrorMessage import plugins.chip from plugins.alpha.block.block import Block -from plugins.alpha.block.configuration import BlockState +from plugins.alpha.block.configuration import BlockConf from plugins.alpha.block.configuration import IoPadConf @@ -99,7 +100,6 @@ class IoNet ( object ): self.coronaNet = None # Corona net going from core to corona. self.chipIntNet = None # Chip net going from corona to I/O pad. self.chipExtNet = None # Chip net going from I/O pad to the outside world. - m = IoNet.reVHDLVector.match( self.coreNet.getName() ) if m: self._flags |= IoNet.IsElem @@ -108,9 +108,8 @@ class IoNet ( object ): else: self._name = self.coreNet.getName() self._index = 0 - self._type = self.coreToChip.getNetType( self._name ) - return + trace( 550, '\tIoNet.__init__(): {}\n'.format(self) ) def __repr__ ( self ): return ''.format( self.coreNet.getName() @@ -137,6 +136,10 @@ class IoNet ( object ): @property def coronaNetName ( self ): s = self._name + if self.coreNet.getDirection() & Net.Direction.IN: + s += '_from_pad' + elif self.coreNet.getDirection() & Net.Direction.OUT: + s += '_to_pad' if self._flags & IoNet.IsElem: s += '({})'.format(self._index) return s @@ -233,13 +236,20 @@ class IoPad ( object ): if direction == IoPad.UNSUPPORTED: return "UNSUPPORTED" return "Invalid value" - def __init__ ( self, coreToChip, padInstanceName ): - self.coreToChip = coreToChip - self.padInstanceName = padInstanceName - self.direction = 0 - self.nets = [] - self.pads = [] + def __init__ ( self, coreToChip, ioPadConf ): + self.coreToChip = coreToChip + self.ioPadConf = ioPadConf + self.direction = 0 + self.nets = [] return + + @property + def padInstanceName ( self ): return self.ioPadConf.instanceName + + @property + def pads ( self ): + print( self.ioPadConf ) + return self.ioPadConf.pads def __str__ ( self ): s = '