diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index 78d167a7..3970fa30 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -61,6 +61,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/niolib.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/libresocio.py ) set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index d5a7f4bf..881bb146 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -517,14 +517,14 @@ class Block ( object ): #katana.printConfiguration () katana.digitalInit () #katana.runNegociatePreRouted() - #Breakpoint.stop( 0, 'Block.route() Before global routing.' ) + Breakpoint.stop( 100, 'Block.route() Before global routing.' ) katana.runGlobalRouter ( Katana.Flags.NoFlags ) katana.loadGlobalRouting ( Anabatic.EngineLoadGrByNet ) - #Breakpoint.stop( 0, 'Block.route() After global routing.' ) + Breakpoint.stop( 100, 'Block.route() After global routing.' ) katana.layerAssign ( Anabatic.EngineNoNetLayerAssign ) katana.runNegociate ( Katana.Flags.NoFlags ) success = katana.isDetailedRoutingSuccess() - #Breakpoint.stop( 0, 'Block.route() done, success:{}.'.format(success) ) + Breakpoint.stop( 100, 'Block.route() done, success:{}.'.format(success) ) katana.finalizeLayout() katana.destroy() return success @@ -639,7 +639,7 @@ class Block ( object ): def save ( self ): if not self.conf.validated: raise ErrorMessage( 1, 'block.save(): Chip is not valid, aborting.' ) - self.spares.save() + self.conf.save() # ---------------------------------------------------------------------------- diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 6c384fca..2e017a83 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -47,6 +47,18 @@ from plugins import getParameter from plugins.alpha.utils import getPlugByName +def findCellOutput ( cell, callerName, parameterId ): + """Find the *external* output net of a cell and return it's name.""" + for net in cell.getNets(): + if not net.isExternal(): continue + if net.isGlobal(): continue + elif net.getDirection() & Net.Direction.OUT: + return net.getName() + raise ErrorMessage( 3, [ '{}: Cannot guess the input terminal of "{}",' \ + .format(callerName,Cfg.getParamString(parameterId).asString()) + , ' please check that the Nets directions are set.' ] ) + + # ---------------------------------------------------------------------------- # Class : "configuration.GaugeConf". @@ -580,7 +592,7 @@ class BufferConf ( object ): trace( 550, '-' ) raise ErrorMessage( 3, [ 'BufferConf.__init__(): Buffer cell "{}" not found in library,' \ .format(Cfg.getParamString('spares.buffer').asString()) - , ' please check the "spares.buffer" configuration parameter in "plugins.conf".' ] ) + , ' please check the "spares.buffer" configuration parameter in "plugins.py".' ] ) trace( 550, '\t| masterCell :{}\n'.format(self.masterCell) ) trace( 550, '\t| maximum sinks:{}\n'.format(self.maxSinks) ) self.count = 0 @@ -627,6 +639,90 @@ class BufferConf ( object ): self.count = 0 +# ---------------------------------------------------------------------------- +# Class : "configuration.ConstantsConf". + +class ConstantsConf ( object ): + """ + Store informations on cells used to generate constant signals ("zero" + and "one") + """ + + ZERO = 1 + ONE = 2 + + def __init__ ( self, framework, cfg ): + trace( 550, ',+', '\tConstantsConf.__init__()\n' ) + cfg.etesian.cell.zero = None + cfg.etesian.cell.one = None + self.zeroCell = framework.getCell( cfg.etesian.cell.zero, CRL.Catalog.State.Views ) + self.oneCell = framework.getCell( cfg.etesian.cell.one , CRL.Catalog.State.Views ) + if not self.zeroCell: + trace( 550, '-' ) + raise ErrorMessage( 3, [ 'ConstantsConf.__init__(): Zero cell "{}" not found in library,' \ + .format(cfg.etesian.cell.zero) + , ' please check the "etesian.cell.zero" configuration parameter in "etesian.py".' ] ) + if not self.oneCell: + trace( 550, '-' ) + raise ErrorMessage( 3, [ 'ConstantsConf.__init__(): One cell "{}" not found in library,' \ + .format(cfg.etesian.cell.zero) + , ' please check the "etesian.cell.one" configuration parameter in "etesian.py".' ] ) + trace( 550, '\t| zeroCell:{}\n'.format(self.zeroCell) ) + trace( 550, '\t| oneCell :{}\n'.format(self.oneCell ) ) + self.zeroCount = 0 + self.oneCount = 0 + self.zeroOutput = findCellOutput( self.zeroCell, 'ConstantsConf.__init__()', 'etesian.cell.zero' ) + self.oneOutput = findCellOutput( self.oneCell , 'ConstantsConf.__init__()', 'etesian.cell.one' ) + trace( 550, '\t| zeroOutput:"{}"\n'.format(self.zeroOutput) ) + trace( 550, '\t| oneOutput :"{}"\n'.format(self.oneOutput ) ) + trace( 550, '-' ) + return + + def name ( self, cellType ): + """Returns the master cell *name* of the selected type.""" + if cellType == ConstantsConf.ZERO: return self.zeroCell.getName() + elif cellType == ConstantsConf.ONE : return self.oneCell .getName() + return None + + def output ( self, cellType ): + """Returns the master cell *output* of the selected type.""" + if cellType == ConstantsConf.ZERO: return self.zeroOutput + elif cellType == ConstantsConf.ONE : return self.oneOutput + return None + + def width ( self, cellType ): + """Returns the master cell abutment box width of the selected type.""" + if cellType == ConstantsConf.ZERO: return self.zeroCell.getAbutmentBox().getWidth() + elif cellType == ConstantsConf.ONE : return self.oneCell .getAbutmentBox().getWidth() + return None + + def height ( self, cellType ): + """Returns the master cell abutment box height of the selected type.""" + if cellType == ConstantsConf.ZERO: return self.zeroCell.getAbutmentBox().getHeight() + elif cellType == ConstantsConf.ONE : return self.oneCell .getAbutmentBox().getHeight() + return None + + def createInstance ( self, cell, cellType ): + """ + Create a new zero/one *instance* in Cell. The instance is named "constant__", + where ```` is the kind of constante (zero or one) and ```` is an ever + incrementing counter (self.count). + """ + instance = None + if cellType == ConstantsConf.ZERO: + instance = Instance.create( cell, 'constant_zero_{}'.format(self.zeroCount), self.zeroCell ) + self.zeroCount += 1 + elif cellType == ConstantsConf.ONE: + instance = Instance.create( cell, 'constant_one_{}'.format(self.oneCount), self.oneCell ) + self.oneCount += 1 + return instance + + def resetCounts ( self ): + """Reset the zero/one instance counters (to use only in case of design reset).""" + self.zeroCount = 0 + self.oneCount = 0 + + # ---------------------------------------------------------------------------- # Class : "configuration.FeedsConf". @@ -852,28 +948,30 @@ class BlockConf ( GaugeConf ): 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.bufferConf = BufferConf( self.framework ) - self.feedsConf = FeedsConf( self.framework ) - 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 ] - self.useClockTree = False - self.useHFNS = False - self.useSpares = True - self.isBuilt = False - self.ioPins = [] - self.ioPinsCounts = {} + self.validated = True + self.editor = None + self.framework = CRL.AllianceFramework.get() + self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive) + self.bufferConf = BufferConf( self.framework ) + self.constantsConf = ConstantsConf( self.framework, self.cfg ) + self.feedsConf = FeedsConf( self.framework ) + self.chipConf = ChipConf( self ) + self.bColumns = 2 + self.bRows = 2 + self.cloneds = [] + self.cell = cell + self.icore = None + self.icorona = None + self.chip = None + self.fixedWidth = None + self.fixedHeight = None + self.deltaAb = [ 0, 0, 0, 0 ] + self.useClockTree = False + self.useHFNS = False + self.useSpares = True + self.isBuilt = False + self.ioPins = [] + self.ioPinsCounts = {} for ioPinSpec in ioPins: self.ioPins.append( IoPin( *ioPinSpec ) ) for line in range(len(ioPads)): @@ -957,3 +1055,39 @@ class BlockConf ( GaugeConf ): def resetBufferCount ( self ): self.bufferConf.resetBufferCount() + + def addClonedCell ( self, masterCell ): + if not masterCell in self.cloneds: + trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) ) + self.cloneds.append( masterCell ) + return + + def rsave ( self, cell ): + """ + Save the complete cell hierarchy. Saves only the physical view, except + for the ones that has been cloned (their names should end up by "_cts"), + for which logical and physical views are to be saved. They are completely + new cells. + """ + flags = CRL.Catalog.State.Physical + if cell.getName().endswith('_cts'): + flags = flags | CRL.Catalog.State.Logical + self.framework.saveCell( cell, flags ) + for instance in cell.getInstances(): + masterCell = instance.getMasterCell() + if not masterCell.isTerminal(): + self.rsave( masterCell ) + + def save ( self ): + """ + Frontend to BlockConf.rsave(). Append the "_cts" suffix to the cloned + cells, then call rsave(). + """ + trace( 550,'\tBlockConf.save() on "{}"\n'.format(self.cell.getName()) ) + for cell in self.cloneds: + trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) ) + cell.setName( cell.getName()+'_cts' ) + if self.chip is None: + self.cell.setName( self.cell.getName()+'_r' ) + self.rsave( self.cell ) + return diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index 69c4da0b..957d5073 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -732,7 +732,6 @@ class Spares ( object ): def __init__ ( self, block ): self.conf = block.conf self.quadTree = None - self.cloneds = [] self.strayBuffers = [] def reset ( self ): @@ -838,12 +837,6 @@ class Spares ( object ): raise ErrorMessage( 2, 'Spares.getFreeBufferUnder(): No more free buffers under {}.'.format(area) ) return leaf.selectFree() - def addClonedCell ( self, 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 ): """ Add a net through a whole hierarchy of Instance/Cells. The master cells @@ -881,7 +874,7 @@ class Spares ( object ): trace( 540, '\tSpares.raddTransNet() top:{} path:{}\n'.format(topNet,path) ) if path.isEmpty(): - self.addClonedCell( topNet.getCell() ) + self.conf.addClonedCell( topNet.getCell() ) return None tailPath = path.getTailPath() headInstance = path.getHeadInstance() @@ -898,8 +891,8 @@ class Spares ( object ): raise ErrorMessage( 3, 'Plug not created for %s on instance %s of %s' \ % (topNet.getName(),headInstance.getName(),masterCell.getName()) ) headPlug.setNet( topNet ) - self.addClonedCell( masterCell ) - self.addClonedCell( headInstance.getCell() ) + self.conf.addClonedCell( masterCell ) + self.conf.addClonedCell( headInstance.getCell() ) else: masterNet = headPlug.getMasterNet() trace( 540, '\ttailPath {}\n'.format(tailPath) ) @@ -909,35 +902,3 @@ class Spares ( object ): def removeUnusedBuffers ( self ): with UpdateSession(): self.quadTree.removeUnusedBuffers() - - def rsave ( self, cell ): - """ - Save the complete cell hierarchy. Saves only the physical view, except - for the ones that has been cloned (their names should end up by "_cts"), - for which logical and physical views are to be saved. They are completely - new cells. - """ - - flags = CRL.Catalog.State.Physical - if cell.getName().endswith('_cts'): - flags = flags | CRL.Catalog.State.Logical - framework.saveCell( cell, flags ) - - for instance in cell.getInstances(): - masterCell = instance.getMasterCell() - if not masterCell.isTerminal(): - self.rsave( masterCell ) - - 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' ) - if self.conf.chip is None: - self.conf.cell.setName( self.conf.cell.getName()+'_r' ) - self.rsave( self.conf.cell ) - return diff --git a/cumulus/src/plugins/alpha/chip/configuration.py b/cumulus/src/plugins/alpha/chip/configuration.py index 1808879a..0c43ec37 100644 --- a/cumulus/src/plugins/alpha/chip/configuration.py +++ b/cumulus/src/plugins/alpha/chip/configuration.py @@ -238,13 +238,17 @@ class ChipConf ( BlockConf ): axis = (uTrackMax + uTrackMin) / 2 width = (iTrackMax - iTrackMin) * lg.getPitch() + lg.getWireWidth() if self.routingGauge.isSymbolic(): + trace( 550, '\tRoutingGauge is symbolic, adjust on lambda.\n' ) 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)) ) + trace( 550, '\t[{} {}] -> [{} {}]\n'.format( iTrackMin + , iTrackMax + , DbU.getValueString(uTrackMin) + , DbU.getValueString(uTrackMax) ) ) + trace( 550, '\taxis: {:.1f}L {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) ) + trace( 550, '\twidth: {:.1f}L {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) ) else: axis = (uMax + uMin) / 2 width = (uMax - uMin) @@ -252,8 +256,8 @@ class ChipConf ( BlockConf ): return axis, width def toCoronaPitchInChip ( self, uCore, layer ): - trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {}l {}\n' \ - .format(DbU.toLambda(uCore), DbU.getValueString(uCore)) ) + trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {:.1f}L {}\n' \ + .format(DbU.toLambda(uCore), DbU.getValueString(uCore)) ) coronaAb = self.getInstanceAb( self.icorona ) lg = None mask = layer.getMask() @@ -271,15 +275,15 @@ class ChipConf ( BlockConf ): else: uCorona = uCore - coronaAb.getXMin() uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer ) - trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l {}\n' \ + trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}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, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) ) + trace( 550, '\ttoCoronaPitchInChip(): uCore: {:.1f}L {}\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) ) trace( 550, '-' ) return uCore @@ -295,16 +299,16 @@ class ChipConf ( BlockConf ): 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' \ + trace( 550, '\t| dxMin:{} ({:.1f}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)) ) + trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) ) + trace( 550, '\t| width:{:.1f}L or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) ) + trace( 550, '\t| dxMin:{:.1f}L\n'.format(DbU.toLambda(dxMin)) ) + trace( 550, '\t| dxMax:{:.1f}L\n'.format(DbU.toLambda(dxMax)) ) h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax ) trace( 550, '\t| {}\n'.format(h) ) trace( 550, '-' ) @@ -324,8 +328,8 @@ class ChipConf ( BlockConf ): 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)) ) + trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) ) + trace( 550, '\t| width:{:.1f}L 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, '-' ) @@ -343,12 +347,13 @@ class ChipConf ( BlockConf ): 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() + botLayer = layer.getBottom() if self.isHorizontal(topLayer): - coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, layer.getBottom() ) + coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, botLayer ) 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() ) + coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, botLayer ) if not (flags & OnHorizontalPitch): trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' ) coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior ) @@ -356,10 +361,10 @@ class ChipConf ( BlockConf ): 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 )) ) + trace( 550, '\t| X axis: {:>12.1f}L or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) ) + trace( 550, '\t| Y axis: {:>12.1f}L 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 @@ -373,17 +378,20 @@ class ChipConf ( BlockConf ): def getViaPitch ( self, viaLayer ): topLayer = viaLayer.getTop() - topPitch = 2*viaLayer.getEnclosure \ - ( topLayer.getBasicLayer(), Layer.EnclosureH|Layer.EnclosureV ) \ - + viaLayer.getMinimalSize() \ - + topLayer.getMinimalSpacing() + if topLayer.isSymbolic(): + topLayer = topLayer.getBasicLayer() + topEnclosure = viaLayer.getEnclosure( topLayer, Layer.EnclosureH|Layer.EnclosureV ) + topPitch = 2*topEnclosure + viaLayer.getMinimalSize() + topLayer.getMinimalSpacing() botLayer = viaLayer.getBottom() - botPitch = 2*viaLayer.getEnclosure \ - ( botLayer.getBasicLayer(), Layer.EnclosureH|Layer.EnclosureV ) \ - + viaLayer.getMinimalSize() \ - + botLayer.getMinimalSpacing() + if botLayer.isSymbolic(): + botLayer = botLayer.getBasicLayer() + botEnclosure = viaLayer.getEnclosure( botLayer, Layer.EnclosureH|Layer.EnclosureV ) + botPitch = 2*botEnclosure + viaLayer.getMinimalSize() + botLayer.getMinimalSpacing() viaPitch = max( topPitch, botPitch ) - trace( 550, '\tgetViaPitch of {}: {}l\n'.format(viaLayer.getName(),DbU.getValueString(viaPitch)) ) + trace( 550, '\tgetViaPitch of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaPitch)) ) + trace( 550, '\t| minimal size of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaLayer.getMinimalSize())) ) + trace( 550, '\t| enclosure of {}: {}\n'.format(topLayer.getName(),DbU.getValueString(topEnclosure)) ) + trace( 550, '\t| enclosure of {}: {}\n'.format(botLayer.getName(),DbU.getValueString(botEnclosure)) ) return viaPitch def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ): @@ -412,7 +420,7 @@ class ChipConf ( BlockConf ): 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)) ) + trace( 550, '\txContact:{} yContact:{}\n'.format(DbU.getValueString(xContact),DbU.getValueString(yContact)) ) for i in range(array[0]): for j in range(array[1]): c = Contact.create( coronaNet @@ -452,10 +460,10 @@ class ChipConf ( BlockConf ): 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 )) ) + trace( 550, '\t| X axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) ) + trace( 550, '\t| Y axis: {:.1f}L 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 diff --git a/cumulus/src/plugins/alpha/chip/corona.py b/cumulus/src/plugins/alpha/chip/corona.py index 9877199d..a632e09b 100644 --- a/cumulus/src/plugins/alpha/chip/corona.py +++ b/cumulus/src/plugins/alpha/chip/corona.py @@ -451,8 +451,10 @@ class VerticalSide ( Side ): 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 ): + print( self.getOuterRail(0) ) + print( self.getOuterRail(0).vias.values() ) + for depth in range(self.getOuterRail(0).vias.values()[0][1].bottomDepth + ,self.getOuterRail(0).vias.values()[0][1].topDepth ): blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer() pitch = routingGauge.getLayerPitch(depth) for chunk in spans.chunks: diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py index 19bd983a..75f70369 100644 --- a/cumulus/src/plugins/alpha/chip/pads.py +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -18,30 +18,16 @@ 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 +from Hurricane import DbU, Point, Transformation, Interval, Box, \ + Path, Occurrence, UpdateSession, Layer, \ + BasicLayer, Net, Pin, Contact, Segment, \ + Horizontal, Vertical, Diagonal, RoutingPad, \ + 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.io import ErrorMessage, WarningMessage from helpers.overlay import UpdateSession import plugins.alpha.chip @@ -62,38 +48,58 @@ class Corner ( object ): def conf ( self ): return self.corona.conf def _getPoints ( self, axis ): + """ + Compute the various coordinates to draw the corner for a wire + positioned at ``axis`` distance from the *border* of the chip. + xExtend and yExtend are used only in case of 45 degree corners, + the 0.5 ratio is an approximate of ``sqrt(2) - 1``. + """ 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 + xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) ) + yExtend = xExtend 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 + xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) ) + yExtend = - xExtend 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 + xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) ) + yExtend = xExtend 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 + xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) ) + yExtend = - xExtend + return xCorner, yCorner, xBb, yBb, xExtend, yExtend def _createCorner ( self ): + self.corona.conf.cfg.chip.use45corners = None 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 ) + xCorner, yCorner, xBb, yBb, xExtend, yExtend = self._getPoints( axis ) + if self.corona.conf.cfg.chip.use45corners: + Diagonal.create( net, layer, Point(xBb+xExtend,yCorner), Point(xCorner,yBb+yExtend), width ) + Horizontal.create( net, layer, yCorner, width, xBb+xExtend, xBb ) + Vertical .create( net, layer, xCorner, width, yBb+yExtend, yBb ) + else: + 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: @@ -243,9 +249,10 @@ class Side ( object ): 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 + padLength = 2*self.conf.ioPadHeight + for pad in self.pads: + padLength += pad[1].getMasterCell().getAbutmentBox().getWidth() + self.conf.validated = self._check( padLength, checkName ) and self.conf.validated return self.conf.validated def _fillPadSpacing ( self, gapWidth ): @@ -537,13 +544,16 @@ class CoreWire ( object ): else: self.symContactSize = ( self.bbSegment.getWidth(), self.bbSegment.getWidth() ) self.viaPitch = self.conf.getViaPitch( self.symContactLayer ) - contactMinSize = 2*self.symContactLayer.getEnclosure( self.symSegmentLayer.getBasicLayer() + basicLayer = self.symSegmentLayer + if basicLayer.isSymbolic(): + basicLayer = basicLayer.getBasicLayer() + contactMinSize = 2*self.symContactLayer.getEnclosure( basicLayer , Layer.EnclosureH|Layer.EnclosureV ) \ + self.symContactLayer.getMinimalSize() arrayWidth = self.symContactSize[0] arrayCount = (arrayWidth - contactMinSize) / self.viaPitch - trace( 550, '\tcontactMinSize: {}l, arrayWidth: {}l, arrayCount: {}\n' \ - .format(DbU.toLambda(contactMinSize),DbU.toLambda(arrayWidth),arrayCount) ) + trace( 550, '\tcontactMinSize: {}, arrayWidth: {}, arrayCount: {}\n' \ + .format(DbU.getValueString(contactMinSize),DbU.getValueString(arrayWidth),arrayCount) ) if arrayCount < 0: arrayCount = 0 #if arrayCount < 3: if self.side & (North|South): @@ -731,7 +741,7 @@ class CoreWire ( object ): 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)) ) + trace( 550, '\txCore: {:.1f}L {}\n'.format(DbU.toLambda(xCore), DbU.getValueString(xCore)) ) self.conf.coronaVertical( self.chipNet , self.symSegmentLayer , xCore @@ -855,43 +865,52 @@ class Corona ( object ): if not self.padLib: self.padLib = padCell.getLibrary() for plug in padInstance.getPlugs(): for component in plug.getMasterNet().getComponents(): + if component is None: continue + bb = component.getBoundingBox() + hspan = Interval( bb.getXMin(), bb.getXMax() ) + axis = bb.getCenter().getY() 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, 'Corona._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, 'Corona._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() ) ) + width = component.getWidth() + elif isinstance(component,Vertical): + width = bb.getHeight() + else: + continue + # Specific hack for Alliance pxlib pad library. + if self.conf.ioPadGauge.getName() == 'pxlib': + if isinstance(component,Vertical): + continue + 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: + pass + else: + axis = self.conf.ioPadHeight - axis + 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, 'Corona._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, 'Corona._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 + , width ) ) def _createCoreWire ( self, chipIntNet, padNet, padInstance, count ): trace( 550, ',+', '\tCorona._createCoreWire()\n' ) @@ -906,6 +925,12 @@ class Corona ( object ): if not side: trace( 550, '-' ) return count + if chipIntNet.isPower() and not padInstance.getName().startswith('p_vdd'): + trace( 550, '-' ) + return count + if chipIntNet.isGround() and not padInstance.getName().startswith('p_vss'): + trace( 550, '-' ) + return count innerBb = self.conf.chip.getAbutmentBox().inflate( -self.conf.ioPadHeight ) rg = self.conf.routingGauge hsegments = {} diff --git a/cumulus/src/plugins/alpha/chip/power.py b/cumulus/src/plugins/alpha/chip/power.py index 6e890869..65e35525 100644 --- a/cumulus/src/plugins/alpha/chip/power.py +++ b/cumulus/src/plugins/alpha/chip/power.py @@ -155,7 +155,10 @@ class GoCb ( object ): 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() ) + layer = self.block.activePlane.metal + if layer.isSymbolic(): + layer = layer.getBasicLayer() + bb = go.getBoundingBox( layer ) query.getPath().getTransformation().applyOn( bb ) self.block.activePlane.addTerminal( rootNet, direction, bb ) else: @@ -190,7 +193,10 @@ class Builder ( object ): 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() ) + layer = layerGauge.getLayer() + if layer.isSymbolic(): + layer = layer.getBasicLayer() + query.setBasicLayer( layer ) query.doQuery() self.activePlane = None @@ -231,7 +237,10 @@ class Builder ( object ): ) segment = self.conf.createVertical( bufferRp, contact, bufferRp.getX(), 0 ) self.activePlane = self.planes[ layerGauge.getLayer().getName() ] - bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() ) + layer = self.activePlane.metal + if layer.isSymbolic(): + layer = layer.getBasicLayer() + bb = segment.getBoundingBox( layer ) self.path.getTransformation().getInvert().applyOn( bb ) self.activePlane.addTerminal( ck, Plane.Vertical, bb ) trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) ) diff --git a/cumulus/src/plugins/alpha/core2chip/core2chip.py b/cumulus/src/plugins/alpha/core2chip/core2chip.py index 200a9537..483854fb 100644 --- a/cumulus/src/plugins/alpha/core2chip/core2chip.py +++ b/cumulus/src/plugins/alpha/core2chip/core2chip.py @@ -52,8 +52,9 @@ from helpers import trace, netDirectionToStr from helpers.overlay import UpdateSession from helpers.io import ErrorMessage, WarningMessage import plugins.chip +from plugins.alpha.utils import getPlugByName from plugins.alpha.block.block import Block -from plugins.alpha.block.configuration import BlockConf, IoPadConf +from plugins.alpha.block.configuration import BlockConf, IoPadConf, ConstantsConf # ------------------------------------------------------------------- @@ -307,6 +308,9 @@ class IoPad ( object ): if (self.direction == IoPad.BIDIR) and (len(self.nets) < 3): self.nets[0].setFlags( IoNet.DoExtNet ) self.nets[0].buildNets() + if len(self.nets) < 2: + enableNet = self.coreToChip.newEnableForNet( self.nets[0] ) + self.nets.append( self.coreToChip.getIoNet( enableNet ) ) self.nets[1].buildNets() connexions.append( ( self.nets[0].chipExtNet, padInfo.padNet ) ) if self.nets[0].coreNet.getDirection() == Net.Direction.IN: @@ -329,7 +333,7 @@ class IoPad ( object ): elif self.direction == IoPad.TRI_OUT: connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) - elif self.direction == IoPad.BUDIR: + elif self.direction == IoPad.BIDIR: connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) ) connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) ) @@ -398,13 +402,13 @@ class CoreToChip ( object ): def getNetType ( self, netName ): - raise ErrorMessage( 1, 'coreToChip.getNetType(): This method must be overloaded.' ) + raise NotImplementedError( 'coreToChip.getNetType(): This method must be overloaded.' ) def isGlobal ( self, netName ): - raise ErrorMessage( 1, 'coreToChip.isGlobal(): This method must be overloaded.' ) + raise NotImplementedError( 'coreToChip.isGlobal(): This method must be overloaded.' ) def getCell ( self, masterCellName ): - raise ErrorMessage( 1, 'coreToChip.getCell(): This method must be overloaded.' ) + raise NotImplementedError( 'coreToChip.getCell(): This method must be overloaded.' ) @staticmethod def _connect ( instance, netO, masterNetO=None ): @@ -431,17 +435,17 @@ class CoreToChip ( object ): def __init__ ( self, core ): if isinstance(core,Block): - state = core.state + conf = core.state elif isinstance(core,BlockConf): - state = core + conf = core else: block = Block.lookup( core ) if not block: raise ErrorMessage( 1, [ 'Core2Chip.__init__(): Core cell "{}" has no Block defined.' \ .format( core.getName() ) ] ) - state = block.state - self.state = state + conf = block.state + self.conf = conf self.ringNetNames = [] self.ioPadInfos = [] self.chipPads = [] @@ -455,16 +459,16 @@ class CoreToChip ( object ): return @property - def core ( self ): return self.state.cell + def core ( self ): return self.conf.cell @property - def icore ( self ): return self.state.icore + def icore ( self ): return self.conf.icore @property - def icorona ( self ): return self.state.icorona + def icorona ( self ): return self.conf.icorona @property - def chip ( self ): return self.state.chip + def chip ( self ): return self.conf.chip def getPadInfo ( self, padType ): for ioPadInfo in self.ioPadInfos: @@ -480,10 +484,30 @@ class CoreToChip ( object ): return False def newDummyNet ( self ): + """Create a dummy net in *chip* cell (for unconnected terminals).""" dummy = Net.create( self.chip, '{}_dummy_{}'.format(self.chip.getName(),self.dummyNetCount) ) self.dummyNetCount += 1 return dummy + def newEnableForNet ( self, ioNet ): + """ + Create a new enable signal, in *core* cell, to control the associated I/O pad. + This is to be used in the case of bi-directional I/O pads used as simples inputs + or outputs. + """ + if ioNet.coreNet.getDirection() & Net.Direction.IN: constantType = ConstantsConf.ZERO + elif ioNet.coreNet.getDirection() & Net.Direction.OUT: constantType = ConstantsConf.ONE + else: + raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \ + .format(ioNet.coreNet.getName()) ) + instance = self.conf.constantsConf.createInstance( self.core, constantType ) + enable = Net.create( self.core, '{}_enable'.format(ioNet.padInstanceName) ) + enable.setExternal ( True ) + enable.setDirection( Net.Direction.OUT ) + getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable ) + self.conf.addClonedCell( self.conf.core ) + return enable + def getIoNet ( self, coreNet ): """ Lookup, and create if it doesn't exist, for an IoNet associated to *core* @@ -566,19 +590,19 @@ class CoreToChip ( object ): from the core cell. """ af = AllianceFramework.get() - self.state.cfg.apply() + self.conf.cfg.apply() with UpdateSession(): print( ' o Build Chip from Core.' ) - print( ' - Core: "{}".'.format(self.state.cell.getName()) ) + print( ' - Core: "{}".'.format(self.conf.cell.getName()) ) print( ' - Corona: "{}".'.format('corona') ) - print( ' - Chip: "{}".'.format(self.state.chipConf.name) ) - self.state.chip = af.createCell( self.state.chipConf.name ) - self.corona = af.createCell( 'corona' ) - self.state.icore = Instance.create( self.corona , 'core' , self.state.cell ) - self.state.icorona = Instance.create( self.state.chip, 'corona', self.corona ) + print( ' - Chip: "{}".'.format(self.conf.chipConf.name) ) + self.conf.chip = af.createCell( self.conf.chipConf.name ) + self.corona = af.createCell( 'corona' ) + self.conf.icore = Instance.create( self.corona , 'core' , self.conf.cell ) + self.conf.icorona = Instance.create( self.conf.chip, 'corona', self.corona ) ioPads = [] clockIoNets = [] - for ioPadConf in self.state.chipConf.padInstances: + for ioPadConf in self.conf.chipConf.padInstances: if ioPadConf.isAllPower(): self._buildAllPowerPads( ioPadConf ) continue @@ -638,5 +662,4 @@ class CoreToChip ( object ): ioPad.udata.createPad() self._connectRing() self._connectClocks() - af.saveCell( self.chip , Catalog.State.Logical ) - af.saveCell( self.corona, Catalog.State.Logical ) + self.conf.rsave( self.chip ) diff --git a/cumulus/src/plugins/alpha/core2chip/libresocio.py b/cumulus/src/plugins/alpha/core2chip/libresocio.py new file mode 100644 index 00000000..5d7a4853 --- /dev/null +++ b/cumulus/src/plugins/alpha/core2chip/libresocio.py @@ -0,0 +1,160 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) SU 2020-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/core2chip/libresocio.py" | +# +-----------------------------------------------------------------+ + +""" +Core2Chip configuration for the FlexLib I/O pad library. + +It provides the same features as the symbolic "niolib", but is +using the real cells provided by LibreSOC.py. For now, apart from +cell library change, the only difference is that the cell names are +in upppercase. We can use them because, in real mode, we are less +dependent from the Alliance design flow. +""" + +from __future__ import print_function +import sys +import re +from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \ + Transformation , Instance , Net +import Viewer +from CRL import Catalog +from CRL import AllianceFramework +from helpers.io import ErrorMessage, WarningMessage +from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip, \ + IoNet, IoPad + + +class CoreToChip ( BaseCoreToChip ): + """ + Provide pad-specific part for LibreSOCIO I/O pads (works in real mode). + """ + rePadType = re.compile(r'(?P.+)_(?P[\d]+)$') + + def __init__ ( self, core ): + BaseCoreToChip.__init__ ( self, core ) + self.ringNetNames = { 'iovdd' : None + , 'iovss' : None + , 'vdd' : None + , 'vss' : None + } + self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.BIDIR, 'GPIO', 'pad', ['s', 'd', 'de'] ) + ] + self._getPadLib() + return + + def _getPadLib ( self ): + self.padLib = AllianceFramework.get().getLibrary( "LibreSOCIO" ) + if not self.padLib: + message = [ 'CoreToChip.libresocio._getPadLib(): Unable to find Alliance "LibreSOCIO" library' ] + raise ErrorMessage( 1, message ) + + def getNetType ( self, netName ): + if netName.startswith('vss') or netName.startswith('iovss'): return Net.Type.GROUND + if netName.startswith('vdd') or netName.startswith('iovdd'): return Net.Type.POWER + return Net.Type.LOGICAL + + def isGlobal ( self, netName ): + if netName in self.ringNetNames: return True + return False + + def getCell ( self, masterCellName ): + #cell = self.padLib.getCell( masterCellName ) + cell = AllianceFramework.get().getCell( masterCellName, Catalog.State.Views ) + if not cell: + raise ErrorMessage( 1, 'libresocio.getCell(): I/O pad library "%s" does not contain cell named "%s"' \ + % (self.padLib.getName(),masterCellName) ) + return cell + + def _buildCoreGroundPads ( self, ioPadConf ): + coreNet = self.core .getNet( ioPadConf.coreSupplyNetName ) + coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName ) + chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName ) + if not coronaNet: + coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName ) + coronaNet.setExternal( True ) + coronaNet.setGlobal ( True ) + 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.GROUND ) + self.icorona.getPlug( coronaNet ).setNet( chipNet ) + self.ringNetNames['vss'] = chipNet + ioPadConf.pads.append( Instance.create( self.chip + , 'p_vss_{}'.format(ioPadConf.index) + , self.getCell('VSS') ) ) + self._connect( ioPadConf.pads[0], chipNet, 'vss' ) + self.groundPadCount += 1 + self.chipPads += ioPadConf.pads + + def _buildIoGroundPads ( self, ioPadConf ): + padNet = self.chip.getNet( ioPadConf.padSupplyNetName ) + if not padNet: + padNet = Net.create( self.chip, ioPadConf.padSupplyNetName ) + padNet.setExternal( True ) + padNet.setType ( Net.Type.GROUND ) + self.ringNetNames['iovss'] = padNet + ioPadConf.pads.append( Instance.create( self.chip + , 'p_iovss_{}'.format(ioPadConf.index) + , self.getCell('IOVSS') ) ) + self._connect( ioPadConf.pads[0], padNet , 'iovss' ) + self.groundPadCount += 1 + self.chipPads += ioPadConf.pads + + def _buildCorePowerPads ( self, ioPadConf ): + coreNet = self.core .getNet( ioPadConf.coreSupplyNetName ) + coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName ) + chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName ) + if not coronaNet: + coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName ) + coronaNet.setExternal( True ) + coronaNet.setGlobal ( True ) + coronaNet.setType ( Net.Type.POWER ) + self.icore.getPlug( coreNet ).setNet( coronaNet ) + if not chipNet: + chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName ) + chipNet.setExternal( True ) + chipNet.setType ( Net.Type.POWER ) + self.icorona.getPlug( coronaNet ).setNet( chipNet ) + self.ringNetNames['vdd'] = chipNet + ioPadConf.pads.append( Instance.create( self.chip + , 'p_vdd_{}'.format(ioPadConf.index) + , self.getCell('VDD') ) ) + self._connect( ioPadConf.pads[0], chipNet, 'vdd' ) + self.powerPadCount += 1 + self.chipPads += ioPadConf.pads + + def _buildIoPowerPads ( self, ioPadConf ): + padNet = self.chip .getNet( ioPadConf.padSupplyNetName ) + if not padNet: + padNet = Net.create( self.chip, ioPadConf.padSupplyNetName ) + padNet.setExternal( True ) + padNet.setType ( Net.Type.POWER ) + self.ringNetNames['iovdd'] = padNet + ioPadConf.pads.append( Instance.create( self.chip + , 'p_iovdd_{}'.format(ioPadConf.index) + , self.getCell('IOVDD') ) ) + self._connect( ioPadConf.pads[0], padNet , 'iovdd' ) + self.powerPadCount += 1 + self.chipPads += ioPadConf.pads + + def _buildClockPads ( self, ioPadConf ): + """For "LibreSOCIO" there is no specialized clock I/O pad. So do nothing.""" + pass + + def _connectClocks ( self ): + """For "LibreSOCIO" there is no pad internal clock ring. So do nothing.""" + pass