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.
This commit is contained in:
Jean-Paul Chaput 2023-01-14 12:39:22 +01:00
parent 0e17b91692
commit 181b2e1080
6 changed files with 152 additions and 58 deletions

View File

@ -89,6 +89,12 @@ class BigVia ( object ):
def getNet ( self ): return self.net 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 ): def getPlate ( self, metal ):
if not self.hasLayout: return None if not self.hasLayout: return None
for plate in self.plates.values(): for plate in self.plates.values():

View File

@ -319,21 +319,60 @@ class GaugeConf ( object ):
if flags & GaugeConf.OffsetTop2: yoffset = -2 if flags & GaugeConf.OffsetTop2: yoffset = -2
trace( 550, '\tyoffset:{}\n'.format(yoffset) ) trace( 550, '\tyoffset:{}\n'.format(yoffset) )
if startDepth == 0: if startDepth == 0:
contact1 = Contact.create( rp, self._routingGauge.getContactLayer(0), 0, 0 ) rg = self.routingGauge.getLayerGauge( 0 )
ytrack = self.getTrack( contact1.getY(), self.horizontalDeepDepth, yoffset ) rpContact = Contact.create( rp, rg.getLayer(), 0, 0 )
dy = ytrack - contact1.getY() ytrack = self.getTrack( rpContact.getY(), self.horizontalDeepDepth, yoffset )
trace( 550, '\tPut on Y-tracks:{}\n'.format(DbU.getValueString(ytrack)) ) contact1 = Contact.create( rp.getNet()
contact1.setDy( dy ) , 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: else:
contact1 = Contact.create( rp, self._routingGauge.getContactLayer(startDepth), 0, 0 ) rg = self.routingGauge.getLayerGauge( startDepth )
ytrack = self.getTrack( contact1.getY(), startDepth, 0 ) rpContact = Contact.create( rp, rg.getLayer(), 0, 0 )
dy = ytrack - contact1.getY() 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 startDepth += 1
trace( 550, contact1 ) trace( 550, '\tcontact1={}\n'.format( contact1 ))
if flags & GaugeConf.HAccess: stopDepth = hdepth if flags & GaugeConf.HAccess: stopDepth = hdepth
else: stopDepth = vdepth 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): for depth in range(startDepth,stopDepth):
rg = self.routingGauge.getLayerGauge(depth) rg = self.routingGauge.getLayerGauge(depth)

View File

@ -154,12 +154,13 @@ class HTree ( object ):
ckParentNet = qt.bInputPlug(0).getNet() ckParentNet = qt.bInputPlug(0).getNet()
driverContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.input, ckParentNet ) driverContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.input, ckParentNet )
driverY = driverContact.getY() driverY = driverContact.getY()
trace( 550, '\tdriverContact={}\n'.format( driverContact ))
if qt.bl: if qt.bl:
trace( 550, '+,', '\tblContact\n' ) trace( 550, '+,', '\tblContact\n' )
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 ) blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 )
trace( 550, ',-', '\tblContact={}\n'.format(blContact) ) trace( 550, ',-', '\tblContact={}\n'.format(blContact) )
if qt.br: if qt.br:
trace( 550, '+,', '\trlContact\n' ) trace( 550, '+,', '\tbrContact\n' )
brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 ) brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0], bufferConf.input, ckNet, GaugeConf.OffsetLeft1 )
trace( 550, ',-', '\tbrContact={}\n'.format(brContact) ) trace( 550, ',-', '\tbrContact={}\n'.format(brContact) )
if qt.tl: if qt.tl:

View File

@ -203,9 +203,11 @@ class CoreWire ( object ):
coronaAb = self.conf.getInstanceAb( self.conf.icorona ) coronaAb = self.conf.getInstanceAb( self.conf.icorona )
coronaTransf = self.conf.icorona.getTransformation() coronaTransf = self.conf.icorona.getTransformation()
self._computeCoreLayers() self._computeCoreLayers()
trace( 550, '\tbbSegment: {}\n'.format(self.bbSegment) )
padLayer = self.padSegment.getLayer() padLayer = self.padSegment.getLayer()
if not isinstance(padLayer,BasicLayer): if not isinstance(padLayer,BasicLayer):
padLayer = padLayer.getBasicLayer() padLayer = padLayer.getBasicLayer()
trace( 550, '\tpadLayer={}\n'.format( padLayer ))
if self.side == West or self.side == East: if self.side == West or self.side == East:
flags = OnHorizontalPitch flags = OnHorizontalPitch
hPitch = self.conf.getPitch( self.symSegmentLayer ) hPitch = self.conf.getPitch( self.symSegmentLayer )
@ -222,18 +224,20 @@ class CoreWire ( object ):
xContact = self.corona.coreSymBb.getXMin() - self.offset * 2*vPitch xContact = self.corona.coreSymBb.getXMin() - self.offset * 2*vPitch
xPadMax = xContact xPadMax = xContact
xCore = coronaAb.getXMin() xCore = coronaAb.getXMin()
if not self.preferredDir: trace( 550, '\txPadMin: {}\n'.format(DbU.getValueString( xPadMin )))
#xPadMax += self.bbSegment.getHeight()//2 #if not self.preferredDir:
xPadMin += 3*vPitch # #xPadMax += self.bbSegment.getHeight()//2
# xPadMin += 3*vPitch
# trace( 550, '\txPadMin: {}\n'.format(DbU.getValueString( xPadMin )))
else: else:
accessDirection = Pin.Direction.EAST accessDirection = Pin.Direction.EAST
xPadMax = self.bbSegment.getXMax() xPadMax = self.bbSegment.getXMax()
xContact = self.corona.coreSymBb.getXMax() + self.offset * 2*vPitch xContact = self.corona.coreSymBb.getXMax() + self.offset * 2*vPitch
xPadMin = xContact xPadMin = xContact
xCore = coronaAb.getXMax() - vPitch xCore = coronaAb.getXMax() - vPitch
if not self.preferredDir: #if not self.preferredDir:
#xPadMin -= self.bbSegment.getHeight()//2 # #xPadMin -= self.bbSegment.getHeight()//2
xPadMin -= 3*vPitch # xPadMin -= 3*vPitch
if self.addJumper: if self.addJumper:
rg = self.conf.routingGauge rg = self.conf.routingGauge
gaugeM5 = rg.getLayerGauge( 4 ) gaugeM5 = rg.getLayerGauge( 4 )
@ -296,6 +300,7 @@ class CoreWire ( object ):
, xPadMin , xPadMin
, xPadMax , xPadMax
) )
trace( 550, '\thChip={}\n'.format( hChip ))
trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) ) trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) )
if self.arraySize: if self.arraySize:
contacts = self.conf.coronaContactArray( self.chipNet contacts = self.conf.coronaContactArray( self.chipNet
@ -331,6 +336,7 @@ class CoreWire ( object ):
, xContact , xContact
, xCore , xCore
) )
trace( 550, '\thCorona={}\n'.format( hCorona ))
trace( 550, '\tCORONA PIN: {} {}\n'.format(self.chipNet, self.count) ) trace( 550, '\tCORONA PIN: {} {}\n'.format(self.chipNet, self.count) )
pin = self.conf.coronaPin( self.chipNet pin = self.conf.coronaPin( self.chipNet
, self.count , self.count
@ -342,22 +348,26 @@ class CoreWire ( object ):
, self.bbSegment.getHeight() , self.bbSegment.getHeight()
) )
hChipBb = hChip.getBoundingBox( padLayer ) hChipBb = hChip.getBoundingBox( padLayer )
trace( 550, '\thChipBb={}\n'.format( hChipBb ))
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMin() ) vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMin() )
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMax() ) vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMax() )
hCoronaBb = hCorona.getBoundingBox( padLayer ) #hCoronaBb = hCorona.getBoundingBox( padLayer )
hCoronaBb = hCorona.getBoundingBox()
self.conf.icorona.getTransformation().applyOn( hCoronaBb ) self.conf.icorona.getTransformation().applyOn( hCoronaBb )
trace( 550, '\thCoronaBb={}\n'.format( hCoronaBb ))
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMin() ) vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMin() )
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMax() ) vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMax() )
if self.padSegment.getLayer().isSymbolic(): if self.padSegment.getLayer().isSymbolic():
vStrapBb.inflate( 0, -self.padSegment.getLayer().getExtentionCap() vStrapBb.inflate( 0, -self.padSegment.getLayer().getExtentionCap()
, 0, -self.padSegment.getLayer().getExtentionCap() ) , 0, -self.padSegment.getLayer().getExtentionCap() )
Vertical.create( self.chipNet v = Vertical.create( self.chipNet
, self.padSegment.getLayer() , self.padSegment.getLayer()
, vStrapBb.getCenter().getX() , vStrapBb.getCenter().getX()
, vStrapBb.getWidth() , vStrapBb.getWidth()
, vStrapBb.getYMin() , vStrapBb.getYMin()
, vStrapBb.getYMax() , vStrapBb.getYMax()
) )
trace( 550, '\tvChip={}\n'.format( v ))
else: else:
flags = OnVerticalPitch flags = OnVerticalPitch
hPitch = self.conf.getPitch( self.padSegment.getLayer() ) hPitch = self.conf.getPitch( self.padSegment.getLayer() )

