From 181b2e108058b5c3fd17632ee47a83f68a9a3080 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Sat, 14 Jan 2023 12:39:22 +0100 Subject: [PATCH] Re-enable and check the building of I/O ring with pad spacers. * New: In cumulus/block.bigvia, add a getBoundingBox() method. * New: In cumulus/block.configuration.GaugeConf.rpAccess(), add a vertical strap segment in case the RP is not high enough to accomodate the potential offset of the contact. In case of gauge with only two routing layers, if the RP is vertically accessed, do not put a VIA12 but just a METAL2 contact (there will be *no* turn). * Change: In cumulus/chip.CoreWire.drawWire(), the wire at *chip level* going to the pad was shrunk of 3 pitch when *not* in the preferred routing direction. Removing it as it creates gaps in some cases. This was likely needed for a specific kind of I/O pad so should be re-enabled on targeted cases in the future. * Change: In cumulus/chip.corona.VerticalRail, manage in a smarter way the conflicts when a rail is accessed from both sides overlapping on an Y position. That is, from the supply I/O pads *and* from the *core* supply lines. Formerly, we just didn't connect the core power line, which was a mistake potentially leaving power rails unconnected (it it did occur on both sides). Also checks if the conflict really arise, that is, the power lines are both on top or bottom. * Change: In cumulus/chip.pads.Side._placePad(), manage I/O pads with a bottom left corner of abutment box *not* at (0,0). Argh! * Bug: In cumulus/chip.pads, create the filler pad instances in the chip, not in the corona. --- cumulus/src/plugins/alpha/block/bigvia.py | 6 ++ .../src/plugins/alpha/block/configuration.py | 59 ++++++++++++++---- cumulus/src/plugins/alpha/block/htree.py | 3 +- cumulus/src/plugins/alpha/chip/__init__.py | 38 +++++++----- cumulus/src/plugins/alpha/chip/corona.py | 60 ++++++++++++++----- cumulus/src/plugins/alpha/chip/pads.py | 44 ++++++++------ 6 files changed, 152 insertions(+), 58 deletions(-) diff --git a/cumulus/src/plugins/alpha/block/bigvia.py b/cumulus/src/plugins/alpha/block/bigvia.py index e3f2cfff..a395e915 100644 --- a/cumulus/src/plugins/alpha/block/bigvia.py +++ b/cumulus/src/plugins/alpha/block/bigvia.py @@ -89,6 +89,12 @@ class BigVia ( object ): def getNet ( self ): return self.net + def getBoundingBox ( self, depth ): + bb = Box( self.x, self.y ) + bb.inflate( self.widths[depth] // 2, self.heights[depth] // 2 ) + return bb + + def getPlate ( self, metal ): if not self.hasLayout: return None for plate in self.plates.values(): diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 6711f8a8..cf0c02aa 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -319,21 +319,60 @@ class GaugeConf ( object ): if flags & GaugeConf.OffsetTop2: yoffset = -2 trace( 550, '\tyoffset:{}\n'.format(yoffset) ) if startDepth == 0: - contact1 = Contact.create( rp, self._routingGauge.getContactLayer(0), 0, 0 ) - ytrack = self.getTrack( contact1.getY(), self.horizontalDeepDepth, yoffset ) - dy = ytrack - contact1.getY() - trace( 550, '\tPut on Y-tracks:{}\n'.format(DbU.getValueString(ytrack)) ) - contact1.setDy( dy ) + rg = self.routingGauge.getLayerGauge( 0 ) + rpContact = Contact.create( rp, rg.getLayer(), 0, 0 ) + ytrack = self.getTrack( rpContact.getY(), self.horizontalDeepDepth, yoffset ) + contact1 = Contact.create( rp.getNet() + , self._routingGauge.getContactLayer( 0 ) + , rpContact.getX() + , ytrack + , rg.getViaWidth() + , rg.getViaWidth() + ) + segment = Vertical.create( rpContact + , contact1 + , rpContact.getLayer() + , rpContact.getX() + , rg.getWireWidth() + ) + #dy = ytrack - contact1.getY() + #trace( 550, '\tPut on Y-tracks:{}\n'.format(DbU.getValueString(ytrack)) ) + #contact1.setDy( dy ) else: - contact1 = Contact.create( rp, self._routingGauge.getContactLayer(startDepth), 0, 0 ) - ytrack = self.getTrack( contact1.getY(), startDepth, 0 ) - dy = ytrack - contact1.getY() + rg = self.routingGauge.getLayerGauge( startDepth ) + rpContact = Contact.create( rp, rg.getLayer(), 0, 0 ) + ytrack = self.getTrack( rpContact.getY(), startDepth, 0 ) + #dy = ytrack - contact1.getY() + contact1 = Contact.create( rp.getNet() + , self._routingGauge.getContactLayer( startDepth ) + , rpContact.getX() + , ytrack + , rg.getViaWidth() + , rg.getViaWidth() + ) + segment = Vertical.create( rpContact + , contact1 + , rpContact.getLayer() + , rpContact.getX() + , rg.getWireWidth() + ) + trace( 550, '\trpContact:{}\n'.format( rpContact )) + trace( 550, '\tcontact1: {}\n'.format( contact1 )) + trace( 550, '\tsegment: {}\n'.format( segment )) startDepth += 1 - trace( 550, contact1 ) + trace( 550, '\tcontact1={}\n'.format( contact1 )) if flags & GaugeConf.HAccess: stopDepth = hdepth else: stopDepth = vdepth - trace( 550, '\tstopDepth:%d\n' % stopDepth ) + trace( 550, '\trange(startDepth={},stopDepth={})={}\n' \ + .format( startDepth, stopDepth, list(range(startDepth,stopDepth)) )) + + if startDepth >= stopDepth: + if not flags & GaugeConf.HAccess: + contact1.setLayer( rpContact.getLayer() ) + self._rpToAccess[rp] = contact1 + trace( 550, '-' ) + return contact1 for depth in range(startDepth,stopDepth): rg = self.routingGauge.getLayerGauge(depth) diff --git a/cumulus/src/plugins/alpha/block/htree.py b/cumulus/src/plugins/alpha/block/htree.py index f0ae35fe..92b2932b 100644 --- a/cumulus/src/plugins/alpha/block/htree.py +++ b/cumulus/src/plugins/alpha/block/htree.py @@ -154,12 +154,13 @@ class HTree ( object ): ckParentNet = qt.bInputPlug(0).getNet() driverContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.input, ckParentNet ) driverY = driverContact.getY() + trace( 550, '\tdriverContact={}\n'.format( driverContact )) if qt.bl: trace( 550, '+,', '\tblContact\n' ) blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 ) trace( 550, ',-', '\tblContact={}\n'.format(blContact) ) if qt.br: - trace( 550, '+,', '\trlContact\n' ) + trace( 550, '+,', '\tbrContact\n' ) brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 ) trace( 550, ',-', '\tbrContact={}\n'.format(brContact) ) if qt.tl: diff --git a/cumulus/src/plugins/alpha/chip/__init__.py b/cumulus/src/plugins/alpha/chip/__init__.py index adc1cd23..38adf3d1 100644 --- a/cumulus/src/plugins/alpha/chip/__init__.py +++ b/cumulus/src/plugins/alpha/chip/__init__.py @@ -203,9 +203,11 @@ class CoreWire ( object ): coronaAb = self.conf.getInstanceAb( self.conf.icorona ) coronaTransf = self.conf.icorona.getTransformation() self._computeCoreLayers() + trace( 550, '\tbbSegment: {}\n'.format(self.bbSegment) ) padLayer = self.padSegment.getLayer() if not isinstance(padLayer,BasicLayer): padLayer = padLayer.getBasicLayer() + trace( 550, '\tpadLayer={}\n'.format( padLayer )) if self.side == West or self.side == East: flags = OnHorizontalPitch hPitch = self.conf.getPitch( self.symSegmentLayer ) @@ -222,18 +224,20 @@ class CoreWire ( object ): xContact = self.corona.coreSymBb.getXMin() - self.offset * 2*vPitch xPadMax = xContact xCore = coronaAb.getXMin() - if not self.preferredDir: - #xPadMax += self.bbSegment.getHeight()//2 - xPadMin += 3*vPitch + trace( 550, '\txPadMin: {}\n'.format(DbU.getValueString( xPadMin ))) + #if not self.preferredDir: + # #xPadMax += self.bbSegment.getHeight()//2 + # xPadMin += 3*vPitch + # trace( 550, '\txPadMin: {}\n'.format(DbU.getValueString( xPadMin ))) else: accessDirection = Pin.Direction.EAST xPadMax = self.bbSegment.getXMax() xContact = self.corona.coreSymBb.getXMax() + self.offset * 2*vPitch xPadMin = xContact xCore = coronaAb.getXMax() - vPitch - if not self.preferredDir: - #xPadMin -= self.bbSegment.getHeight()//2 - xPadMin -= 3*vPitch + #if not self.preferredDir: + # #xPadMin -= self.bbSegment.getHeight()//2 + # xPadMin -= 3*vPitch if self.addJumper: rg = self.conf.routingGauge gaugeM5 = rg.getLayerGauge( 4 ) @@ -296,6 +300,7 @@ class CoreWire ( object ): , xPadMin , xPadMax ) + trace( 550, '\thChip={}\n'.format( hChip )) trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) ) if self.arraySize: contacts = self.conf.coronaContactArray( self.chipNet @@ -331,6 +336,7 @@ class CoreWire ( object ): , xContact , xCore ) + trace( 550, '\thCorona={}\n'.format( hCorona )) trace( 550, '\tCORONA PIN: {} {}\n'.format(self.chipNet, self.count) ) pin = self.conf.coronaPin( self.chipNet , self.count @@ -342,22 +348,26 @@ class CoreWire ( object ): , self.bbSegment.getHeight() ) hChipBb = hChip.getBoundingBox( padLayer ) + trace( 550, '\thChipBb={}\n'.format( hChipBb )) vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMin() ) vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMax() ) - hCoronaBb = hCorona.getBoundingBox( padLayer ) + #hCoronaBb = hCorona.getBoundingBox( padLayer ) + hCoronaBb = hCorona.getBoundingBox() self.conf.icorona.getTransformation().applyOn( hCoronaBb ) + trace( 550, '\thCoronaBb={}\n'.format( hCoronaBb )) vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMin() ) vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.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() - ) + v = Vertical.create( self.chipNet + , self.padSegment.getLayer() + , vStrapBb.getCenter().getX() + , vStrapBb.getWidth() + , vStrapBb.getYMin() + , vStrapBb.getYMax() + ) + trace( 550, '\tvChip={}\n'.format( v )) else: flags = OnVerticalPitch hPitch = self.conf.getPitch( self.padSegment.getLayer() ) diff --git a/cumulus/src/plugins/alpha/chip/corona.py b/cumulus/src/plugins/alpha/chip/corona.py index 1ca8cb0d..65e41802 100644 --- a/cumulus/src/plugins/alpha/chip/corona.py +++ b/cumulus/src/plugins/alpha/chip/corona.py @@ -13,8 +13,9 @@ # +-----------------------------------------------------------------+ +import sys import bisect -from operator import methodcaller +from operator import methodcaller, xor import Cfg from Hurricane import DbU, Point, Interval, Box, Transformation, \ Path, Occurrence, Net, Contact, Horizontal, \ @@ -100,8 +101,7 @@ class HorizontalRail ( Rail ): return ''.format( self.side.getRailNet(self.order).getName() , self.order , DbU.getValueString(self.axis) ) - - def connect ( self, contact ): + def isReachable ( self, contact ): trace( 550, ',+', '\tTry to connect to: {}\n'.format(self) ) trace( 550, '\tContact {}\n'.format(contact) ) contactBb = contact.getBoundingBox() @@ -132,6 +132,10 @@ class HorizontalRail ( Rail ): trace( 550, ',-', '\tFailed: overlap with existing contact @{}.\n' \ .format(self.vias[keys[insertIndex-1]][2]) ) return False + trace( 550, ',-' ) + return True + + def connect ( self, contact ): viaWidth = contact.getWidth() viaHeight = self.side.hRailWidth if self.conf.routingGauge.isSymbolic(): @@ -152,7 +156,6 @@ class HorizontalRail ( Rail ): , DbU.getValueString(contact.getX()) , DbU.getValueString(self.axis)) ) self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) - trace( 550, '-' ) return True def doLayout ( self ): @@ -218,8 +221,11 @@ class VerticalRail ( Rail ): , self.side.vRailWidth ) - def connect ( self, contact ): - contactBb = contact.getBoundingBox() + def isReachable ( self, contact ): + railDepth = self.conf.routingGauge.getLayerDepth( self.side.getVLayer() ) + contactDepth = self.conf.routingGauge.getLayerDepth( contact.getLayer() ) + contactBb = contact.getBoundingBox() + contactAbove = True if contactDepth > railDepth else False if contactBb.getYMin() < self.side.innerBb.getYMin() \ or contactBb.getYMax() > self.side.innerBb.getYMax(): # XXX turn this into a non-fatal case. ERROR is still printed, @@ -228,7 +234,7 @@ class VerticalRail ( Rail ): , 'power pad is likely to be to far off north or south.' , '(core:{})'.format(self.side.innerBb) ] ) ) if contact.getY() in self.vias: return False - trace( 550, ',+', '\tVerticalRail.connect() [{}] @{}\n'.format(self.order,DbU.getValueString(self.axis)) ) + trace( 550, ',+', '\tVerticalRail.isReachable() [{}] @{}\n'.format(self.order,DbU.getValueString(self.axis)) ) trace( 550, '\t{}\n'.format(contact) ) keys = list( self.vias.keys() ) keys.sort() @@ -241,20 +247,43 @@ class VerticalRail ( Rail ): if len(keys) > 0: if insertIndex < len(keys): insertPosition = keys[ insertIndex ] - trace( 550, '\tinsertIndex:{}'.format(insertIndex) ) + trace( 550, '\tinsertIndex:{}\n'.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(): + , self.vias[insertPosition][1].getBoundingBox(railDepth)) ) + if self.vias[insertPosition][1].bottomDepth < railDepth: bigviaAbove = False + elif self.vias[insertPosition][1].topDepth > railDepth: bigviaAbove = True + else: + print( ErrorMessage( 1, [ '{} neither above nor below' \ + .format( self.vias[insertPosition][1] ) ] )) + trace( 550, '\tcontactAbove={} bigviaAbove={}\n'.format( contactAbove, bigviaAbove )) + if contactBb.getYMax() >= self.vias[insertPosition][1].getBoundingBox(railDepth).getYMin() \ + and not xor(contactAbove,bigviaAbove): trace( 550, ',--', '\tReject {} intersect NEXT\n'.format(contact) ) return False if insertIndex > 0: + insertPosition = keys[ insertIndex-1 ] 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(): + , self.vias[insertPosition][1].getBoundingBox(railDepth)) ) + if self.vias[insertPosition][1].bottomDepth < railDepth: bigviaAbove = False + elif self.vias[insertPosition][1].topDepth > railDepth: bigviaAbove = True + else: + print( ErrorMessage( 1, [ '{} neither above nor below' \ + .format( self.vias[insertPosition][1] ) ] )) + trace( 550, '\tcontactAbove={} bigviaAbove={}\n'.format( contactAbove, bigviaAbove )) + if self.vias[insertPosition][1].getBoundingBox(railDepth).getYMax() >= contactBb.getYMin() \ + and not xor(contactAbove,bigviaAbove): trace( 550, ',--', '\tReject {} intersect PREVIOUS\n'.format(contact) ) return False + trace( 550, ',--' ) + return True + + def connect ( self, contact ): + trace( 550, '\tVerticalRail.connect() {}\n'.format(contact) ) + if self.net != contact.getNet(): + trace( 550, '\tReject {} vs. {}\n'.format( self.net, contact.getNet() )) + return False viaWidth = self.side.vRailWidth viaHeight = contact.getHeight() if self.conf.routingGauge.isSymbolic(): @@ -269,8 +298,8 @@ class VerticalRail ( Rail ): , contact.getHeight() - DbU.fromLambda(1.0) , flags=BigVia.AllowAllExpand ) , contact ] - trace(550, ',--' '\tADD {}\n'.format(contact) ) self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) + trace( 550, '\t-> BigVIA {}\n'.format(self.vias[ contact.getY() ][1]) ) return True @@ -348,15 +377,18 @@ class Side ( object ): for terminal in blockSide.terminals: trace( 550, '\tterminal:{}\n'.format(terminal) ) for rail in self.rails: + if not rail.isReachable( terminal[1] ): + break rail.connect( terminal[1] ) def getRailRange ( self, net ): if net.isClock(): return range(len(self.rails)) if not net.isSupply(): return [] if self.side & HORIZONTAL: - trace( 550, '\tHORIZONTAL rail.\n' ) + trace( 550, '\tHorizontal rail.\n' ) return range( len(self.coronaCks), len(self.rails) ) else: + trace( 550, '\tVertical rail.\n' ) trace( 550, '\t{} > {}\n'.format(self.horizontalDepth,self.verticalDepth) ) if self.horizontalDepth > self.verticalDepth: return range( len(self.coronaCks), len(self.rails) ) diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py index 50fd9eff..5334ea52 100644 --- a/cumulus/src/plugins/alpha/chip/pads.py +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -150,7 +150,7 @@ class Corner ( object ): def _instanciateCorner ( self ): name, transformation = self._getTransformation() - corner = Instance.create( self.conf.cell + corner = Instance.create( self.conf.chip , name, self.corona.padCorner , transformation , Instance.PlacementStatus.FIXED @@ -278,7 +278,7 @@ class Side ( object ): iPadSpacer = _nextSpacer( iPadSpacer ) while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0: gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] ) - spacer = Instance.create( self.conf.cell + spacer = Instance.create( self.conf.chip , self.spacerNames % self.spacerCount , self.corona.padSpacers[iPadSpacer]) self.spacerCount += 1 @@ -286,13 +286,14 @@ class Side ( object ): 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)) ) + print( 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 ): + padAb = padInstance.getMasterCell().getAbutmentBox() if self.type == North: - x = self.conf.chipAb.getXMin() + self.u + x = self.conf.chipAb.getXMin() + self.u - padAb.getXMin() y = self.conf.chipAb.getYMax() if self.corona.padOrient == Transformation.Orientation.ID: orientation = Transformation.Orientation.MY @@ -301,7 +302,7 @@ class Side ( object ): y -= self.conf.ioPadHeight x = self.toGrid( x ) elif self.type == South: - x = self.conf.chipAb.getXMin() + self.u + x = self.conf.chipAb.getXMin() + self.u - padAb.getXMin() y = self.conf.chipAb.getYMin() if self.corona.padOrient == Transformation.Orientation.ID: orientation = Transformation.Orientation.ID @@ -311,27 +312,29 @@ class Side ( object ): x = self.toGrid( x ) elif self.type == West: x = self.conf.chipAb.getXMin() - y = self.conf.chipAb.getYMin() + self.u + y = self.conf.chipAb.getYMin() + self.u + padAb.getXMin() if self.corona.padOrient == Transformation.Orientation.ID: orientation = Transformation.Orientation.R3 - y += padInstance.getMasterCell().getAbutmentBox().getWidth() + y += padAb.getWidth() else: orientation = Transformation.Orientation.R1 - x += padInstance.getMasterCell().getAbutmentBox().getHeight() + x += padAb.getHeight() y = self.toGrid( y ) elif self.type == East: x = self.conf.chipAb.getXMax() y = self.conf.chipAb.getYMin() + self.u + if padAb.getXMin(): + y += padAb.getXMin() + padAb.getWidth() 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() + x -= padAb.getHeight() + y += padAb.getWidth() y = self.toGrid( y ) padInstance.setTransformation ( Transformation( x, y, orientation ) ) padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED ) - self.u += padInstance.getMasterCell().getAbutmentBox().getWidth() + self.u += padAb.getWidth() p = None if self.conf.ioPadGauge.getName() == 'pxlib': p = re.compile( r'p(?Pv[sd]{2}[ei])ck_px' ) @@ -510,12 +513,15 @@ class Corona ( object ): def __init__ ( self, chip ): - 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 _cmpPad ( pad ): + return pad.getAbutmentBox().getWidth() + + #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 = [] @@ -560,7 +566,7 @@ class Corona ( object ): if spacerCell: self.padSpacers.append( spacerCell ) else: raise ErrorMessage( 1, 'Corona.__init__(): Missing spacer cell "{}"'.format(spacerName) ) - self.padSpacers.sort( _cmpPad ) + self.padSpacers = sorted( self.padSpacers, key=_cmpPad, reverse=True ) if self.conf.cfg.chip.padCorner is not None: self.padCorner = self.padLib.getCell( self.conf.cfg.chip.padCorner ) if self.conf.cfg.chip.minPadSpacing is None: