#!/usr/bin/env python # # This file is part of the Coriolis Software. # Copyright (c) UPMC 2014-2014, 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@asim.lip6.fr | # | =============================================================== | # | Python : "./plugins/chip/PadsCorona.py" | # +-----------------------------------------------------------------+ from operator import itemgetter import Cfg from Hurricane import DbU from Hurricane import Point from Hurricane import Transformation from Hurricane import Box from Hurricane import Path from Hurricane import Occurrence from Hurricane import UpdateSession from Hurricane import Net from Hurricane import Contact from Hurricane import Horizontal from Hurricane import Vertical from Hurricane import Instance import CRL from CRL import RoutingLayerGauge from helpers import ErrorMessage from helpers import WarningMessage import chip.Configuration class Side ( object ): def __init__ ( self, corona, sideType ): self._type = sideType self._corona = corona self._powerContacts = [] if self._type == chip.North: self._pads = self._corona.northPads elif self._type == chip.South: self._pads = self._corona.southPads elif self._type == chip.East: self._pads = self._corona.eastPads elif self._type == chip.West: self._pads = self._corona.westPads else: raise ErrorMessage( 1, 'PadsCorona.Side.__init__(): Invalid value for sideType (%d)' % sideType ) return def _toGrid ( self, v ): return v - (v % DbU.fromLambda(5.0)) def getAxis ( self, i ): if self._type == chip.North: return self._corona.chipSize.getXMax() - self._corona.padHeight + self._corona._powerRails[i][2] elif self._type == chip.South: return self._corona.chipSize.getXMin() + self._corona.padHeight - self._corona._powerRails[i][2] elif self._type == chip.East: return self._corona.chipSize.getYMax() - self._corona.padHeight + self._corona._powerRails[i][2] elif self._type == chip.West: return self._corona.chipSize.getYMin() + self._corona.padHeight - self._corona._powerRails[i][2] else: raise ErrorMessage( 1, 'PadsCorona.Side.__init__(): Invalid value for sideType (%d)' % sideType ) return 0 def _check ( self, checkSize, checkName ): sideName = 'unknown' chipSize = 0 if self._type == chip.North or self._type == chip.South: chipSize = self._corona.chipSize.getWidth() sideName = 'wide' elif self._type == chip.East or self._type == chip.West: chipSize = self._corona.chipSize.getHeight() sideName = 'tall' if checkSize > chipSize: print ErrorMessage( 1, [ 'Chip is not %s enought to accomodate the %s,' % (sideName,checkName) , 'needs %dl, but only has %dl.' % ( DbU.toLambda(checkSize), DbU.toLambda(chipSize) ) ] ) return False return True def check ( self ): validated = True if self._type == chip.North: self.validated = self._check( self._corona.coreSize.getWidth() + 2*self._corona.minCorona + 2*self._corona.padHeight , 'core' ) checkName = 'north pads' elif self._type == chip.East: self.validated = self._check( self._corona.coreSize.getHeight() + 2*self._corona.minCorona + 2*self._corona.padHeight , 'core' ) checkName = 'east pads' elif self._type == chip.South: checkName = 'south pads' elif self._type == chip.West: checkName = 'west pads' validated = self._check( len(self._pads)*self._corona.padWidth + 2*self._corona.padHeight , checkName ) and validated return validated def _createPowerContacts ( self, pad, net ): if self._type == chip.North or self._type == chip.South: hvDepth = self._corona.getVDepth() elif self._type == chip.East or self._type == chip.West: hvDepth = self._corona.getHDepth() masterCell = pad.getMasterCell() for component in masterCell.getNet(net.getName()).getExternalComponents(): if component.getBoundingBox().getYMin() > masterCell.getAbutmentBox().getYMin(): continue if self._corona.routingGauge.getLayerDepth(component.getLayer()) != hvDepth: continue if not isinstance(component,Vertical): continue if self._type == chip.North or self._type == chip.South: width = component.getWidth() height = 0 else: width = 0 height = component.getWidth() position = Point( component.getX(), masterCell.getAbutmentBox().getYMin() ) pad.getTransformation().applyOn( position ) self._powerContacts.append( Contact.create( net , component.getLayer() , position.getX() , position.getY() , width , height ) ) return def _createAllPowerContacts ( self ): for pad in self._pads: masterCell = pad.getMasterCell() if masterCell.getName() != 'pvddick_px' \ and masterCell.getName() != 'pvssick_px' \ and masterCell.getName() != 'pvddeck_px' \ and masterCell.getName() != 'pvsseck_px': continue #print 'Power pad:', pad self._createPowerContacts( pad, self._corona.vddi ) self._createPowerContacts( pad, self._corona.vssi ) return def _placePads ( self ): if self._type == chip.North: hAdvance = True orientation = Transformation.Orientation.ID sideLength = self._corona.chipSize.getWidth() x = self._corona.padHeight y = self._corona.chipSize.getHeight() - self._corona.padHeight elif self._type == chip.South: hAdvance = True orientation = Transformation.Orientation.MY sideLength = self._corona.chipSize.getWidth() x = self._corona.padHeight y = self._corona.padHeight elif self._type == chip.East: hAdvance = False orientation = Transformation.Orientation.R3 sideLength = self._corona.chipSize.getHeight() x = self._corona.chipSize.getWidth() - self._corona.padHeight y = self._corona.padHeight + self._corona.padWidth elif self._type == chip.West: hAdvance = False orientation = Transformation.Orientation.R1 sideLength = self._corona.chipSize.getHeight() x = self._corona.padHeight y = self._corona.padHeight step = (sideLength - 2*self._corona.padHeight) / len(self._pads) for pad in self._pads: pad.setTransformation ( Transformation( self._toGrid(x), self._toGrid(y), orientation ) ) pad.setPlacementStatus( Instance.PlacementStatus.FIXED ) if hAdvance: x += step else: y += step return def _routePads ( self ): for i in range(len(self._corona._powerRails)): if self._type == chip.South: Horizontal.create( self._corona._corners[chip.SouthWest ][i] , self._corona._corners[chip.SouthEast][i] , self._corona._powerRails[i][1] , self.getAxis( i ) , self._corona._powerRails[i][3] ) elif self._type == chip.North: Horizontal.create( self._corona._corners[chip.NorthWest ][i] , self._corona._corners[chip.NorthEast][i] , self._corona._powerRails[i][1] , self.getAxis( i ) , self._corona._powerRails[i][3] ) elif self._type == chip.East: Vertical.create( self._corona._corners[chip.SouthEast][i] , self._corona._corners[chip.NorthEast ][i] , self._corona._powerRails[i][1] , self.getAxis( i ) , self._corona._powerRails[i][3] ) elif self._type == chip.West: Vertical.create( self._corona._corners[chip.SouthWest][i] , self._corona._corners[chip.NorthWest ][i] , self._corona._powerRails[i][1] , self.getAxis( i ) , self._corona._powerRails[i][3] ) return def doLayout ( self ): self._placePads() self._routePads() self._createAllPowerContacts() return class Corona ( chip.Configuration.Wrapper ): def __init__ ( self, confWrapper ): chip.Configuration.Wrapper.__init__( self, confWrapper.conf ) self.validated = False self._northSide = Side( self, chip.North ) self._southSide = Side( self, chip.South ) self._eastSide = Side( self, chip.East ) self._westSide = Side( self, chip.West ) self._corners = { chip.SouthWest : [] , chip.SouthEast : [] , chip.NorthWest : [] , chip.NorthEast : [] } self._powerRails = [] # [ , [net, layer, axis, width] ] self._locatePadRails() self._guessHvLayers() return @property def southSide ( self ): return self._southSide @property def northSide ( self ): return self._northSide @property def eastSide ( self ): return self._eastSide @property def westSide ( self ): return self._westSide def getSwCorner ( self, i ): return self._corners[chip.SouthWest][i] def getSeCorner ( self, i ): return self._corners[chip.SouthEast][i] def getNwCorner ( self, i ): return self._corners[chip.NorthWest][i] def getNeCorner ( self, i ): return self._corners[chip.NorthEast][i] def getRailNet ( self, i ): return self._powerRails[i][0] def getRailLayer ( self, i ): return self._powerRails[i][1] def getRailAxis ( self, i ): return self._powerRails[i][2] def getRailWidth ( self, i ): return self._powerRails[i][3] def getHDepth ( self ): return self._horizontalDepth def getVDepth ( self ): return self._verticalDepth def validate ( self ): self.validated = self._northSide.check() self.validated = self._southSide.check() and self.validated self.validated = self._eastSide.check() and self.validated self.validated = self._westSide.check() and self.validated return self.validated def _locatePadRails ( self ): if not self.clockPad: print ErrorMessage( 1, 'There must be at least one pad of model "pck_px" to guess the pad rails.' ) return False for plug in self.clockPad.getPlugs(): masterNet = plug.getMasterNet() netType = masterNet.getType() net = plug.getNet() if netType != Net.Type.POWER \ and netType != Net.Type.GROUND \ and netType != Net.Type.CLOCK: continue if not net: net = self.cell.getNet( masterNet.getName() ) if not net: print ErrorMessage( 1, 'Missing global net <%s> at chip level.' % masterNet.getName() ) continue for component in masterNet.getExternalComponents(): if not isinstance(component,Horizontal): continue xs = component.getSourcePosition().getX() xt = component.getTargetPosition().getX() if xs < xt: length = xt - xs else: length = xs - xt if length < self.padWidth*.6: continue self._powerRails.append( [ net, component.getLayer(), component.getY(), component.getWidth() ] ) self._powerRails.sort( key=itemgetter(2) ) #for rail in self._powerRails: # print 'Pad rail %s @%d width:%d layer:%s' % ( str(rail[0].getName()) # , DbU.toLambda(rail[2]) # , DbU.toLambda(rail[3]) # , str(rail[1].getName()) # ) return def _guessHvLayers ( self ): if not self.powerPad: print ErrorMessage( 1, 'There must be at least one pad of model "pvddick_px" to guess the pad power terminals.' ) return False availableDepths = set() masterCell = self.powerPad.getMasterCell() for component in masterCell.getNet('vddi').getExternalComponents(): if component.getBoundingBox().getYMin() <= masterCell.getAbutmentBox().getYMin(): availableDepths.add( self.routingGauge.getLayerDepth(component.getLayer()) ) #print 'available depth:', availableDepths self._horizontalDepth = 0 self._verticalDepth = 0 for depth in range(0,self.topLayerDepth+1): if not depth in availableDepths: continue if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal: self._horizontalDepth = depth if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical: self._verticalDepth = depth #print 'h:', self._horizontalDepth #print 'v:', self._verticalDepth return def doLayout ( self ): if not self.validated: return UpdateSession.open() self.cell.setAbutmentBox( self.chipSize ) for i in range(len(self._powerRails)): xBL = self._westSide .getAxis(i) yBL = self._southSide.getAxis(i) xTR = self._eastSide .getAxis(i) yTR = self._northSide.getAxis(i) self._corners[chip.SouthWest].append( Contact.create( self.getRailNet(i) , self.getRailLayer(i) , xBL, yBL , self.getRailWidth(i) , self.getRailWidth(i) ) ) self._corners[chip.NorthWest].append( Contact.create( self.getRailNet(i) , self.getRailLayer(i) , xBL, yTR , self.getRailWidth(i) , self.getRailWidth(i) ) ) self._corners[chip.SouthEast].append( Contact.create( self.getRailNet(i) , self.getRailLayer(i) , xTR, yBL , self.getRailWidth(i) , self.getRailWidth(i) ) ) self._corners[chip.NorthEast].append( Contact.create( self.getRailNet(i) , self.getRailLayer(i) , xTR, yTR , self.getRailWidth(i) , self.getRailWidth(i) ) ) self._northSide.doLayout() self._southSide.doLayout() self._eastSide.doLayout() self._westSide.doLayout() UpdateSession.close() return