View File

@ -13,8 +13,9 @@
# +-----------------------------------------------------------------+ # +-----------------------------------------------------------------+
import sys
import bisect import bisect
from operator import methodcaller from operator import methodcaller, xor
import Cfg import Cfg
from Hurricane import DbU, Point, Interval, Box, Transformation, \ from Hurricane import DbU, Point, Interval, Box, Transformation, \
Path, Occurrence, Net, Contact, Horizontal, \ Path, Occurrence, Net, Contact, Horizontal, \
@ -100,8 +101,7 @@ class HorizontalRail ( Rail ):
return '<HorizontalRail "{}" ({}) @{}>'.format( self.side.getRailNet(self.order).getName() return '<HorizontalRail "{}" ({}) @{}>'.format( self.side.getRailNet(self.order).getName()
, self.order , self.order
, DbU.getValueString(self.axis) ) , DbU.getValueString(self.axis) )
def isReachable ( self, contact ):
def connect ( self, contact ):
trace( 550, ',+', '\tTry to connect to: {}\n'.format(self) ) trace( 550, ',+', '\tTry to connect to: {}\n'.format(self) )
trace( 550, '\tContact {}\n'.format(contact) ) trace( 550, '\tContact {}\n'.format(contact) )
contactBb = contact.getBoundingBox() contactBb = contact.getBoundingBox()
@ -132,6 +132,10 @@ class HorizontalRail ( Rail ):
trace( 550, ',-', '\tFailed: overlap with existing contact @{}.\n' \ trace( 550, ',-', '\tFailed: overlap with existing contact @{}.\n' \
.format(self.vias[keys[insertIndex-1]][2]) ) .format(self.vias[keys[insertIndex-1]][2]) )
return False return False
trace( 550, ',-' )
return True
def connect ( self, contact ):
viaWidth = contact.getWidth() viaWidth = contact.getWidth()
viaHeight = self.side.hRailWidth viaHeight = self.side.hRailWidth
if self.conf.routingGauge.isSymbolic(): if self.conf.routingGauge.isSymbolic():
@ -152,7 +156,6 @@ class HorizontalRail ( Rail ):
, DbU.getValueString(contact.getX()) , DbU.getValueString(contact.getX())
, DbU.getValueString(self.axis)) ) , DbU.getValueString(self.axis)) )
self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
trace( 550, '-' )
return True return True
def doLayout ( self ): def doLayout ( self ):
@ -218,8 +221,11 @@ class VerticalRail ( Rail ):
, self.side.vRailWidth , self.side.vRailWidth
) )
def connect ( self, contact ): def isReachable ( self, contact ):
contactBb = contact.getBoundingBox() 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() \ if contactBb.getYMin() < self.side.innerBb.getYMin() \
or contactBb.getYMax() > self.side.innerBb.getYMax(): or contactBb.getYMax() > self.side.innerBb.getYMax():
# XXX turn this into a non-fatal case. ERROR is still printed, # 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.' , 'power pad is likely to be to far off north or south.'
, '(core:{})'.format(self.side.innerBb) ] ) ) , '(core:{})'.format(self.side.innerBb) ] ) )
if contact.getY() in self.vias: return False 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) ) trace( 550, '\t{}\n'.format(contact) )
keys = list( self.vias.keys() ) keys = list( self.vias.keys() )
keys.sort() keys.sort()
@ -241,20 +247,43 @@ class VerticalRail ( Rail ):
if len(keys) > 0: if len(keys) > 0:
if insertIndex < len(keys): if insertIndex < len(keys):
insertPosition = keys[ insertIndex ] insertPosition = keys[ insertIndex ]
trace( 550, '\tinsertIndex:{}'.format(insertIndex) ) trace( 550, '\tinsertIndex:{}\n'.format(insertIndex) )
trace( 550, '\tCheck NEXT contactBb:{} via:{}\n' \ trace( 550, '\tCheck NEXT contactBb:{} via:{}\n' \
.format( contactBb .format( contactBb
, self.vias[insertPosition][2].getBoundingBox()) ) , self.vias[insertPosition][1].getBoundingBox(railDepth)) )
if contactBb.getYMax() >= self.vias[insertPosition][2].getBoundingBox().getYMin(): 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) ) trace( 550, ',--', '\tReject {} intersect NEXT\n'.format(contact) )
return False return False
if insertIndex > 0: if insertIndex > 0:
insertPosition = keys[ insertIndex-1 ]
trace( 550, '\tcheck PREVIOUS contactBb:{} via:{}\n' \ trace( 550, '\tcheck PREVIOUS contactBb:{} via:{}\n' \
.format( contactBb .format( contactBb
, self.vias[keys[insertIndex-1]][2].getBoundingBox()) ) , self.vias[insertPosition][1].getBoundingBox(railDepth)) )
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getYMax() >= contactBb.getYMin(): 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) ) trace( 550, ',--', '\tReject {} intersect PREVIOUS\n'.format(contact) )
return False 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 viaWidth = self.side.vRailWidth
viaHeight = contact.getHeight() viaHeight = contact.getHeight()
if self.conf.routingGauge.isSymbolic(): if self.conf.routingGauge.isSymbolic():
@ -269,8 +298,8 @@ class VerticalRail ( Rail ):
, contact.getHeight() - DbU.fromLambda(1.0) , contact.getHeight() - DbU.fromLambda(1.0)
, flags=BigVia.AllowAllExpand ) , flags=BigVia.AllowAllExpand )
, contact ] , contact ]
trace(550, ',--' '\tADD {}\n'.format(contact) )
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
trace( 550, '\t-> BigVIA {}\n'.format(self.vias[ contact.getY() ][1]) )
return True return True
@ -348,15 +377,18 @@ class Side ( object ):
for terminal in blockSide.terminals: for terminal in blockSide.terminals:
trace( 550, '\tterminal:{}\n'.format(terminal) ) trace( 550, '\tterminal:{}\n'.format(terminal) )
for rail in self.rails: for rail in self.rails:
if not rail.isReachable( terminal[1] ):
break
rail.connect( terminal[1] ) rail.connect( terminal[1] )
def getRailRange ( self, net ): def getRailRange ( self, net ):
if net.isClock(): return range(len(self.rails)) if net.isClock(): return range(len(self.rails))
if not net.isSupply(): return [] if not net.isSupply(): return []
if self.side & HORIZONTAL: if self.side & HORIZONTAL:
trace( 550, '\tHORIZONTAL rail.\n' ) trace( 550, '\tHorizontal rail.\n' )
return range( len(self.coronaCks), len(self.rails) ) return range( len(self.coronaCks), len(self.rails) )
else: else:
trace( 550, '\tVertical rail.\n' )
trace( 550, '\t{} > {}\n'.format(self.horizontalDepth,self.verticalDepth) ) trace( 550, '\t{} > {}\n'.format(self.horizontalDepth,self.verticalDepth) )
if self.horizontalDepth > self.verticalDepth: if self.horizontalDepth > self.verticalDepth:
return range( len(self.coronaCks), len(self.rails) ) return range( len(self.coronaCks), len(self.rails) )

