From c595a8e73e7c44158df21a24e3cd2e393cdc3e15 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 16 Nov 2021 17:11:00 +0100 Subject: [PATCH] No longer straight route the root of a H-Tree. * Change: In cumulus/plugins.block.HTree._rrouteHTree(), make the non-routing of the root net the default policy. Straight routing can still be activated with the use of Spares.ROUTE_ROOT_NET. --- cumulus/src/plugins/alpha/block/htree.py | 4 +- cumulus/src/plugins/alpha/block/spares.py | 3 +- cumulus/src/plugins/alpha/harness/__init__.py | 0 .../plugins/alpha/harness/configuration.py | 711 ++++++++++++++++++ cumulus/src/plugins/alpha/harness/harness.py | 148 ++++ 5 files changed, 864 insertions(+), 2 deletions(-) create mode 100644 cumulus/src/plugins/alpha/harness/__init__.py create mode 100644 cumulus/src/plugins/alpha/harness/configuration.py create mode 100644 cumulus/src/plugins/alpha/harness/harness.py diff --git a/cumulus/src/plugins/alpha/block/htree.py b/cumulus/src/plugins/alpha/block/htree.py index 68c38287..21d17954 100644 --- a/cumulus/src/plugins/alpha/block/htree.py +++ b/cumulus/src/plugins/alpha/block/htree.py @@ -185,7 +185,9 @@ class HTree ( object ): self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, blY ) if qt.isRoot(): ckNet = self.treeNet - if not self.spares.conf.isCoreBlock and ckNet.isExternal(): + if not self.spares.conf.isCoreBlock \ + and ckNet.isExternal() \ + and (self.flags & Spares.ROUTE_ROOT_NET): trace( 550, '\tRemoving any previous pin...\n' ) pins = [] for pin in ckNet.getPins(): pins.append( pin ) diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index d510159f..128d8024 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -892,7 +892,7 @@ class QuadTree ( object ): class Spares ( object ): """ Manages all the spare buffer over a Cell abutment box. Used for clock tree - synthesis (CTS) and high fanout net synthesis (HFS). 4 buffers are created + synthesis (CTS) and high fanout net synthesis (HNFS). 4 buffers are created in each pool. Pools are set in a regular matrix over the whole abutment box. Excess area is put in the topmost and rightmost pools. """ @@ -901,6 +901,7 @@ class Spares ( object ): CHECK_USED = 0x00010000 MARK_USED = 0x00020000 HEAVY_LEAF_LOAD = 0x00040000 + ROUTE_ROOT_NET = 0x00080000 def __init__ ( self, block ): self.conf = block.conf diff --git a/cumulus/src/plugins/alpha/harness/__init__.py b/cumulus/src/plugins/alpha/harness/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/cumulus/src/plugins/alpha/harness/configuration.py b/cumulus/src/plugins/alpha/harness/configuration.py new file mode 100644 index 00000000..fcb1f0f6 --- /dev/null +++ b/cumulus/src/plugins/alpha/harness/configuration.py @@ -0,0 +1,711 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) Sorbonne Université 2014-2021, 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" | +# +-----------------------------------------------------------------+ + +import sys +import os.path +import Cfg +from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \ + Path, Layer, Occurrence, Net, RoutingPad, \ + Horizontal, Vertical, Contact, Pin, Plug, \ + 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, WarningMessage, \ + vprint, catch +import plugins.chip +from plugins.alpha.block.configuration import BlockConf + +__all__ = [ 'ChipConf' ] + + +plugins.alpha.chip.importConstants( globals() ) +af = CRL.AllianceFramework.get() + + +# ------------------------------------------------------------------- +# 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,int): 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()) ) + 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.padCoreSide = None + self.cfg.chip.supplyRailWidth = None + self.cfg.chip.supplyRailPitch = None + 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.coronaCks = [] + self.blockageNet = None + self.padsHavePosition = False + self.chipLogos = [] + trace( 550, '-' ) + + @property + def padCoreSide ( self ): + return self.cfg.chip.padCoreSide + + @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 ): + global af + if self.useClockTree: + clockNets = [] + for net in self.cellPnR.getNets(): + if net.isClock(): + clockNets.append( net ) + self.railsCount = self.cfg.chip.block.rails.count + len(clockNets) + trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) ) + hRailsSize = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace + if hRailsSize % self.sliceHeight: + hRailsSize += self.sliceHeight - (hRailsSize % self.sliceHeight) + self.minHCorona = hRailsSize + self.sliceHeight + vRailsSize = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace + if vRailsSize % self.sliceHeight: + vRailsSize += self.sliceHeight - (vRailsSize % self.sliceHeight) + self.minVCorona = vRailsSize + self.sliceHeight + + 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() ) ) + self.coreSize = ( self.coreSize[0] - self.coreSize[0] % self.sliceStep + , self.coreSize[1] - self.coreSize[1] % self.sliceHeight ) + self.core.setAbutmentBox( Box( 0, 0, self.coreAb.getWidth(), self.coreAb.getHeight() ) ) + trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) ) + coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) // 2 + trace( 550, '\tCore X, {} '.format(DbU.getValueString(coreX)) ) + coreX = coreX - (coreX % self.sliceHeight) + trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.sliceHeight) + , DbU.getValueString(coreX)) ) + coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) // 2 + 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(): + 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 + , 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) + trace( 550, '-' ) + return axis, width + + def toCoronaPitchInChip ( self, uCore, layer ): + 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() + 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: {:.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: {:.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 + + 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:{} ({:.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: {:.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, '-' ) + 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: {:.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, '-' ) + 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() + botLayer = layer.getBottom() + if self.isHorizontal(topLayer): + 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, botLayer ) + 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.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 + , coronaY + , width + , height + ) + trace( 550, '\t| {}\n'.format(c) ) + trace( 550, '-' ) + return c + + def getViaPitch ( self, viaLayer ): + topLayer = viaLayer.getTop() + if topLayer.isSymbolic(): + topLayer = topLayer.getBasicLayer() + topEnclosure = viaLayer.getEnclosure( topLayer, Layer.EnclosureH|Layer.EnclosureV ) + topPitch = 2*topEnclosure + viaLayer.getMinimalSize() + topLayer.getMinimalSpacing() + botLayer = viaLayer.getBottom() + 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 {}: {}\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 ): + trace( 550, ',+', '\tChipConf.coronaContactArray\n' ) + viaPitch = self.getViaPitch( layer ) + 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:{} 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 + , 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: {:.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 + , 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 + + global af + 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 not net in self.coronaCks: + self.coronaCks.append( net ) + vprint( 2, ' - Using clock "{}".'.format(net.getName()) ) + 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.chipSize[0] % self.sliceStep: + print( WarningMessage( 'ChipConf.checkChipSize(): Width of "{}" ({})is not on sliceStep ({}), ajusted.' \ + .format( self.chipConf.name + , DbU.getValueString(self.chipSize[0]) + , DbU.getValueString(self.sliceStep))) ) + adjust = self.sliceStep - self.chipSize[0] % self.sliceStep + self.chipSize = (self.chipSize[0] + adjust, self.chipSize[1]) + if self.chipSize[1] % self.sliceStep: + print( WarningMessage( 'ChipConf.checkChipSize(): Height of "{}" ({})is not on sliceStep ({}), ajusted.' \ + .format( self.chipConf.name + , DbU.getValueString(self.chipSize[1]) + , DbU.getValueString(self.sliceStep))) ) + adjust = self.sliceStep - self.chipSize[1] % self.sliceStep + self.chipSize = (self.chipSize[0], self.chipSize[1] + adjust) + + #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 padNet in netPads: + 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 ) + self.setRoutingBb( self.corona.getAbutmentBox() ) + + 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/harness/harness.py b/cumulus/src/plugins/alpha/harness/harness.py new file mode 100644 index 00000000..1724e9c9 --- /dev/null +++ b/cumulus/src/plugins/alpha/harness/harness.py @@ -0,0 +1,148 @@ + +# This file is part of the Coriolis Software. +# Copyright (c) Sorbonne Université 2014-2021, 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" | +# +-----------------------------------------------------------------+ + + +import sys +import traceback +import os.path +import optparse +import math +import cProfile +import pstats +import Cfg +import Hurricane +from Hurricane import DataBase, DbU ,Point, Transformation, Box, \ + Path, Occurrence, UpdateSession, Breakpoint, \ + Net, RoutingPad, Contact, Horizontal, Vertical, \ + Instance, HyperNet, Query +import Viewer +import CRL +from CRL import RoutingLayerGauge +import helpers +from helpers import trace +from helpers.io import ErrorMessage, 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.powerplane +import plugins.alpha.chip.corona + + +# -------------------------------------------------------------------- +# Class : "chip.Chip" + +class Chip ( Block ): + + def __init__ ( self, conf ): + super(Chip,self).__init__( conf ) + + 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 doChipFloorplan ( self ): + print( ' - Chip has {} north pads.'.format(len(self.conf.chipConf.northPads)) ) + print( ' - Chip has {} south pads.'.format(len(self.conf.chipConf.southPads)) ) + print( ' - Chip has {} east pads.' .format(len(self.conf.chipConf.eastPads )) ) + print( ' - Chip has {} west pads.' .format(len(self.conf.chipConf.westPads )) ) + self.conf.computeCoronaBorder() + self.conf.chipValidate() + if not self.conf.validated: + raise ErrorMessage( 1, 'chip.doChipFloorplan(): 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 ) + self.conf.validated = self.padsCorona.validate() + if not self.conf.validated: + return False + self.padsCorona.doLayout() + self.validate() + 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 + trace( 550, '\tCore X, {} '.format(DbU.getValueString(x)) ) + x = x - (x % self.conf.sliceHeight) + trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.conf.sliceHeight) + , DbU.getValueString(x)) ) + y = y - (y % self.conf.sliceHeight) + self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) ) + self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED ) + self.conf.refresh() + + def doConnectCore ( self ): + if self.padsCorona: + self.padsCorona.doPowerLayout() + if self.conf.routingGauge.hasPowerSupply(): + power = plugins.alpha.chip.powerplane.Builder( self.conf ) + power.connectPower() + #power.connectHTrees( self.hTrees ) + power.doLayout() + Breakpoint.stop( 101, 'After Query power.' ) + else: + power = plugins.alpha.chip.power.Builder( self.conf ) + power.connectPower() + power.connectClocks() + 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 ): + super(Chip,self).doPnR() + self.conf.refresh( self.conf.chip ) + return self.conf.validated + + def save ( self, flags=0 ): + if not self.conf.validated: + raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' ) + views = CRL.Catalog.State.Logical + if self.conf.routingGauge.isSymbolic(): + views = views | CRL.Catalog.State.Physical + super(Chip,self).save( flags )