View File

@ -150,7 +150,7 @@ class Corner ( object ):
def _instanciateCorner ( self ): def _instanciateCorner ( self ):
name, transformation = self._getTransformation() name, transformation = self._getTransformation()
corner = Instance.create( self.conf.cell corner = Instance.create( self.conf.chip
, name, self.corona.padCorner , name, self.corona.padCorner
, transformation , transformation
, Instance.PlacementStatus.FIXED , Instance.PlacementStatus.FIXED
@ -278,7 +278,7 @@ class Side ( object ):
iPadSpacer = _nextSpacer( iPadSpacer ) iPadSpacer = _nextSpacer( iPadSpacer )
while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0: while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0:
gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] ) gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] )
spacer = Instance.create( self.conf.cell spacer = Instance.create( self.conf.chip
, self.spacerNames % self.spacerCount , self.spacerNames % self.spacerCount
, self.corona.padSpacers[iPadSpacer]) , self.corona.padSpacers[iPadSpacer])
self.spacerCount += 1 self.spacerCount += 1
@ -286,13 +286,14 @@ class Side ( object ):
if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]): if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
iPadSpacer = _nextSpacer( iPadSpacer ) iPadSpacer = _nextSpacer( iPadSpacer )
if gapWidth != 0: if gapWidth != 0:
raise ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \ print( ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \
.format(self.sideName,DbU.getValueString(gapWidth)) ) .format(self.sideName,DbU.getValueString(gapWidth)) ))
self.u += gapWidth self.u += gapWidth
def _placePad ( self, padInstance ): def _placePad ( self, padInstance ):
padAb = padInstance.getMasterCell().getAbutmentBox()
if self.type == North: 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() y = self.conf.chipAb.getYMax()
if self.corona.padOrient == Transformation.Orientation.ID: if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.MY orientation = Transformation.Orientation.MY
@ -301,7 +302,7 @@ class Side ( object ):
y -= self.conf.ioPadHeight y -= self.conf.ioPadHeight
x = self.toGrid( x ) x = self.toGrid( x )
elif self.type == South: 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() y = self.conf.chipAb.getYMin()
if self.corona.padOrient == Transformation.Orientation.ID: if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.ID orientation = Transformation.Orientation.ID
@ -311,27 +312,29 @@ class Side ( object ):
x = self.toGrid( x ) x = self.toGrid( x )
elif self.type == West: elif self.type == West:
x = self.conf.chipAb.getXMin() 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: if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R3 orientation = Transformation.Orientation.R3
y += padInstance.getMasterCell().getAbutmentBox().getWidth() y += padAb.getWidth()
else: else:
orientation = Transformation.Orientation.R1 orientation = Transformation.Orientation.R1
x += padInstance.getMasterCell().getAbutmentBox().getHeight() x += padAb.getHeight()
y = self.toGrid( y ) y = self.toGrid( y )
elif self.type == East: elif self.type == East:
x = self.conf.chipAb.getXMax() x = self.conf.chipAb.getXMax()
y = self.conf.chipAb.getYMin() + self.u y = self.conf.chipAb.getYMin() + self.u
if padAb.getXMin():
y += padAb.getXMin() + padAb.getWidth()
if self.corona.padOrient == Transformation.Orientation.ID: if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R1 orientation = Transformation.Orientation.R1
else: else:
orientation = Transformation.Orientation.R3 orientation = Transformation.Orientation.R3
x -= padInstance.getMasterCell().getAbutmentBox().getHeight() x -= padAb.getHeight()
y += padInstance.getMasterCell().getAbutmentBox().getWidth() y += padAb.getWidth()
y = self.toGrid( y ) y = self.toGrid( y )
padInstance.setTransformation ( Transformation( x, y, orientation ) ) padInstance.setTransformation ( Transformation( x, y, orientation ) )
padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED ) padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.u += padInstance.getMasterCell().getAbutmentBox().getWidth() self.u += padAb.getWidth()
p = None p = None
if self.conf.ioPadGauge.getName() == 'pxlib': if self.conf.ioPadGauge.getName() == 'pxlib':
p = re.compile( r'p(?P<power>v[sd]{2}[ei])ck_px' ) p = re.compile( r'p(?P<power>v[sd]{2}[ei])ck_px' )
@ -510,12 +513,15 @@ class Corona ( object ):
def __init__ ( self, chip ): def __init__ ( self, chip ):
def _cmpPad ( pad1, pad2): def _cmpPad ( pad ):
width1 = pad1.getAbutmentBox().getWidth() return pad.getAbutmentBox().getWidth()
width2 = pad2.getAbutmentBox().getWidth()
if width1 == width2: return 0 #def _cmpPad ( pad1, pad2):
if width1 > width2: return -1 # width1 = pad1.getAbutmentBox().getWidth()
return 1 # width2 = pad2.getAbutmentBox().getWidth()
# if width1 == width2: return 0
# if width1 > width2: return -1
# return 1
def _dupPads ( padsConf ): def _dupPads ( padsConf ):
duplicateds = [] duplicateds = []
@ -560,7 +566,7 @@ class Corona ( object ):
if spacerCell: self.padSpacers.append( spacerCell ) if spacerCell: self.padSpacers.append( spacerCell )
else: else:
raise ErrorMessage( 1, 'Corona.__init__(): Missing spacer cell "{}"'.format(spacerName) ) 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: if self.conf.cfg.chip.padCorner is not None:
self.padCorner = self.padLib.getCell( self.conf.cfg.chip.padCorner ) self.padCorner = self.padLib.getCell( self.conf.cfg.chip.padCorner )
if self.conf.cfg.chip.minPadSpacing is None: if self.conf.cfg.chip.minPadSpacing is None: