2416 lines
104 KiB
Python
2416 lines
104 KiB
Python
|
|
import os
|
|
import re
|
|
|
|
import Cfg
|
|
from Hurricane import *
|
|
from helpers.io import ErrorMessage
|
|
import CRL
|
|
#import Mauka
|
|
|
|
#import Knik
|
|
#import Kite
|
|
#import Zephyr
|
|
#import Lightning
|
|
#import Zephiros
|
|
|
|
#from Anemometer import *
|
|
#from Metisse import *
|
|
|
|
#from Mistral import *
|
|
#from Nimbus import *
|
|
|
|
from math import *
|
|
|
|
|
|
missingCORIOLIS_TOP = "Missing environment variable CORIOLIS_TOP"
|
|
|
|
global POWER, OCCUPIED, FREE
|
|
POWER = 2
|
|
OCCUPIED = 1
|
|
FREE = 0
|
|
|
|
global PITCH, SLICE
|
|
PITCH = 5
|
|
SLICE = 50
|
|
|
|
global RING_WIDTH
|
|
RING_WIDTH = 12
|
|
|
|
global RING_INTERVAL
|
|
RING_INTERVAL = 3
|
|
|
|
global standard_instances_masque
|
|
|
|
global standard_instances_list
|
|
standard_instances_list = []
|
|
|
|
global pad_north, pad_south, pad_east, pad_west
|
|
pad_north = []
|
|
pad_south = []
|
|
pad_east = []
|
|
pad_west = []
|
|
|
|
global nb_alims_verticales
|
|
nb_alims_verticales = 0
|
|
|
|
global nb_vdd_pins, nb_vss_pins
|
|
nb_vdd_pins = 0
|
|
nb_vss_pins = 0
|
|
|
|
global ck_contact_list_to_create
|
|
ck_contact_list_to_create = []
|
|
|
|
|
|
def getNetFromPlug ( plug ):
|
|
net = plug.getNet()
|
|
if net: return net
|
|
|
|
masterNet = plug.getMasterNet()
|
|
if masterNet.getName() in [ 'vddi', 'vssi', 'vdde', 'vsse' ]:
|
|
cell = plug.getCell()
|
|
net = cell.getNet(masterNet.getName())
|
|
|
|
return net
|
|
|
|
##################
|
|
## PlaceCentric ##
|
|
##################
|
|
def pyPlaceCentric ( cell, instance ) :
|
|
'''This function places an instance in the middle of the abutment box of a cell'''
|
|
|
|
UpdateSession.open()
|
|
|
|
if not instance :
|
|
raise ErrorMessage(2,"PlaceCentric: the instance does not exist.")
|
|
|
|
w = cell.getAbutmentBox().getWidth()
|
|
h = cell.getAbutmentBox().getHeight()
|
|
|
|
if ( w < instance.getAbutmentBox().getWidth() ) or ( h < instance.getAbutmentBox().getHeight() ) :
|
|
raise ErrorMessage(2,"PlaceCentric : the instance's size is greater than this model.")
|
|
|
|
XCenter = cell.getAbutmentBox().getXCenter()
|
|
YCenter = cell.getAbutmentBox().getYCenter()
|
|
|
|
New_Xmin = XCenter - instance.getAbutmentBox().getWidth() / 2
|
|
New_Ymin = YCenter - instance.getAbutmentBox().getHeight() / 2
|
|
|
|
# One must place the cell on a pitch grid
|
|
New_Xmin = New_Xmin - ( New_Xmin % DbU_lambda(PITCH) )
|
|
New_Ymin = New_Ymin - ( New_Ymin % DbU_lambda(PITCH) )
|
|
|
|
Tx = New_Xmin - instance.getAbutmentBox().getXMin()
|
|
Ty = New_Ymin - instance.getAbutmentBox().getYMin()
|
|
|
|
instance.setTransformation ( Transformation ( Tx, Ty ).getTransformation ( instance.getTransformation() ) )
|
|
instance.setPlacementStatus ( Instance.PlacementStatus.PLACED )
|
|
|
|
UpdateSession.close()
|
|
|
|
#######################
|
|
## PlaceGlue ##
|
|
#######################
|
|
def pyPlaceGlue ( cell ) :
|
|
'''This function places the glue (unplaced leaf instances) in current cell.
|
|
The placement will be made in the region given by the core argument:
|
|
- if core is None, the placement region will be the cell abox.
|
|
- if core is a cell sub-instance, the placement region will be the sub-instance abox.'''
|
|
|
|
mauka = Mauka.MaukaEngine.create ( cell )
|
|
mauka.run ()
|
|
temporarySave ()
|
|
|
|
|
|
#############
|
|
## RouteCk ##
|
|
#############
|
|
def pyRouteCk ( cell, netCk ) :
|
|
'''This function route signel Ck to standard cells'''
|
|
|
|
global pad_north, pad_south, pad_east, pad_west
|
|
|
|
UpdateSession.open()
|
|
|
|
# Error if Pads have not already been placed
|
|
if pad_north == [] : raise ErrorMessage(2,"RouteCk : Pads in the north haven't been placed.")
|
|
if pad_south == [] : raise ErrorMessage(2,"RouteCk : Pads in the south haven't been placed.")
|
|
if pad_east == [] : raise ErrorMessage(2,"RouteCk : Pads in the east haven't been placed.")
|
|
if pad_west == [] : raise ErrorMessage(2,"RouteCk : Pads in the west haven't been placed.")
|
|
|
|
# pad_list contains all pads
|
|
pad_list = []
|
|
pad_list.extend ( pad_north )
|
|
pad_list.extend ( pad_south )
|
|
pad_list.extend ( pad_east )
|
|
pad_list.extend ( pad_west )
|
|
|
|
net_list = dict()
|
|
|
|
for ins in pad_list :
|
|
# For each pad that is a clock pad -> adding corresponding net in net_list if not already existing
|
|
if isInternalClockPad ( ins ) or isExternalClockPad ( ins ):
|
|
clockPlug = None
|
|
for plug in ins.getPlugs():
|
|
if plug.getNet() == netCk :
|
|
clockPlug = plug
|
|
break
|
|
|
|
if clockPlug and not net_list.has_key ( str ( clockPlug.getNet().getName() ) ) : net_list[str ( clockPlug.getNet().getName() )] = ( clockPlug.getNet(), cell )
|
|
|
|
map ( createGrid, net_list.values() )
|
|
|
|
UpdateSession.close()
|
|
|
|
######################
|
|
## AlimVerticalRail ##
|
|
######################
|
|
def pyAlimVerticalRail ( cell, xcoord ) :
|
|
'''x is in pitch, it is where the vertical alimentation call back are placed'''
|
|
|
|
global PITCH, SLICE
|
|
global standard_instances_list, nb_alims_verticales, nb_lignes, standard_instances_masque
|
|
global nb_vdd_pins, nb_vss_pins
|
|
|
|
UpdateSession.open()
|
|
|
|
box = cell.getAbutmentBox()
|
|
|
|
# Error message if wrong abutment box
|
|
if ( box.getXMin() == box.getXMax() ) or ( box.getYMin() == box.getYMax() ) :
|
|
message = "AlimVerticalRail : Can't place the rail vertical in the abutment box of model %s." %str(cell.getName()) \
|
|
+ " The abutment box doesn't exist !" \
|
|
+ " Maybe you should use DefAb function or ResizeAb function to define un box before the placement of Rail Vertical."
|
|
raise ErrorMessage(2,message)
|
|
|
|
# Check the value of x
|
|
nb_col = cell.getAbutmentBox().getWidth() / DbU_lambda(PITCH)
|
|
if ( xcoord >= nb_col ) or ( xcoord < 0 ) :
|
|
print 'This is it'
|
|
message = "AlimVerticalRail : Illegal argument x , x must be between %d and %d\n" % ( 0, nb_col )
|
|
raise ErrorMessage(2,message)
|
|
|
|
# To get the informations about the placement
|
|
reference = getStandardInstancesMasque ( cell )
|
|
|
|
if not reference :
|
|
message = "AlimVerticalRail : No instance is placed in the model " + str(cell.getName()) + ".\n" \
|
|
+ "Please place some instances before the placement of Rail Vertical.\n"
|
|
raise ErrorMessage(2,message)
|
|
|
|
# Placement verification
|
|
#verifyPlacement ( cell ) # NON !!
|
|
# delete elements in standard_instances_list
|
|
del standard_instances_list[0:]
|
|
# get YMin of reference
|
|
Ymin = reference[1]
|
|
# get orientation code
|
|
orientation = reference[2]
|
|
|
|
nb_alims_verticales += 1
|
|
|
|
# get the opposite of orientation ID=>MY MY=>ID
|
|
if orientation in [Transformation.Orientation.ID, Transformation.Orientation.MX] :
|
|
inv_orientation = Transformation.Orientation.MY
|
|
orientation = Transformation.Orientation.ID
|
|
elif orientation in [Transformation.Orientation.MY, Transformation.Orientation.R2] :
|
|
inv_orientation = Transformation.Orientation.ID
|
|
orientation = Transformation.Orientation.MY
|
|
else :
|
|
raise ErrorMessage(2,"AlimVerticalRail : Strawberry.")
|
|
|
|
# print "Placement of vertical rail"
|
|
# print "Reference ", reference
|
|
|
|
power_cell = CRL.AllianceFramework.get().getCell ( "powmid_x0", CRL.Catalog.State.Views )
|
|
|
|
Height_power = power_cell.getAbutmentBox().getHeight()
|
|
Width_power = power_cell.getAbutmentBox().getWidth()
|
|
|
|
nb_slices = Height_power / DbU_lambda(SLICE)
|
|
nb_pitchs = Width_power / DbU_lambda(PITCH)
|
|
|
|
# skim through column of index x
|
|
for i in range ( nb_lignes ) :
|
|
espace_enough = True
|
|
|
|
# check the space left
|
|
for j in range ( nb_slices ) :
|
|
for k in range ( nb_pitchs ) :
|
|
if standard_instances_masque[i + j][xcoord + k] != FREE :
|
|
espace_enough = False
|
|
break
|
|
|
|
if espace_enough :
|
|
# avoir le nombre de slices entre la reference
|
|
distance = Ymin / DbU_lambda(SLICE) - i
|
|
|
|
if distance < 0 : distance = -distance
|
|
|
|
name_inst = "powmid_%d_%d" % ( nb_alims_verticales , i )
|
|
Powmid = create_inst ( "powmid_x0", name_inst, cell )
|
|
x = xcoord * DbU_lambda(PITCH)
|
|
y = i * DbU_lambda(SLICE)
|
|
if distance % 2 : my_orientation = inv_orientation
|
|
else : my_orientation = orientation
|
|
place ( Powmid, int(x), int(y), my_orientation )
|
|
|
|
# place pins (connectors) in metal3 on top and bottom
|
|
metal3 = DataBase.getDB().getTechnology().getLayer( "METAL3" )
|
|
|
|
powerNet = None
|
|
for net in cell.getPowerNets():
|
|
if powerNet:
|
|
raise ErrorMessage(2,"AlimVerticalRail : more than 1 Power Net found !")
|
|
powerNet = net
|
|
if not powerNet:
|
|
raise ErrorMessage(2,"AlimVerticalRail : no Power Net found !")
|
|
|
|
groundNet = None
|
|
for net in cell.getGroundNets():
|
|
if groundNet:
|
|
raise ErrorMessage(2,"AlimVerticalRail : more than 1 Ground Net found !")
|
|
groundNet = net
|
|
if not groundNet:
|
|
raise ErrorMessage(2,"AlimVerticalRail : no Ground Net found !")
|
|
|
|
pin_height = 10
|
|
pin_width = 10
|
|
pin_x1 = xcoord * DbU_lambda(PITCH) + DbU_lambda(10)
|
|
pin_x2 = xcoord * DbU_lambda(PITCH) + DbU_lambda(25)
|
|
pin_y1 = ( nb_lignes * DbU_lambda(SLICE) ) - DbU_lambda(pin_height/4)
|
|
pin_y2 = 0 + DbU_lambda(pin_height/4)
|
|
|
|
# Top
|
|
if standard_instances_masque[nb_lignes-1][xcoord] == FREE :
|
|
pin_name = str(powerNet.getName()) + "." + str(nb_vdd_pins)
|
|
pin = Pin.create ( powerNet, pin_name, 1, 2, metal3, pin_x1, pin_y1, DbU_lambda(pin_width), DbU_lambda(pin_height) )
|
|
nb_vdd_pins += 1
|
|
|
|
pin_name = str(groundNet.getName()) + "." + str(nb_vss_pins)
|
|
pin = Pin.create ( groundNet, pin_name, 1, 2, metal3, pin_x2, pin_y1, DbU_lambda(pin_width), DbU_lambda(pin_height) )
|
|
nb_vss_pins += 1
|
|
|
|
# Bottom
|
|
if standard_instances_masque[0][xcoord] == FREE :
|
|
pin_name = str(powerNet.getName()) + "." + str(nb_vdd_pins)
|
|
pin = Pin.create ( powerNet, pin_name, 2 , 2, metal3, pin_x1, pin_y2, DbU_lambda(pin_width), DbU_lambda(pin_height) )
|
|
nb_vdd_pins += 1
|
|
|
|
pin_name = str(groundNet.getName()) + "." + str(nb_vss_pins)
|
|
pin = Pin.create ( groundNet, pin_name, 2 , 2, metal3, pin_x2, pin_y2, DbU_lambda(pin_width), DbU_lambda(pin_height) )
|
|
nb_vss_pins += 1
|
|
|
|
UpdateSession.close()
|
|
|
|
########################
|
|
## AlimHorizontalRail ##
|
|
########################
|
|
def pyAlimHorizontalRail ( cell, ycoord ) :
|
|
'''This function places the horizontal alimentation call back in Alu 4
|
|
1. the two pins in Alu 4 which name is VDD or VSS are placed
|
|
2. the horizontal in Alu 4 is placed, and is locked on the two pins
|
|
y is in slice'''
|
|
|
|
global PITCH, SLICE, RING_WIDTH
|
|
global standard_instances_list, nb_alims_verticales, nb_lignes, standard_instances_masque
|
|
global nb_vdd_pins, nb_vss_pins
|
|
|
|
UpdateSession.open()
|
|
|
|
box = cell.getAbutmentBox()
|
|
|
|
# Error message if wrong abutment box
|
|
if ( box.getXMin() == box.getXMax() ) or ( box.getYMin() == box.getYMax() ) :
|
|
err = "\nAlimHorizontalRail : Can't place the rail horizontal in the abutment box of model " + str(cell.getName()) \
|
|
+ "\n The abutment box doesn't exist !" \
|
|
+ "\n Maybe you should use DefAb function or ResizeAb function to define un box before the placement of Rail Horizontal.\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
# Check the value of y
|
|
if ( ycoord >= nb_lignes ) or ( ycoord < 0 ) :
|
|
err = "\nAlimHorizontalRail : Illegal argument y, y must be between %d and %d\n" % ( 0, nb_lignes )
|
|
raise ErrorMessage(2,err)
|
|
|
|
# To get the informations about the placement
|
|
reference = getStandardInstancesMasque ( cell )
|
|
|
|
if not reference :
|
|
err = "AlimHorizontalRail : No instance is placed in the model " + str(cell.getName()) + ".\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
# get layers
|
|
metal4 = DataBase.getDB().getTechnology().getLayer ( "METAL4" )
|
|
via1 = DataBase.getDB().getTechnology().getLayer ( "VIA12" )
|
|
via2 = DataBase.getDB().getTechnology().getLayer ( "VIA23" )
|
|
via3 = DataBase.getDB().getTechnology().getLayer ( "VIA34" )
|
|
|
|
# Know if it is vdd or vss
|
|
string = getVddVss ( cell, ycoord )
|
|
|
|
pin_width = DbU_lambda(RING_WIDTH)
|
|
pin_height = DbU_lambda(RING_WIDTH)
|
|
pin_x1 = 0 + ( pin_height / 4 )
|
|
pin_x2 = cell.getAbutmentBox().getWidth() - ( pin_height / 4 )
|
|
pin_y = ycoord * DbU_lambda(SLICE)
|
|
|
|
# Create two pins
|
|
if string == "vdd" :
|
|
net = cell.getNet ( "vdd" )
|
|
|
|
pin_name = str(net.getName()) + "." + str(nb_vdd_pins)
|
|
pin1 = Pin.create ( net, pin_name, 4, 2, metal4, pin_x1, pin_y, pin_width, pin_height )
|
|
nb_vdd_pins += 1
|
|
|
|
pin_name = str(net.getName()) + "." + str(nb_vdd_pins)
|
|
pin2 = Pin.create ( net, pin_name, 3, 2, metal4, pin_x2, pin_y, pin_width, pin_height )
|
|
nb_vdd_pins += 1
|
|
|
|
else :
|
|
net = cell.getNet ( "vss" )
|
|
|
|
pin_name = str(net.getName()) + "." + str(nb_vss_pins)
|
|
pin1 = Pin.create ( net, pin_name, 4, 2, metal4, pin_x1, pin_y, pin_width, pin_height )
|
|
nb_vss_pins += 1
|
|
|
|
pin_name = str(net.getName()) + "." + str(nb_vss_pins)
|
|
pin2 = Pin.create ( net, pin_name, 3, 2, metal4, pin_x2, pin_y, pin_width, pin_height )
|
|
nb_vss_pins += 1
|
|
|
|
# Create horizontal rail
|
|
rail_horizontal = Horizontal.create ( pin1 , pin2 , metal4 , pin_y, pin_height, 0 , 0 )
|
|
|
|
power_hur_cell = CRL.AllianceFramework.get().getCell ( "powmid_x0", CRL.Catalog.State.Views )
|
|
Width_power = power_hur_cell.getAbutmentBox().getWidth()
|
|
nb_pitchs = Width_power / DbU_lambda(PITCH) # avoir l'interval du cellule power
|
|
|
|
# create contacts in via1 , via2 , et via3
|
|
i = 0
|
|
while i < nb_colonnes :
|
|
# if it is a power cell, make the via3, and pass the power cell
|
|
if standard_instances_masque[ycoord][i] == POWER :
|
|
contact_side = DbU_lambda(RING_WIDTH) - DbU_lambda(1.0)
|
|
|
|
if string == "vdd" : contact3 = Contact.create ( rail_horizontal, via3, i*DbU_lambda(PITCH) + DbU_lambda(10), 0, contact_side, DbU_lambda(2) )
|
|
else : contact3 = Contact.create ( rail_horizontal, via3, i*DbU_lambda(PITCH) + DbU_lambda(25), 0, contact_side, DbU_lambda(2) )
|
|
i += nb_pitchs
|
|
|
|
i+=1
|
|
|
|
UpdateSession.close()
|
|
|
|
####################
|
|
## AlimConnectors ##
|
|
####################
|
|
def pyAlimConnectors ( cell ) :
|
|
'''Creates the METAL1 connectors on the east & west sides of the core'''
|
|
|
|
global nb_lignes, nb_vdd_pins, nb_vss_pins
|
|
|
|
UpdateSession.open()
|
|
|
|
box = cell.getAbutmentBox()
|
|
|
|
# Error message if wrong abutment box
|
|
if ( box.getXMin() == box.getXMax() ) or ( box.getYMin() == box.getYMax() ) :
|
|
err = "\nAlimConnectors : can't place connectors. The abutment box don't exist.\n" \
|
|
+ "The abutment box don't exist !\n" \
|
|
+ "Maybe you should use DefAb function or ResizeAb function to define un box before the placement of alim connectors.\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
# avoir les infos actuelles de placement
|
|
getStandardInstancesMasque ( cell )
|
|
|
|
if not reference :
|
|
err = "\nAlimConnectors : no instance placed in the model " + str(cell.getName()) + "." \
|
|
+ "Please place some instances before the placement of alim connectors.\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
metal1 = DataBase.getDB().getTechnology().getLayer("METAL1")
|
|
string = getVddVss ( cell, 0 )
|
|
|
|
if re.search ( "vdd", string ) :
|
|
inv_string = "vss"
|
|
nb_string_pins = nb_vdd_pins
|
|
nb_inv_pins = nb_vss_pins
|
|
else :
|
|
inv_string = "vdd"
|
|
nb_string_pins = nb_vss_pins
|
|
nb_inv_pins = nb_vdd_pins
|
|
|
|
netPair = cell.getNet ( string )
|
|
if not netPair:
|
|
raise ErrorMessage(2,"AlimConnectors : can't get net %s."%string)
|
|
|
|
netImpair = cell.getNet ( inv_string )
|
|
if not netImpair:
|
|
raise ErrorMessage(2,"AlimConnectors : can't get net %s.\n"%inv_string)
|
|
|
|
for i in range ( nb_lignes + 1 ) :
|
|
pin_width = DbU_lambda(12)
|
|
pin_height = DbU_lambda(12)
|
|
pin_y = i * DbU_lambda(SLICE)
|
|
|
|
if i == 0 :
|
|
pin_height = pin_height / 2
|
|
pin_width = pin_width / 2
|
|
pin_y = pin_y + ( pin_height / 2 )
|
|
elif i == nb_lignes :
|
|
pin_height = pin_height / 2
|
|
pin_width = pin_width / 2
|
|
pin_y = pin_y - ( pin_height / 2 )
|
|
|
|
pin_x1 = 0 + ( pin_width / 2 )
|
|
pin_x2 = cell.getAbutmentBox().getWidth() - ( pin_width / 2 )
|
|
|
|
# Ligne impaire
|
|
if i % 2 :
|
|
pin_name = str(netImpair.getName()) + "." + str(nb_inv_pins)
|
|
pin1 = Pin.create ( netImpair, pin_name, 4, 2, metal1, pin_x1, pin_y, pin_width, pin_height )
|
|
nb_inv_pins += 1
|
|
|
|
pin_name = str(netImpair.getName()) + "." + str(nb_inv_pins)
|
|
pin2 = Pin.create ( netImpair, pin_name, 3, 2, metal1, pin_x2, pin_y, pin_width, pin_height )
|
|
nb_inv_pins += 1
|
|
Horizontal.create ( pin1, pin2, metal1, pin1.getY(), pin_height )
|
|
# Ligne paire
|
|
else :
|
|
pin_name = str(netPair.getName()) + "." + str(nb_string_pins)
|
|
pin1 = Pin.create ( netPair, pin_name, 4, 2, metal1, pin_x1, pin_y, pin_width, pin_height )
|
|
nb_string_pins += 1
|
|
|
|
pin_name = str(netPair.getName()) + "." + str(nb_string_pins)
|
|
pin2 = Pin.create ( netPair, pin_name, 3, 2, metal1, pin_x2, pin_y, pin_width, pin_height )
|
|
nb_string_pins += 1
|
|
Horizontal.create ( pin1, pin2, metal1, pin1.getY(), pin_height )
|
|
|
|
if re.search ( "vdd", string ) :
|
|
nb_vdd_pins = nb_string_pins
|
|
nb_vss_pins = nb_inv_pins
|
|
else :
|
|
nb_vss_pins = nb_string_pins
|
|
nb_vdd_pins = nb_inv_pins
|
|
|
|
UpdateSession.close()
|
|
|
|
#######################
|
|
## GlobalRoute ##
|
|
#######################
|
|
#def pyGlobalRoute ( cell ):
|
|
# """Perform global routing"""
|
|
#
|
|
# # Initialize Nimbus Grid (50x50 lambdas).
|
|
# Kite.setupNimbusGrid ( cell ) # ca a pas l'air de faire ce qu'il faut
|
|
#
|
|
# # la il faudrait rajouter un petit appel a cell->FlattenNets() pour que ce soit correct !
|
|
#
|
|
# # Global routing.
|
|
# globalRouter = Knik.getKnik ( cell
|
|
# , 1 # congestion.
|
|
# , 2 # preCongestion.
|
|
# , False # benchMode.
|
|
# , True # useSegments.
|
|
# )
|
|
# globalRouter.Route ()
|
|
# globalRouter.Delete ()
|
|
|
|
#######################
|
|
## DetailRoute ##
|
|
#######################
|
|
#def pyDetailRoute ( cell ):
|
|
# """Perform detailed routing"""
|
|
#
|
|
# viewer = getCEditor ( cell )
|
|
#
|
|
# TOOL_TOP = os.getenv ( "CORIOLIS_TOP" )
|
|
# if not TOOL_TOP:
|
|
# raise missingCORIOLIS_TOP
|
|
# config = TOOL_TOP + "/share/etc/kite.conf.xml"
|
|
#
|
|
# Kite.setDemoMode ( True )
|
|
# Kite.ConfigurationCreate ( config )
|
|
# detailedRouter = Kite.Create ( cell, viewer )
|
|
# detailedRouter.setGlobalThreshold ( 9*DbU_lambda(50.0) )
|
|
# detailedRouter.setRipupLimit ( 10 )
|
|
# detailedRouter.LoadGlobalRouting ( Kite.LOAD_GR_BY_NET )
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# detailedRouter.LayerAssign ( Kite.LAYER_ASSIGN_BY_TRUNK )
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# detailedRouter.ComputeNetConstraints ()
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# detailedRouter.ComputeNetOptimals ()
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# detailedRouter.RunNegociate ()
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# # Save detailed routing.
|
|
# detailedRouter.Delete ()
|
|
# if viewer: viewer.Refresh ()
|
|
#
|
|
# return
|
|
|
|
#def pyTimingStaticAnalysis ( cell ):
|
|
# """Perfom timing static analysis"""
|
|
#
|
|
# TOOL_TOP = os.getenv ( "CORIOLIS_TOP")
|
|
# if not TOOL_TOP:
|
|
# raise missingCORIOLIS_TOP
|
|
# config = TOOL_TOP + "/share/cells/sxlib/sxlib_timing.lib"
|
|
#
|
|
# LibertyParse ( config )
|
|
#
|
|
# lightning = Lightning.getLightning ( cell )
|
|
# timingStaticAnalysis = Zephyr.getZephyr ( cell )
|
|
# #zephiros = Zephiros.getZephiros ( cell )
|
|
#
|
|
# timingStaticAnalysis.Update()
|
|
# #zephiros.PrintMaxDelay()
|
|
#
|
|
# return
|
|
|
|
|
|
|
|
##############
|
|
## PadNorth ##
|
|
##############
|
|
def pyPadNorth ( cell, core, args ) :
|
|
'''This function places pads up north of the cell. It leaves an empty squarre of CARRE * CARRE, CARRE is defined in macro'''
|
|
|
|
global pad_north
|
|
|
|
# Sauvegarder la liste des plots
|
|
pad_north = args
|
|
|
|
UpdateSession.open()
|
|
|
|
# avoir le largeur de l espace au nord pour placer les pads
|
|
north_espace_width = cell.getAbutmentBox().getYMax() - core.getAbutmentBox().getYMax()
|
|
north_espace_longueur = cell.getAbutmentBox().getWidth() - (2 * getPadHeight ( cell ) ) # FIXME D2
|
|
|
|
# avoir le nombre de pads
|
|
nb_pads = len ( args )
|
|
|
|
# avoir le largeur total des pads
|
|
largeur = 0
|
|
for ins in args :
|
|
if ins.getPlacementStatus() :
|
|
raise ErrorMessage(2,"PadNorth : the instance %s is already placed."%str(ins.getName()))
|
|
|
|
if ins.getAbutmentBox().getHeight() >= north_espace_width :
|
|
raise ErrorMessage(2,"PadNorth : not enough space for all pads.")
|
|
|
|
largeur += ins.getAbutmentBox().getWidth()
|
|
|
|
if largeur > north_espace_longueur :
|
|
raise ErrorMessage(2,"PadNorth : not enough space for all pads.")
|
|
|
|
# calculer l interval entre les pads
|
|
interval = ( north_espace_longueur - largeur ) / ( nb_pads + 1 )
|
|
|
|
# placer les pads
|
|
Xmin_cell = cell.getAbutmentBox().getXMin()
|
|
Ymin_cell = cell.getAbutmentBox().getYMin()
|
|
Height_cell = cell.getAbutmentBox().getHeight()
|
|
|
|
x_init = Xmin_cell + getPadHeight ( cell ) + interval
|
|
|
|
##### Parcours des pads #####
|
|
for ins in args :
|
|
pad_height = ins.getAbutmentBox().getHeight()
|
|
pad_width = ins.getAbutmentBox().getWidth()
|
|
|
|
_y = Ymin_cell + Height_cell - pad_height # la position finale dans la cell
|
|
_x = x_init
|
|
|
|
# ATTENTION LES PLOTS DOIVENT ETRE PLACES SUR UNE GRILLE DE 5 LAMBDAS !!!!!!!!!!!!!!
|
|
_x = _x - ( _x % DbU_lambda(PITCH) )
|
|
|
|
# ATTENTION ON NE PLACE PAS DES PLOTS D ALIM EN DEHORS DE LA COURONNE INTERNE
|
|
if isInternalGroundPad ( ins ) or isInternalPowerPad ( ins ) \
|
|
or isExternalGroundPad ( ins ) or isExternalPowerPad ( ins ) :
|
|
cellAB = cell.getAbutmentBox()
|
|
coreAB = core.getAbutmentBox()
|
|
pad_height = getPadHeight ( cell )
|
|
if _x <= ( ( cellAB.getXMin() + pad_height ) + coreAB.getXMin() ) / 2 \
|
|
or _x >= ( ( cellAB.getXMax() - pad_height ) + coreAB.getXMax() ) / 2 :
|
|
raise ErrorMessage(2,"PadNorth : pad %s must be closer to the center.\n"%str(ins.getName()))
|
|
|
|
# x calcule pour le pad suivant
|
|
x_init = _x + interval + pad_width
|
|
|
|
# avoir x y
|
|
box = ins.getMasterCell().getAbutmentBox()
|
|
_difx = box.getXMin()
|
|
_dify = box.getYMin()
|
|
|
|
ins.setTransformation ( Transformation ( _x - _difx
|
|
, _y - _dify
|
|
, Transformation.Orientation.ID
|
|
)
|
|
)
|
|
|
|
ins.setPlacementStatus ( Instance.PlacementStatus.FIXED )
|
|
|
|
UpdateSession.close()
|
|
|
|
##############
|
|
## PadSouth ##
|
|
##############
|
|
def pyPadSouth ( cell, core, args ) :
|
|
'''This function places pads down south of the cell. It leaves an empty squarre of CARRE * CARRE, CARRE is defined in macro'''
|
|
|
|
global pad_south
|
|
|
|
# Sauvegarder la liste des plots
|
|
pad_south = args
|
|
|
|
UpdateSession.open()
|
|
|
|
# avoir le largeur du espace disponible du nord pour placer les pads
|
|
south_espace_width = core.getAbutmentBox().getYMin() - cell.getAbutmentBox().getYMin()
|
|
south_espace_longueur = cell.getAbutmentBox().getWidth() - ( 2 * getPadHeight ( cell ) )
|
|
|
|
# avoir le nombre de pads
|
|
nb_pads = len ( args )
|
|
|
|
# avoir le largeur total des pads
|
|
largeur = 0
|
|
for ins in args :
|
|
if ins.getPlacementStatus() :
|
|
raise ErrorMessage(2,"PadSouth : the instance %s is already placed."%str(ins.getName()))
|
|
|
|
if ins.getAbutmentBox().getHeight() >= south_espace_width :
|
|
raise ErrorMessage(2,"PadSouth : not enough space for all pads.")
|
|
|
|
largeur += ins.getAbutmentBox().getWidth()
|
|
|
|
if largeur > south_espace_longueur :
|
|
raise ErrorMessage(2,"PadSouth : not enough space for all pads.")
|
|
|
|
# calculer l'interval entre les pads
|
|
interval = ( south_espace_longueur - largeur ) / ( nb_pads + 1 )
|
|
|
|
# placer les pads
|
|
Xmin_cell = cell.getAbutmentBox().getXMin()
|
|
Ymin_cell = cell.getAbutmentBox().getYMin()
|
|
|
|
x_init = Xmin_cell + getPadHeight ( cell ) + interval
|
|
|
|
##### Parcours des pads #####
|
|
for ins in args :
|
|
pad_height = ins.getAbutmentBox().getHeight()
|
|
pad_width = ins.getAbutmentBox().getWidth()
|
|
|
|
_y = Ymin_cell # la position finale dans la cell
|
|
_x = x_init
|
|
|
|
# ATTENTION LES PLOTS DOIVENT ETRE PLACES SUR UNE GRILLE DE 5 LAMBDAS !!!!!!!!!!!!!!
|
|
_x = _x - ( _x % DbU_lambda(PITCH) )
|
|
|
|
# ATTENTION ON NE PLACE PAS DES PLOTS D ALIM EN DEHORS DE LA COURONNE INTERNE
|
|
if isInternalGroundPad ( ins ) or isInternalPowerPad ( ins ) \
|
|
or isExternalGroundPad ( ins ) or isExternalPowerPad ( ins ) :
|
|
cellAB = cell.getAbutmentBox()
|
|
coreAB = core.getAbutmentBox()
|
|
pad_height = getPadHeight ( cell )
|
|
if _x <= ( ( cellAB.getXMin() + pad_height ) + coreAB.getXMin() ) / 2 \
|
|
or _x >= ( ( cellAB.getXMax() - pad_height ) + coreAB.getXMax() ) / 2 :
|
|
raise ErrorMessage(2,"PadSouth : pad %s must be closer to the center."%str(ins.getName()))
|
|
|
|
# x calcule pour le pad suivant
|
|
x_init = _x + interval + pad_width
|
|
|
|
# avoir x y apres orientation
|
|
box = ins.getMasterCell().getAbutmentBox()
|
|
_difx = Transformation ( 0, 0, Transformation.Orientation.MY ).getBox ( box ).getXMin()
|
|
_dify = Transformation ( 0, 0, Transformation.Orientation.MY ).getBox ( box ).getYMin()
|
|
|
|
ins.setTransformation ( Transformation ( _x - _difx
|
|
, _y - _dify
|
|
, Transformation.Orientation.MY
|
|
)
|
|
)
|
|
|
|
ins.setPlacementStatus ( Instance.PlacementStatus.FIXED )
|
|
|
|
UpdateSession.close()
|
|
|
|
#############
|
|
## PadEast ##
|
|
#############
|
|
def pyPadEast ( cell, core, args ) :
|
|
'''This function places pads at the east of the cell. It leaves an empty squarre of CARRE * CARRE, CARRE is defined in macro'''
|
|
|
|
global pad_east
|
|
|
|
# Sauvegarder la liste des plots
|
|
pad_east = args
|
|
|
|
UpdateSession.open()
|
|
|
|
# avoir le largeur du espace disponible du nord pour placer les pads
|
|
east_espace_width = cell.getAbutmentBox().getXMax() - core.getAbutmentBox().getXMax()
|
|
east_espace_longueur = cell.getAbutmentBox().getHeight() - ( 2 * getPadHeight ( cell ) )
|
|
|
|
# avoir le nombre de pads
|
|
nb_pads = len ( args )
|
|
|
|
# avoir le largeur total des pads
|
|
largeur = 0
|
|
for ins in args :
|
|
if ins.getPlacementStatus() :
|
|
raise ErrorMessage(2,"PadEast : the instance %s is already placed."%str(insGetName()))
|
|
|
|
if ins.getAbutmentBox().getHeight() >= east_espace_width :
|
|
raise ErrorMessage(2,"PadEast : not enough space for pads.")
|
|
|
|
largeur += ins.getAbutmentBox().getWidth()
|
|
|
|
if largeur > east_espace_longueur :
|
|
raise ErrorMessage(2,"PadEast : not enough space for all pads.")
|
|
|
|
# calculer l'interval entre les pads
|
|
interval = ( east_espace_longueur - largeur ) / ( nb_pads + 1 )
|
|
|
|
# placer les pads
|
|
Xmin_cell = cell.getAbutmentBox().getXMin()
|
|
Ymin_cell = cell.getAbutmentBox().getYMin()
|
|
Xmax_cell = cell.getAbutmentBox().getXMax()
|
|
|
|
y_init = Ymin_cell + getPadHeight ( cell ) + interval
|
|
|
|
##### Parcours des pads #####
|
|
for ins in args :
|
|
pad_height = ins.getAbutmentBox().getHeight()
|
|
pad_width = ins.getAbutmentBox().getWidth()
|
|
|
|
Xmin_pad = ins.getMasterCell().getAbutmentBox().getXMin()
|
|
Ymin_pad = ins.getMasterCell().getAbutmentBox().getYMin()
|
|
|
|
_x = Xmax_cell - pad_height # la position finale dans la cell
|
|
_y = y_init
|
|
|
|
# ATTENTION LES PLOTS DOIVENT ETRE PLACES SUR UNE GRILLE DE 5 LAMBDAS !!!!!!!!!!!!!!
|
|
_y = _y - ( _y % DbU_lambda(PITCH) )
|
|
|
|
# ATTENTION ON NE PLACE PAS DES PLOTS D ALIM EN DEHORS DE LA COURONNE INTERNE
|
|
if isInternalGroundPad ( ins ) or isInternalPowerPad ( ins ) \
|
|
or isExternalGroundPad ( ins ) or isExternalPowerPad ( ins ) :
|
|
cellAB = cell.getAbutmentBox()
|
|
coreAB = core.getAbutmentBox()
|
|
pad_height = getPadHeight ( cell )
|
|
if _y <= ( ( cellAB.getYMin() + pad_height ) + coreAB.getYMin() ) / 2 \
|
|
or _y >= ( ( cellAB.getYMax() - pad_height ) + coreAB.getYMax() ) / 2 :
|
|
raise ErrorMessage(2,"PadEast : pad %s must be closer to the center.\n"%str(ins.getName()))
|
|
|
|
# y calcule pour le pad suivant
|
|
y_init = _y + interval + pad_width
|
|
|
|
# avoir le x y apres orientation
|
|
box = ins.getMasterCell().getAbutmentBox()
|
|
_difx = Transformation ( 0, 0, 7 ).getBox ( box ).getXMin()
|
|
_dify = Transformation ( 0, 0, 7 ).getBox ( box ).getYMin()
|
|
|
|
ins.setTransformation ( Transformation ( _x - _difx
|
|
, _y - _dify
|
|
, Transformation.Orientation.YR
|
|
)
|
|
)
|
|
|
|
ins.setPlacementStatus ( Instance.PlacementStatus.FIXED )
|
|
|
|
UpdateSession.close()
|
|
|
|
#############
|
|
## PadWest ##
|
|
#############
|
|
def pyPadWest ( cell, core, args ) :
|
|
'''This function places pads at the west of the cell. It leaves an empty squarre of CARRE * CARRE, CARRE is defined in macro'''
|
|
|
|
global pad_west
|
|
|
|
# Sauvegarder la liste des plots
|
|
pad_west = args
|
|
|
|
UpdateSession.open()
|
|
|
|
# avoir le largeur du espace disponible du nord pour placer les pads
|
|
west_espace_width = core.getAbutmentBox().getXMin() - cell.getAbutmentBox().getXMin()
|
|
west_espace_longueur = cell.getAbutmentBox().getHeight() - ( 2 * getPadHeight ( cell ) )
|
|
|
|
# avoir le nombre de pads
|
|
nb_pads = len ( args )
|
|
|
|
# avoir le largeur total des pads
|
|
largeur = 0
|
|
for ins in args :
|
|
if ins.getPlacementStatus() :
|
|
raise ErrorMessage(2,"PadWest : the instance %s is already placed."%str(ins.getName()))
|
|
|
|
if ins.getAbutmentBox().getHeight() >= west_espace_width :
|
|
raise ErrorMessage(2,"PadWest : not enough space for pads.")
|
|
|
|
largeur += ins.getAbutmentBox().getWidth()
|
|
|
|
if largeur > west_espace_longueur :
|
|
raise ErrorMessage(2,"PadWest : not enough space for pads.")
|
|
|
|
# calculer l'interval entre les pads
|
|
interval = int ( ( west_espace_longueur - largeur ) / ( nb_pads + 1 ) )
|
|
|
|
# placer les pads
|
|
Xmin_cell = cell.getAbutmentBox().getXMin()
|
|
Ymin_cell = cell.getAbutmentBox().getYMin()
|
|
|
|
y_init = Ymin_cell + getPadHeight ( cell ) + interval
|
|
|
|
##### Parcours des pads #####
|
|
for ins in args :
|
|
pad_height = ins.getAbutmentBox().getHeight()
|
|
pad_width = ins.getAbutmentBox().getWidth()
|
|
|
|
_x = Xmin_cell # la position finale dans la cell
|
|
_y = y_init
|
|
|
|
# ATTENTION LES PLOTS DOIVENT ETRE PLACES SUR UNE GRILLE DE 5 LAMBDAS !!!!!!!!!!!!!!
|
|
_y = _y - ( _y % DbU_lambda(PITCH) )
|
|
|
|
# ATTENTION ON NE PLACE PAS DES PLOTS D ALIM EN DEHORS DE LA COURONNE INTERNE
|
|
if isInternalGroundPad ( ins ) or isInternalPowerPad ( ins ) \
|
|
or isExternalGroundPad ( ins ) or isExternalPowerPad ( ins ) :
|
|
cellAB = cell.getAbutmentBox()
|
|
coreAB = core.getAbutmentBox()
|
|
pad_height = getPadHeight ( cell )
|
|
|
|
if _y <= ( ( cellAB.getYMin() + pad_height ) + coreAB.getYMin() ) / 2 \
|
|
or _y >= ( ( cellAB.getYMax() - pad_height ) + coreAB.getYMax() ) / 2 :
|
|
raise ErrorMessage(2,"PadWest : pad %s must be closer to the center.\n"%str(ins.getName()))
|
|
|
|
# y calcule pour le pad suivant
|
|
y_init = _y + interval + pad_width
|
|
|
|
# avoir x y apres orientation
|
|
box = ins.getMasterCell().getAbutmentBox()
|
|
_difx = Transformation ( 0, 0, 1 ).getBox ( box ).getXMin()
|
|
_dify = Transformation ( 0, 0, 1 ).getBox ( box ).getYMin()
|
|
|
|
ins.setTransformation ( Transformation ( _x - _difx
|
|
, _y - _dify
|
|
, Transformation.Orientation.R1
|
|
)
|
|
)
|
|
|
|
ins.setPlacementStatus ( Instance.PlacementStatus.FIXED )
|
|
|
|
UpdateSession.close()
|
|
|
|
###############
|
|
## PowerRing ##
|
|
###############
|
|
def pyPowerRing ( cell, core, n ) :
|
|
'''This function places power rings around the core and around the plots
|
|
n is the number of rings (n vdd, n+1 vss)
|
|
, Distance between rings is defined by macro DbU_lambda ( RING_INTERVAL )
|
|
Width of rings is defined by macro DbU_lambda ( RING_WIDTH )'''
|
|
|
|
global pad_north, pad_south, pad_east, pad_west
|
|
global RING_INTERVAL, RING_WIDTH
|
|
|
|
db = DataBase.getDB()
|
|
|
|
topRoutingLayerName = Cfg.getParamString('katabatic.topRoutingLayer', 'METAL4').asString()
|
|
topRoutingLayer = db.getTechnology().getLayer( topRoutingLayerName )
|
|
allowedDepth = CRL.AllianceFramework.get().getRoutingGauge().getLayerDepth( topRoutingLayer )
|
|
|
|
print 'topRoutingLayer: <%s> depth:%d' % (topRoutingLayer.getName(), allowedDepth)
|
|
|
|
UpdateSession.open()
|
|
|
|
if pad_north == [] : raise ErrorMessage(2,"PowerRing : Pads in the north haven't been placed")
|
|
if pad_south == [] : raise ErrorMessage(2,"PowerRing : Pads in the south haven't been placed")
|
|
if pad_east == [] : raise ErrorMessage(2,"PowerRing : Pads in the east haven't been placed")
|
|
if pad_west == [] : raise ErrorMessage(2,"PowerRing : Pads in the west haven't been placed")
|
|
|
|
#############################
|
|
# PARAMETRE DU PLACEMENT ##
|
|
#############################
|
|
|
|
# le largeur du fil de routage
|
|
routage_segment_width = DbU_lambda(12)
|
|
|
|
# la distance entre les deux centres des couronnes
|
|
decalage = DbU_lambda(RING_WIDTH) + DbU_lambda(RING_INTERVAL)
|
|
|
|
# Recuperer les informations sur le core
|
|
core_width = core.getAbutmentBox().getWidth()
|
|
core_height = core.getAbutmentBox().getHeight()
|
|
core_Xmin = core.getAbutmentBox().getXMin()
|
|
core_Ymin = core.getAbutmentBox().getYMin()
|
|
core_Xmax = core.getAbutmentBox().getXMax()
|
|
core_Ymax = core.getAbutmentBox().getYMax()
|
|
mips_core = core.getMasterCell()
|
|
|
|
# Recuperer la hauteur des plots
|
|
pad_height = getPadHeight ( cell )
|
|
|
|
# Recuperer les layers ( Vias , Alus )
|
|
metal4 = db.getTechnology().getLayer ( "METAL4" )
|
|
metal3 = db.getTechnology().getLayer ( "METAL3" )
|
|
metal2 = db.getTechnology().getLayer ( "METAL2" )
|
|
metal1 = db.getTechnology().getLayer ( "METAL1" )
|
|
via1 = db.getTechnology().getLayer ( "VIA12" )
|
|
via2 = db.getTechnology().getLayer ( "VIA23" )
|
|
via3 = db.getTechnology().getLayer ( "VIA34" )
|
|
|
|
if (allowedDepth < 3):
|
|
hCoronaLayer = metal2
|
|
vCoronaLayer = metal3
|
|
cCoronaLayer = via2
|
|
else:
|
|
hCoronaLayer = metal4
|
|
vCoronaLayer = metal3
|
|
cCoronaLayer = via3
|
|
|
|
# Recuperer les nets ( qui connectent les connectors du plot : vdde , vsse , vddi , vssi , ck )
|
|
instance = cell.getInstance( pad_north[0].getName() )
|
|
model = instance.getMasterCell()
|
|
vddp = instance.getPlug ( model.getNet("vdde") ).getNet()
|
|
vssp = instance.getPlug ( model.getNet("vsse") ).getNet()
|
|
vdd = instance.getPlug ( model.getNet("vddi") ).getNet()
|
|
vss = instance.getPlug ( model.getNet("vssi") ).getNet()
|
|
ck = instance.getPlug ( model.getNet("ck" ) ).getNet()
|
|
# If nets are globals, get them from the netlist.
|
|
if not vddp: vddp = cell.getNet('vdde')
|
|
if not vssp: vssp = cell.getNet('vsse')
|
|
if not vdd: vdd = cell.getNet('vddi')
|
|
if not vss: vss = cell.getNet('vssi')
|
|
if not ck: ck = cell.getNet('cki')
|
|
|
|
# Prendre la hauteur, la longueur, Xmin et Ymin de ce modele
|
|
cell_height = cell.getAbutmentBox().getHeight()
|
|
cell_width = cell.getAbutmentBox().getWidth()
|
|
cell_Xmin = cell.getAbutmentBox().getXMin()
|
|
cell_Ymin = cell.getAbutmentBox().getYMin()
|
|
cell_Xmax = cell.getAbutmentBox().getXMax()
|
|
cell_Ymax = cell.getAbutmentBox().getYMax()
|
|
|
|
# Verifier s'il y a assez de places pour les couronnes
|
|
if ( cell_height - core_height ) < ( cell_width - core_width ) : smaller = cell_height - core_height
|
|
else : smaller = cell_width - core_width
|
|
limit = DbU_lambda ( int ( DbU_getLambda ( smaller ) / 2 ) ) - pad_height
|
|
|
|
if ( (2*n + 1) * DbU_lambda(RING_INTERVAL) + (2*n) * DbU_lambda(RING_WIDTH) ) >= limit : # 2*n + 1 spaces + 2*n width
|
|
raise ErrorMessage(2,"PowerRing : too many rings, not enough space")
|
|
|
|
# la distance entre les couronnes et le core
|
|
marge = DbU_lambda ( int ( DbU_getLambda ( limit - (2*n + 1 ) * DbU_lambda(RING_INTERVAL) - (2*n) * DbU_lambda(RING_WIDTH) ) ) / 2 )
|
|
|
|
east_power = []
|
|
west_power = []
|
|
north_power = []
|
|
south_power = []
|
|
|
|
searchVddVss ( cell, east_power, west_power, north_power, south_power )
|
|
#affichePad ( cell )
|
|
|
|
# Creation des listes pad_north_pin_y_vss et pad_north_pin_vdd
|
|
pad_north_pin_x_vss = []
|
|
pad_north_pin_x_vdd = []
|
|
for pad_inst in pad_north :
|
|
if isInternalGroundPad ( pad_inst ) or isInternalPowerPad ( pad_inst ) \
|
|
or isExternalGroundPad ( pad_inst ) or isExternalPowerPad ( pad_inst ):
|
|
transformation = pad_inst.getTransformation()
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_north_pin_x_vss.append ( [transformation.getX ( element.getX(), element.getY() ), element.getBoundingBox().getHalfWidth()] )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_north_pin_x_vdd.append ( [transformation.getX ( element.getX(), element.getY() ), element.getBoundingBox().getHalfWidth()] )
|
|
|
|
|
|
# Creation des listes pad_south_pin_y_vss et pad_south_pin_vdd
|
|
pad_south_pin_x_vss = []
|
|
pad_south_pin_x_vdd = []
|
|
for pad_inst in pad_south :
|
|
if isInternalGroundPad ( pad_inst ) or isInternalPowerPad ( pad_inst ) \
|
|
or isExternalGroundPad ( pad_inst ) or isExternalPowerPad ( pad_inst ):
|
|
transformation = pad_inst.getTransformation()
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_south_pin_x_vss.append ( [transformation.getX ( element.getX(), element.getY() ), element.getBoundingBox().getHalfWidth()] )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_south_pin_x_vdd.append ( [transformation.getX ( element.getX(), element.getY() ), element.getBoundingBox().getHalfWidth()] )
|
|
|
|
|
|
# Creation des listes pad_east_pin_y_vss et pad_east_pin_vdd
|
|
pad_east_pin_y_vss = []
|
|
pad_east_pin_y_vdd = []
|
|
for pad_inst in pad_east :
|
|
if isInternalGroundPad ( pad_inst ) or isInternalPowerPad ( pad_inst ) \
|
|
or isExternalGroundPad ( pad_inst ) or isExternalPowerPad ( pad_inst ):
|
|
transformation = pad_inst.getTransformation()
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_east_pin_y_vss.append ( [transformation.getY ( element.getX(), element.getY() ), element.getBoundingBox().getHalfHeight()] )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_east_pin_y_vdd.append ( [transformation.getY ( element.getX(), element.getY() ), element.getBoundingBox().getHalfHeight()] )
|
|
|
|
# Creation des listes pad_west_pin_y_vss et pad_west_pin_vdd
|
|
pad_west_pin_y_vss = []
|
|
pad_west_pin_y_vdd = []
|
|
for pad_inst in pad_west :
|
|
if isInternalGroundPad ( pad_inst ) or isInternalPowerPad ( pad_inst ) \
|
|
or isExternalGroundPad ( pad_inst ) or isExternalPowerPad ( pad_inst ):
|
|
transformation = pad_inst.getTransformation()
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_west_pin_y_vss.append ( [transformation.getY ( element.getX(), element.getY() ), element.getBoundingBox().getHalfHeight()] )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
if re.search ( "METAL2", str ( element.getLayer() ) ) \
|
|
and ( ( element.getY() - element.getBoundingBox().getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
pad_west_pin_y_vdd.append ( [transformation.getY ( element.getX(), element.getY() ), element.getBoundingBox().getHalfHeight()] )
|
|
|
|
#####################################
|
|
## PLACER LES COURONNES INTERNES ##
|
|
#####################################
|
|
|
|
# les listes pour sauvegarder les segments des couronnes des quatres coins
|
|
vertical_west_vss = []
|
|
vertical_east_vss = []
|
|
horizontal_south_vss = []
|
|
horizontal_north_vss = []
|
|
|
|
vertical_west_vdd = []
|
|
vertical_east_vdd = []
|
|
horizontal_south_vdd = []
|
|
horizontal_north_vdd = []
|
|
|
|
init_Xmin = core_Xmin - marge - DbU_lambda(RING_WIDTH) / 2
|
|
init_Xmin = init_Xmin - ( init_Xmin % DbU_lambda(PITCH) )
|
|
init_Ymin = core_Ymin - marge - DbU_lambda(RING_WIDTH) / 2
|
|
init_Ymin = init_Ymin - ( init_Ymin % DbU_lambda(PITCH) )
|
|
init_Xmax = core_Xmax + marge + DbU_lambda(RING_WIDTH) / 2
|
|
init_Xmax = init_Xmax - ( init_Xmax % DbU_lambda(PITCH) )
|
|
init_Ymax = core_Ymax + marge + DbU_lambda(RING_WIDTH) / 2
|
|
init_Ymax = init_Ymax - ( init_Ymax % DbU_lambda(PITCH) )
|
|
|
|
contact_side = DbU_lambda(RING_WIDTH-1)
|
|
|
|
|
|
for i in range ( 0, 2*n+1, 2 ) :
|
|
contact1 = Contact.create ( vss, cCoronaLayer, init_Xmin - decalage*i, init_Ymin - decalage*i, contact_side, contact_side )
|
|
contact2 = Contact.create ( vss, cCoronaLayer, init_Xmin - decalage*i, init_Ymax + decalage*i, contact_side, contact_side )
|
|
contact3 = Contact.create ( vss, cCoronaLayer, init_Xmax + decalage*i, init_Ymax + decalage*i, contact_side, contact_side )
|
|
contact4 = Contact.create ( vss, cCoronaLayer, init_Xmax + decalage*i, init_Ymin - decalage*i, contact_side, contact_side )
|
|
|
|
vertical_west_vss.append ( Vertical.create ( contact1, contact2, vCoronaLayer, init_Xmin - decalage*i, DbU_lambda(RING_WIDTH) ) )
|
|
vertical_east_vss.append ( Vertical.create ( contact3, contact4, vCoronaLayer, init_Xmax + decalage*i, DbU_lambda(RING_WIDTH) ) )
|
|
horizontal_south_vss.append ( Horizontal.create ( contact1, contact4, hCoronaLayer, init_Ymin - decalage*i, DbU_lambda(RING_WIDTH) ) )
|
|
horizontal_north_vss.append ( Horizontal.create ( contact2, contact3, hCoronaLayer, init_Ymax + decalage*i, DbU_lambda(RING_WIDTH) ) )
|
|
|
|
if i != 2*n :
|
|
contact1 = Contact.create ( vdd, cCoronaLayer, init_Xmin - decalage* ( i + 1 ), init_Ymin - decalage*( i + 1 ) , contact_side, contact_side )
|
|
contact2 = Contact.create ( vdd, cCoronaLayer, init_Xmin - decalage* ( i + 1 ), init_Ymax + decalage*( i + 1 ) , contact_side, contact_side )
|
|
contact3 = Contact.create ( vdd, cCoronaLayer, init_Xmax + decalage* ( i + 1 ), init_Ymax + decalage*( i + 1 ) , contact_side, contact_side )
|
|
contact4 = Contact.create ( vdd, cCoronaLayer, init_Xmax + decalage* ( i + 1 ), init_Ymin - decalage*( i + 1 ) , contact_side, contact_side )
|
|
vertical_west_vdd.append ( Vertical.create ( contact1, contact2, vCoronaLayer, init_Xmin - decalage* ( i + 1 ), DbU_lambda(RING_WIDTH) ) )
|
|
vertical_east_vdd.append ( Vertical.create ( contact3, contact4, vCoronaLayer, init_Xmax + decalage* ( i + 1 ), DbU_lambda(RING_WIDTH) ) )
|
|
horizontal_south_vdd.append ( Horizontal.create ( contact1, contact4, hCoronaLayer, init_Ymin - decalage* ( i + 1 ), DbU_lambda(RING_WIDTH) ) )
|
|
horizontal_north_vdd.append ( Horizontal.create ( contact2, contact3, hCoronaLayer, init_Ymax + decalage* ( i + 1 ), DbU_lambda(RING_WIDTH) ) )
|
|
|
|
# MACRO pour les directions d'access des pins
|
|
UNDEFINED = 0
|
|
NORTH = 1
|
|
SOUTH = 2
|
|
EAST = 3
|
|
WEST = 4
|
|
|
|
##############################################################
|
|
## Connecter les pins de vss aux couronnes de vss ##
|
|
##############################################################
|
|
core_transformation = core.getTransformation()
|
|
|
|
# parcourir les pins de vss
|
|
for element in mips_core.getNet("vss").getPins():
|
|
element_layer_name = str ( element.getLayer().getName() ) # string, nom du layer
|
|
# avoir le x, y transforme
|
|
_x = core_transformation.getX ( element.getX(), element.getY() )
|
|
_y = core_transformation.getY ( element.getX(), element.getY() )
|
|
|
|
# Creer un contact a la place du pin
|
|
if (allowedDepth > 2) and \
|
|
re.search ( "METAL4", element_layer_name ) : old_contact = Contact.create ( vss, metal4, _x, _y , element.getHeight(), element.getHeight() )
|
|
elif re.search ( "METAL1", element_layer_name ) : old_contact = Contact.create ( vss, metal1, _x, _y , element.getHeight(), element.getHeight() )
|
|
elif re.search ( "METAL3", element_layer_name ) : old_contact = Contact.create ( vss, metal3, _x, _y , element.getHeight(), element.getHeight() )
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s.\n" % element_layer_name)
|
|
|
|
# Connection du cote de l'ouest
|
|
if element.getAccessDirection() == WEST :
|
|
# Parcourir tous les couronnes vss
|
|
halfHeight = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [yPin,pinHalfHeight] in pad_west_pin_y_vss + pad_west_pin_y_vdd :
|
|
if ( _y + halfHeight + DbU_lambda(3) >= yPin - pinHalfHeight and _y + halfHeight + DbU_lambda(3) <= yPin + pinHalfHeight ) \
|
|
or ( _y - halfHeight - DbU_lambda(3) <= yPin + pinHalfHeight and _y - halfHeight - DbU_lambda(3) >= yPin - pinHalfHeight ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti + 1 ) :
|
|
contact_x = init_Xmin - ( decalage*2 )*i # x du contact a creer
|
|
contact_side = element.getHeight() - DbU_lambda(1.0)
|
|
|
|
if (allowedDepth > 2) and re.search( "METAL4", element_layer_name ) :
|
|
contact = Contact.create ( vss, via3 , contact_x , _y , contact_side , contact_side )
|
|
horizontal = Horizontal.create ( contact, old_contact , metal4 , _y , element.getHeight() )
|
|
old_contact = contact
|
|
else :
|
|
contact_via1 = Contact.create ( vss, via1 , contact_x , _y , contact_side , contact_side )
|
|
contact_via2 = Contact.create ( vss, via2 , contact_x , _y , contact_side , contact_side )
|
|
horizontal = Horizontal.create ( contact_via1 , old_contact , metal1 , _y , element.getHeight() )
|
|
old_contact = contact_via1
|
|
|
|
# Connection du cote de l'est
|
|
if element.getAccessDirection() == EAST :
|
|
# Parcourir tous les couronnes vss
|
|
halfHeight = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [yPin,pinHalfHeight] in pad_east_pin_y_vss + pad_east_pin_y_vdd :
|
|
if ( _y + halfHeight + DbU_lambda(3) >= yPin - pinHalfHeight and _y + halfHeight + DbU_lambda(3) <= yPin + pinHalfHeight ) \
|
|
or ( _y - halfHeight - DbU_lambda(3) <= yPin + pinHalfHeight and _y - halfHeight - DbU_lambda(3) >= yPin - pinHalfHeight ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti + 1 ) :
|
|
contact_x = init_Xmax + ( decalage*2 )*i # x du contact a creer
|
|
contact_side = element.getHeight() - DbU_lambda(1.0)
|
|
|
|
if (allowedDepth > 2) and re.search( "METAL4", element_layer_name ) :
|
|
contact = Contact.create ( vss, via3 , contact_x , _y , contact_side, contact_side )
|
|
horizontal = Horizontal.create ( contact, old_contact , metal4 , _y , element.getHeight() )
|
|
old_contact = contact
|
|
else :
|
|
contact_via1 = Contact.create ( vss, via1 , contact_x , _y , contact_side , contact_side )
|
|
contact_via2 = Contact.create ( vss, via2 , contact_x , _y , contact_side , contact_side )
|
|
horizontal = Horizontal.create ( contact_via1 , old_contact , metal1 , _y , element.getHeight() )
|
|
old_contact = contact_via1
|
|
|
|
# Connection du cote du nord
|
|
if element.getAccessDirection() == NORTH :
|
|
# Parcourir tous les couronnes vss
|
|
halfWidth = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [xPin,pinHalfWidth] in pad_north_pin_x_vss + pad_north_pin_x_vdd :
|
|
if ( _x + halfWidth + DbU_lambda(3) >= xPin - pinHalfWidth and _x + halfWidth + DbU_lambda(3) <= xPin + pinHalfWidth ) \
|
|
or ( _x - halfWidth - DbU_lambda(3) <= xPin + pinHalfWidth and _x - halfWidth - DbU_lambda(3) >= xPin - pinHalfWidth ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti + 1 ) :
|
|
contact_y = init_Ymax + ( decalage*2 )*i # y du contact a creer
|
|
|
|
if re.search ( "METAL3", element_layer_name ) :
|
|
contact = Contact.create ( vss, via3, _x, contact_y, element.getHeight(), element.getHeight() )
|
|
vertical = Vertical.create ( contact, old_contact, metal3, _x, DbU_lambda(RING_WIDTH) )
|
|
old_contact = contact
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s.\n"% element_layer_name)
|
|
|
|
# Connection du cote du sud
|
|
if element.getAccessDirection() == SOUTH :
|
|
# Parcourir tous les couronnes vss
|
|
halfWidth = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [xPin,pinHalfWidth] in pad_south_pin_x_vss + pad_south_pin_x_vdd :
|
|
if ( _x + halfWidth + DbU_lambda(3) >= xPin - pinHalfWidth and _x + halfWidth + DbU_lambda(3) <= xPin + pinHalfWidth ) \
|
|
or ( _x - halfWidth - DbU_lambda(3) <= xPin + pinHalfWidth and _x - halfWidth - DbU_lambda(3) >= xPin - pinHalfWidth ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti+1 ) :
|
|
contact_y = init_Ymin - ( decalage*2 )*i # x du contact a creer
|
|
|
|
if re.search ( "METAL3", element_layer_name ) :
|
|
contact = Contact.create ( vss, via3, _x, contact_y, element.getHeight(), element.getHeight() )
|
|
vertical = Vertical.create ( contact, old_contact, metal3, _x, DbU_lambda(RING_WIDTH) )
|
|
old_contact = contact
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s."%element_layer_name)
|
|
|
|
# End of while
|
|
|
|
#######################################################
|
|
### Connecter les pins de vdd aux couronnes de vdd ###
|
|
#######################################################
|
|
core_transformation = core.getTransformation()
|
|
|
|
# parcourir les pins de vdd
|
|
for element in mips_core.getNet("vdd").getPins():
|
|
element_layer_name = str(element.getLayer().getName()) # string , nom du layer
|
|
# avoir x, y transforme
|
|
_x = core_transformation.getX ( element.getX(), element.getY() )
|
|
_y = core_transformation.getY ( element.getX(), element.getY() )
|
|
|
|
# Creer un contact a la place du pin
|
|
if (allowedDepth > 2) and \
|
|
re.search ( "METAL4", element_layer_name ) : old_contact = Contact.create ( vdd, metal4, _x, _y , element.getHeight(), element.getHeight() )
|
|
elif re.search ( "METAL1", element_layer_name ) : old_contact = Contact.create ( vdd, metal1, _x, _y , element.getHeight(), element.getHeight() )
|
|
elif re.search ( "METAL3", element_layer_name ) : old_contact = Contact.create ( vdd, metal3, _x, _y , element.getHeight(), element.getHeight() )
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s."%element_layer_name)
|
|
|
|
# Connection du cote de l'ouest
|
|
if element.getAccessDirection() == WEST :
|
|
# Parcourir tous les couronnes vdd
|
|
halfHeight = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [yPin,pinHalfHeight] in pad_west_pin_y_vss + pad_west_pin_y_vdd :
|
|
if ( _y + halfHeight + DbU_lambda(3) >= yPin - pinHalfHeight and _y + halfHeight + DbU_lambda(3) <= yPin + pinHalfHeight ) \
|
|
or ( _y - halfHeight - DbU_lambda(3) <= yPin + pinHalfHeight and _y - halfHeight - DbU_lambda(3) >= yPin - pinHalfHeight ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti ) :
|
|
contact_x = init_Xmin - decalage - ( decalage*2 )*i # x du contact a creer
|
|
contact_side = element.getHeight() - DbU_lambda(1.0)
|
|
|
|
if (allowedDepth > 2) and re.search( "METAL4", element_layer_name ) :
|
|
contact = Contact.create ( vdd, via3, contact_x, _y, contact_side, contact_side )
|
|
horizontal = Horizontal.create ( contact, old_contact, metal4, _y, element.getHeight() )
|
|
old_contact = contact
|
|
else :
|
|
contact_via1 = Contact.create ( vdd, via1, contact_x, _y, contact_side, contact_side )
|
|
contact_via2 = Contact.create ( vdd, via2, contact_x, _y, contact_side, contact_side )
|
|
horizontal = Horizontal.create ( contact_via1, old_contact, metal1, _y, element.getHeight() )
|
|
old_contact = contact_via1
|
|
|
|
# Connection du cote de l'est
|
|
if element.getAccessDirection() == EAST :
|
|
# Parcourir tous les couronnes vdd
|
|
halfHeight = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [yPin,pinHalfHeight] in pad_east_pin_y_vss + pad_east_pin_y_vdd :
|
|
if ( _y + halfHeight + DbU_lambda(3) >= yPin - pinHalfHeight and _y + halfHeight + DbU_lambda(3) <= yPin + pinHalfHeight ) \
|
|
or ( _y - halfHeight - DbU_lambda(3) <= yPin + pinHalfHeight and _y - halfHeight - DbU_lambda(3) >= yPin - pinHalfHeight ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti ) :
|
|
contact_x = init_Xmax + ( decalage*2 )*i + decalage # x du contact a creer
|
|
contact_side = element.getHeight() - DbU_lambda(1.0)
|
|
|
|
if (allowedDepth > 2) and re.search( "METAL4", element_layer_name ) :
|
|
contact = Contact.create ( vdd, via3 , contact_x , _y , contact_side , contact_side )
|
|
horizontal = Horizontal.create ( contact, old_contact , metal4 , _y , element.getHeight() )
|
|
old_contact = contact
|
|
else :
|
|
contact_via1 = Contact.create ( vdd, via1, contact_x, _y, contact_side, contact_side )
|
|
contact_via2 = Contact.create ( vdd, via2, contact_x, _y, contact_side, contact_side )
|
|
horizontal = Horizontal.create ( contact_via1, old_contact, metal1, _y, element.getHeight() )
|
|
old_contact = contact_via1
|
|
|
|
# Connection du cote du nord
|
|
if element.getAccessDirection() == NORTH :
|
|
# Parcourir tous les couronnes vdd
|
|
halfWidth = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [xPin,pinHalfWidth] in pad_north_pin_x_vss + pad_north_pin_x_vdd :
|
|
if ( _x + halfWidth + DbU_lambda(3) >= xPin - pinHalfWidth and _x + halfWidth + DbU_lambda(3) <= xPin + pinHalfWidth ) \
|
|
or ( _x - halfWidth - DbU_lambda(3) <= xPin + pinHalfWidth and _x - halfWidth - DbU_lambda(3) >= xPin - pinHalfWidth ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti ) :
|
|
contact_y = init_Ymax + decalage + ( decalage*2 )*i # x du contact a creer
|
|
|
|
if re.search ( "METAL3", element_layer_name ) :
|
|
contact = Contact.create ( vdd, via3, _x, contact_y, element.getHeight(), element.getHeight() )
|
|
vertical = Vertical.create ( contact, old_contact, metal3, _x, DbU_lambda(RING_WIDTH) )
|
|
old_contact = contact
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s."%element_layer_name)
|
|
|
|
# Connection du cote du sud
|
|
if element.getAccessDirection() == SOUTH :
|
|
# Parcourir tous les couronnes vdd
|
|
halfWidth = element.getHeight() / 2
|
|
lastVerti = n
|
|
for [xPin,pinHalfWidth] in pad_south_pin_x_vss + pad_south_pin_x_vdd :
|
|
if ( _x + halfWidth + DbU_lambda(3) >= xPin - pinHalfWidth and _x + halfWidth + DbU_lambda(3) <= xPin + pinHalfWidth ) \
|
|
or ( _x - halfWidth - DbU_lambda(3) <= xPin + pinHalfWidth and _x - halfWidth - DbU_lambda(3) >= xPin - pinHalfWidth ):
|
|
lastVerti = n/2 + (n+1)%2
|
|
|
|
for i in range ( lastVerti ) :
|
|
contact_y = init_Ymin - decalage - ( decalage*2 )*i # x du contact a creer
|
|
|
|
if re.search ( "METAL3", element_layer_name ) :
|
|
contact = Contact.create ( vdd, via3, _x, contact_y, element.getHeight(), element.getHeight() )
|
|
vertical = Vertical.create ( contact, old_contact, metal3, _x, DbU_lambda(RING_WIDTH) )
|
|
old_contact = contact
|
|
else :
|
|
raise ErrorMessage(2,"wrong layer of pin in the west of core : %s."%element_layer_name)
|
|
|
|
# End of while
|
|
|
|
# Attention au decalage de 1/2 de CMETAL
|
|
#LAMBDA = DbU_lambda ( 1 ) / 2
|
|
LAMBDA = DbU_lambda ( 1 )
|
|
|
|
###############################################################
|
|
# Connection entre couronnes internes et couronnes externes #
|
|
###############################################################
|
|
for pad_inst in pad_east :
|
|
if isInternalPowerPad ( pad_inst ) or isExternalPowerPad ( pad_inst ) \
|
|
or isInternalGroundPad ( pad_inst ) or isExternalGroundPad ( pad_inst ) :
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
Contact.create ( vss, via2, X, Y, height, height )
|
|
contactPad = Contact.create ( vss, via1, X, Y, height, height )
|
|
Horizontal.create ( contactPad, vertical_east_vss[-1], metal1, Y, DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vss, via1, vertical_east_vss[-1].getX(), Y, height, height )
|
|
Contact.create ( vss, via2, vertical_east_vss[-1].getX(), Y, height, height )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
#Contact ( vdd, via2, X, Y, height, height )
|
|
contactPad = Contact.create ( vdd, via1, X, Y, height, height )
|
|
Horizontal.create ( contactPad, vertical_east_vdd[-1], metal1, Y, DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vdd, via1, vertical_east_vdd[-1].getX(), Y, height, height )
|
|
Contact.create ( vdd, via2, vertical_east_vdd[-1].getX(), Y, height, height )
|
|
|
|
for pad_inst in pad_west :
|
|
if isInternalPowerPad ( pad_inst ) or isExternalPowerPad ( pad_inst ) \
|
|
or isInternalGroundPad ( pad_inst ) or isExternalGroundPad ( pad_inst ) :
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
#Contact ( vss, via2, X, Y, height, height )
|
|
contactPad = Contact.create ( vss, via1, X, Y, height, height )
|
|
Horizontal.create ( contactPad, vertical_west_vss[-1], metal1, Y, DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vss, via1, vertical_west_vss[-1].getX(), Y, height, height )
|
|
Contact.create ( vss, via2, vertical_west_vss[-1].getX(), Y, height, height )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
#Contact ( vdd, via2, X, Y, height, height )
|
|
contactPad = Contact.create ( vdd, via1, X, Y, height, height )
|
|
Horizontal.create ( contactPad, vertical_west_vdd[-1], metal1, Y, DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vdd, via1, vertical_west_vdd[-1].getX(), Y, height, height )
|
|
Contact.create ( vdd, via2, vertical_west_vdd[-1].getX(), Y, height, height )
|
|
|
|
for pad_inst in pad_north :
|
|
if isInternalPowerPad ( pad_inst ) or isExternalPowerPad ( pad_inst ) \
|
|
or isInternalGroundPad ( pad_inst ) or isExternalGroundPad ( pad_inst ) :
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
Contact.create ( vss, via1, X, Y, height, height )
|
|
#Contact.create ( vss, via2, X, Y, height, height )
|
|
|
|
contactPad = Contact.create ( vss, metal1, X, Y, height, height )
|
|
Vertical.create ( contactPad, horizontal_north_vss[-1], metal1, X , DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vss, via1, X, horizontal_north_vss[-1].getY(), height, height )
|
|
if allowedDepth > 2:
|
|
Contact.create ( vss, via2, X, horizontal_north_vss[-1].getY(), height, height )
|
|
Contact.create ( vss, via3, X, horizontal_north_vss[-1].getY(), height, height )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
Contact.create ( vdd, via1, X, Y, height, height )
|
|
#Contact.create ( vdd, via2, X, Y, height, height )
|
|
|
|
contactPad = Contact.create ( vdd, metal1, X, Y, height, height )
|
|
Vertical.create ( contactPad, horizontal_north_vdd[-1], metal1, X, DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vdd, via1, X, horizontal_north_vdd[-1].getY(), height, height )
|
|
if allowedDepth > 2:
|
|
Contact.create ( vdd, via2, X, horizontal_north_vdd[-1].getY(), height, height )
|
|
Contact.create ( vdd, via3, X, horizontal_north_vdd[-1].getY(), height, height )
|
|
|
|
for pad_inst in pad_south :
|
|
if isInternalPowerPad ( pad_inst ) or isExternalPowerPad ( pad_inst ) \
|
|
or isInternalGroundPad ( pad_inst ) or isExternalGroundPad ( pad_inst ) :
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vssi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
Contact.create ( vss, via1, X, Y, height, height )
|
|
#Contact.create ( vss, via2, X, Y, height, height )
|
|
|
|
contactPad = Contact.create ( vss, metal1, X, Y, height, height )
|
|
Vertical.create ( contactPad, horizontal_south_vss[-1], metal1, X , DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vss, via1, X, horizontal_south_vss[-1].getY(), height, height )
|
|
if allowedDepth > 2:
|
|
Contact.create ( vss, via2, X, horizontal_south_vss[-1].getY(), height, height )
|
|
Contact.create ( vss, via3, X, horizontal_south_vss[-1].getY(), height, height )
|
|
|
|
for element in NetExternalComponents.get ( pad_inst.getMasterCell().getNet("vddi") ):
|
|
layer = element.getLayer()
|
|
height = element.getBoundingBox().getHeight() - DbU_lambda(1.0)
|
|
|
|
if re.search ( "METAL3", str ( layer ) ) \
|
|
and ( ( element.getY() - ( height / 2 ) ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
X = pad_inst.getTransformation().getX ( element.getX(), element.getY() )
|
|
Y = pad_inst.getTransformation().getY ( element.getX(), element.getY() )
|
|
|
|
Contact.create ( vdd, via1, X, Y, height, height )
|
|
#Contact.create ( vdd, via2, X, Y, height, height )
|
|
|
|
contactPad = Contact.create ( vdd, metal1, X, Y, height, height )
|
|
Vertical.create ( contactPad, horizontal_south_vdd[-1], metal1, X , DbU_lambda ( RING_WIDTH ) )
|
|
Contact.create ( vdd, via1, X, horizontal_south_vdd[-1].getY(), height, height )
|
|
if allowedDepth > 2:
|
|
Contact.create ( vdd, via2, X, horizontal_south_vdd[-1].getY(), height, height )
|
|
Contact.create ( vdd, via3, X, horizontal_south_vdd[-1].getY(), height, height )
|
|
|
|
|
|
##################################### ###########################
|
|
## PLACER LES COURONNES EXTERNES ## # 1 2 #
|
|
##################################### # #
|
|
# #
|
|
# #
|
|
points_0 = [] # CHIP #
|
|
points_1 = [] # #
|
|
points_2 = [] # #
|
|
points_3 = [] # #
|
|
# #
|
|
# 0 3 #
|
|
###########################
|
|
|
|
instance = cell.getInstance ( pad_north[0].getName() )
|
|
trans = instance.getTransformation()
|
|
|
|
for net in instance.getMasterCell().getNets():
|
|
if net.isSupply() or net.isClock() :
|
|
for component in NetExternalComponents.get(net):
|
|
plug = instance.getPlug ( net )
|
|
NET = getNetFromPlug( plug )
|
|
if ( not NET ) : raise ErrorMessage(2,"Error plug : %s must be connected" % str(plug.getName()))
|
|
|
|
layer = getNonCLayer ( component.getLayer() )
|
|
|
|
# On applique la transformation au component, et on recupere les nouvelles coordonnees
|
|
Y = cell_Ymax + cell_Ymin - trans.getY ( component.getX(), component.getY() )
|
|
|
|
# On recupere la hauteur du component pour router sur la meme hauteur
|
|
RING_HEIGHT = component.getBoundingBox().getHeight()
|
|
|
|
# On calcule les differents points aux angles pour chaque net
|
|
X_point = cell_Xmin + Y
|
|
Y_point = cell_Ymin + Y
|
|
contact = Contact.create ( NET, layer, X_point, Y_point, RING_HEIGHT, RING_HEIGHT )
|
|
points_0.append ( dict ( [ ['X',X_point], ['Y',Y_point], ['N',NET], ['L',layer], ['R',RING_HEIGHT], ['C',contact] ] ) )
|
|
|
|
X_point = cell_Xmin + Y
|
|
Y_point = cell_Ymin + ( cell_Ymax - Y )
|
|
contact = Contact.create ( NET, layer, X_point, Y_point, RING_HEIGHT, RING_HEIGHT )
|
|
points_1.append ( dict ( [ ['X',X_point], ['Y',Y_point], ['N',NET], ['L',layer], ['R',RING_HEIGHT], ['C',contact] ] ) )
|
|
|
|
X_point = cell_Xmin + ( cell_Xmax - Y )
|
|
Y_point = cell_Ymin + ( cell_Ymax - Y )
|
|
contact = Contact.create ( NET, layer, X_point, Y_point, RING_HEIGHT, RING_HEIGHT )
|
|
points_2.append ( dict ( [ ['X',X_point], ['Y',Y_point], ['N',NET], ['L',layer], ['R',RING_HEIGHT], ['C',contact] ] ) )
|
|
|
|
X_point = cell_Xmin + ( cell_Xmax - Y )
|
|
Y_point = cell_Ymin + Y
|
|
contact = Contact.create ( NET, layer, X_point, Y_point, RING_HEIGHT, RING_HEIGHT )
|
|
points_3.append ( dict ( [ ['X',X_point], ['Y',Y_point], ['N',NET], ['L',layer], ['R',RING_HEIGHT], ['C',contact] ] ) )
|
|
# end of while
|
|
# end of while
|
|
|
|
#print "\n\n\n\npoints_0 : ", points_0 , "\n\npoints_1 : " ,points_1 , "\n\npoints_2 : " ,points_2 , "\n\npoints_3 : " , points_3 , "\n\n\n\n"
|
|
|
|
# Placer au cote du nord
|
|
for ins_pad in pad_north :
|
|
Y_pad = DbU_lambda ( int ( DbU_getLambda ( ins_pad.getAbutmentBox().getYCenter() ) ) )
|
|
X_pad = DbU_lambda ( int ( DbU_getLambda ( ins_pad.getAbutmentBox().getXCenter() ) ) )
|
|
|
|
if ins_pad == pad_north[0] :
|
|
for point in points_1 :
|
|
contact = Contact.create ( point['N'], point['L'], X_pad, point['Y'], point['R'], point['R'] )
|
|
Horizontal.create ( point['C'], contact, point['L'], point['Y'], point['R'] )
|
|
else :
|
|
for point in points_1 :
|
|
Horizontal.create ( point['N'], point['L'], point['Y'], point['R'], old_X_pad, X_pad )
|
|
|
|
if ins_pad == pad_north[-1] :
|
|
for point in points_2 :
|
|
contact = Contact.create ( point['N'], point['L'], X_pad, point['Y'], point['R'], point['R'] )
|
|
Horizontal.create ( contact, point['C'], point['L'], point['Y'], point['R'] )
|
|
|
|
old_X_pad = X_pad
|
|
|
|
# Placer au cote de l'est
|
|
for ins_pad in pad_east :
|
|
Y_pad = ins_pad.getAbutmentBox().getYCenter()
|
|
X_pad = ins_pad.getAbutmentBox().getXCenter()
|
|
|
|
if ins_pad == pad_east[0] :
|
|
for point in points_3 :
|
|
contact = Contact.create ( point['N'], point['L'], point['X'], Y_pad, point['R'], point['R'] )
|
|
Vertical.create ( point['C'], contact, point['L'], point['X'], point['R'] )
|
|
else :
|
|
for point in points_3 :
|
|
Vertical.create ( point['N'], point['L'], point['X'], point['R'], old_Y_pad, Y_pad )
|
|
|
|
if ins_pad == pad_east[-1] :
|
|
for point in points_2 :
|
|
contact = Contact.create ( point['N'], point['L'], point['X'], Y_pad, point['R'], point['R'] )
|
|
Vertical.create ( contact, point['C'], point['L'], point['X'], point['R'] )
|
|
|
|
old_Y_pad = Y_pad
|
|
|
|
# Placer au cote du south
|
|
for ins_pad in pad_south :
|
|
Y_pad = ins_pad.getAbutmentBox().getYCenter()
|
|
X_pad = ins_pad.getAbutmentBox().getXCenter()
|
|
|
|
if ins_pad == pad_south[0] :
|
|
for point in points_0 :
|
|
contact = Contact.create ( point['N'], point['L'], X_pad, point['Y'], point['R'], point['R'] )
|
|
Horizontal.create ( point['C'], contact, point['L'], point['Y'], point['R'] )
|
|
else :
|
|
for point in points_0 :
|
|
Horizontal.create ( point['N'], point['L'], point['Y'], point['R'], old_X_pad, X_pad )
|
|
|
|
if ins_pad == pad_south[-1] :
|
|
for point in points_3 :
|
|
contact = Contact.create ( point['N'], point['L'], X_pad, point['Y'], point['R'], point['R'] )
|
|
Horizontal.create ( contact, point['C'], point['L'], point['Y'], point['R'] )
|
|
|
|
old_X_pad = X_pad
|
|
|
|
# Placer au cote de l'ouest
|
|
for ins_pad in pad_west :
|
|
Y_pad = ins_pad.getAbutmentBox().getYCenter()
|
|
X_pad = ins_pad.getAbutmentBox().getXCenter()
|
|
|
|
if ins_pad == pad_west[0] :
|
|
for point in points_0 :
|
|
contact = Contact.create ( point['N'], point['L'], point['X'], Y_pad, point['R'], point['R'] )
|
|
Vertical.create ( point['C'], contact, point['L'], point['X'], point['R'] )
|
|
else :
|
|
for point in points_0 :
|
|
Vertical.create ( point['N'], point['L'], point['X'], point['R'], old_Y_pad, Y_pad )
|
|
|
|
if ins_pad == pad_west[-1] :
|
|
for point in points_1 :
|
|
contact = Contact.create ( point['N'], point['L'], point['X'], Y_pad, point['R'], point['R'] )
|
|
Vertical.create ( contact, point['C'], point['L'], point['X'], point['R'] )
|
|
|
|
old_Y_pad = Y_pad
|
|
|
|
UpdateSession.close()
|
|
|
|
#######################################
|
|
def create_inst ( model, name, cell ) :
|
|
|
|
# Error : if the cell the instance has to be instanciated in does not exist
|
|
if not cell :
|
|
raise ErrorMessage(2,"Cannot create instance %s : the cell does not exist."%name)
|
|
|
|
# Load model in the database
|
|
modelmastercell = CRL.AllianceFramework.get().getCell ( model, CRL.Catalog.State.Views )
|
|
|
|
# Error : if the model is not found in the libraries
|
|
if not modelmastercell :
|
|
raise ErrorMessage(2,"Cannot create instance %s : model %s does not exist in the database."%(name,model))
|
|
|
|
inst = Instance.create ( cell, name, modelmastercell )
|
|
|
|
# Connection
|
|
plugGround = inst.getPlug ( iter(modelmastercell.getGroundNets()).next() )
|
|
plugGround.setNet ( iter(cell.getGroundNets()).next() )
|
|
plugPower = inst.getPlug ( iter(modelmastercell.getPowerNets()).next() )
|
|
plugPower.setNet ( iter(cell.getPowerNets()).next() )
|
|
|
|
return inst
|
|
|
|
##########################
|
|
def place ( inst, x, y, orientation ) :
|
|
|
|
# Error : if the hurricane instance does not exist
|
|
if not inst :
|
|
raise ErrorMessage(2,"Layout : The instance of %s has not been created."%str(inst.getName()))
|
|
|
|
# Error : if the instance is already placed
|
|
if inst.getPlacementStatus() == Instance.PlacementStatus.FIXED :
|
|
raise ErrorMessage(2,"Placement : the instance %s is already placed."%str(inst.getName()))
|
|
|
|
UpdateSession.open()
|
|
|
|
## A COMPLETER POUR FAIRE DES PLACE AVEC TOUTES LES SYMETRIES ##
|
|
if orientation == Transformation.Orientation.MY :
|
|
y += inst.getAbutmentBox().getHeight()
|
|
|
|
inst.setTransformation ( Transformation ( x, y, orientation ) )
|
|
inst.setPlacementStatus ( Instance.PlacementStatus.FIXED )
|
|
|
|
UpdateSession.close()
|
|
|
|
#########################################
|
|
def getStandardInstancesMasque ( cell ) :
|
|
'''This function creates the mask of the standard cells'''
|
|
|
|
global FREE, standard_instances_masque, nb_lignes, nb_colonnes, reference
|
|
|
|
# The two dimensions of the mask
|
|
nb_lignes = cell.getAbutmentBox().getHeight() / DbU_lambda(SLICE)
|
|
nb_colonnes = cell.getAbutmentBox().getWidth() / DbU_lambda(PITCH)
|
|
|
|
# Creation of a mask named standard_instances_masque
|
|
standard_instances_masque = []
|
|
standard_instances_masque = [[FREE for j in range(nb_colonnes)] for i in range(nb_lignes)]
|
|
|
|
# Cover of all the instances of this model and fill in of the mask
|
|
reference = getAllStandardInstances ( cell )
|
|
|
|
return reference
|
|
|
|
######################################
|
|
def getAllStandardInstances ( cell ) :
|
|
'''This function is used to get all the standard instances of a cell and to flatten all the standard cells'''
|
|
|
|
global reference
|
|
|
|
reference = []
|
|
|
|
for element in cell.getInstances():
|
|
# FOR EACH PLACED or FIXED instance of the cell, we call getStandardInstances method
|
|
if element.getPlacementStatus() != Instance.PlacementStatus.UNPLACED :
|
|
reference = getStandardInstances ( cell, element, element.getTransformation(), cell.getName() )
|
|
|
|
return reference
|
|
|
|
##########################################################
|
|
def getStandardInstances ( cell, inst, transformation, name_masterinst ) :
|
|
'''This function covers all the instances of the model ,
|
|
it is also used to get all the transformations of the placed instances
|
|
it fills the standard_instances masque and the standard_instances_list '''
|
|
|
|
global POWER, OCCUPIED
|
|
global standard_instances_masque, reference
|
|
|
|
# Si l'instance est PLACED ou FIXED
|
|
if inst.getPlacementStatus() != Instance.PlacementStatus.UNPLACED :
|
|
name = str ( inst.getMasterCell().getLibrary().getName() )
|
|
|
|
if inst.isLeaf() :
|
|
# new abutmentbox
|
|
newbox = transformation.getBox ( inst.getMasterCell().getAbutmentBox() )
|
|
|
|
Height = newbox.getHeight()
|
|
Width = newbox.getWidth()
|
|
Xmin = newbox.getXMin()
|
|
Ymin = newbox.getYMin()
|
|
|
|
orientation = transformation.getOrientation()
|
|
|
|
if reference == [] : reference[ 0:3 ] = [ Xmin, Ymin, orientation ]
|
|
|
|
# on ajoute l'inst a la liste standard_instances_list
|
|
standard_instances_list.append ( ( Ymin, orientation, inst, str(name_masterinst) ) ) # add a tuple
|
|
|
|
nb_slices = Height / DbU_lambda(SLICE)
|
|
nb_pitchs = Width / DbU_lambda(PITCH)
|
|
|
|
# on remplit le masque
|
|
for i in range ( nb_slices ) :
|
|
for j in range ( nb_pitchs ) :
|
|
# on marque les cellules en POWER ou OCCUPIED FIXME : pourquoi ?
|
|
if re.search ( "powmid_x0", str ( inst.getMasterCell().getName() ) ) :
|
|
standard_instances_masque [ Ymin / DbU_lambda(SLICE) + i ][ Xmin / DbU_lambda(PITCH) + j ] = POWER
|
|
else :
|
|
standard_instances_masque [ Ymin / DbU_lambda(SLICE) + i ][ Xmin / DbU_lambda(PITCH) + j ] = OCCUPIED
|
|
|
|
# Si la masterCell n'est pas terminale, on appelle la fonction recursivement sur ses instances
|
|
else :
|
|
for element in inst.getMasterCell().getInstances():
|
|
getStandardInstances ( cell, element, transformation.getTransformation(element.getTransformation()), inst.getName() )
|
|
|
|
return reference
|
|
|
|
##########
|
|
def verifyPlacement ( cell ) :
|
|
'''This function is used to check the placement of the standard cells'''
|
|
|
|
global standard_instances_list
|
|
|
|
# YMin of reference
|
|
YMin = standard_instances_list[0][0]
|
|
|
|
# orientation code of reference
|
|
orientation = standard_instances_list[0][1]
|
|
|
|
# cover all the other
|
|
for i in range ( 1, len ( standard_instances_list ) ) :
|
|
element = standard_instances_list[i]
|
|
element_YMin = element[0]
|
|
element_orientation = element[1]
|
|
|
|
distance = element_YMin - YMin
|
|
|
|
# Error : if the orientation is different from 0, 2, 4 ,6
|
|
#if not element_orientation in [0,2,4,6] :
|
|
if element_orientation in [1,3,5,7] :
|
|
err = "Placement of cells : please check your file of layout with DRUC."
|
|
# err += "Error Detail :" + "\n"
|
|
# err += " instance " + str(element[2].getName()) + " of model " + str(element[2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(element[2].getCell().getName()) + "\n"
|
|
# err += " incoherent with :" + "\n"
|
|
# err += " instance " + str(standard_instances_list[0][2].getName()) + "\n"
|
|
# err += " of model " + str(standard_instances_list[0][2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(standard_instances_list[0][2].getCell().getName()) + "\n"
|
|
# err += " reference ymin is " + str(YMin) + " orientation " + str(orientation) + "\n"
|
|
# err += " element ymin is", element[0], "orientation", element_orientation + "\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
if distance < 0 : distance = -distance
|
|
|
|
nb_case = distance / DbU_lambda ( 50 )
|
|
|
|
# odd number
|
|
if nb_case % 2 :
|
|
if ( element_orientation - orientation ) in [4,-4] :
|
|
err = "Placement of cells : please check your file of layout with DRUC\n"
|
|
# err += "Error Detail :" + "\n"
|
|
# err += " instance " + str(element[2].getName()) + " of model " + str(element[2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(element[2].getCell().getName()) + "\n"
|
|
# err += " incoherent with :" + "\n"
|
|
# err += " instance " + str(standard_instances_list[0][2].getName()) + "\n"
|
|
# err += " of model " + str(standard_instances_list[0][2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(standard_instances_list[0][2].getCell().getName()) + "\n"
|
|
# err += " reference ymin is " + str(YMin) + " orientation " + orientation + "\n"
|
|
# err += " element ymin is " + element[0] + " orientation " + element_orientation + "\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
# even number
|
|
else :
|
|
if ( element_orientation - orientation ) in [2,-2,6,-6] :
|
|
err = "Placement of cells : please check your file of layout with DRUC\n"
|
|
# err += "Error Detail :"
|
|
# err += " instance " + str(element[2].getName()) + " of model " + str(element[2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(element[2].getCell().getName()) + "\n"
|
|
# err += " incoherent with :" + "\n"
|
|
# err += " instance " + str(standard_instances_list[0][2].getName()) + "\n"
|
|
# err += " of model " + str(standard_instances_list[0][2].getMasterCell().getName()) + "\n"
|
|
# err += " in cell " + str(standard_instances_list[0][2].getCell().getName()) + "\n"
|
|
# err += " reference ymin is " + str(YMin) + " orientation " + orientation + "\n"
|
|
# err += " element ymin is " + element[0] + " orientation " + element_orientation + "\n"
|
|
raise ErrorMessage(2,err)
|
|
|
|
###################################
|
|
def temporarySave ( cell = None ) :
|
|
|
|
UpdateSession.open()
|
|
|
|
framework = CRL.AllianceFramework.get()
|
|
|
|
if cell == None :
|
|
for cell in framework.getLibrary(0).getCells():
|
|
if str ( cell.getName() ) != "__Scratch__" :
|
|
framework.saveCell ( cell, CRL.Catalog.State.Physical )
|
|
else :
|
|
framework.saveCell ( cell, CRL.Catalog.State.Physical )
|
|
|
|
UpdateSession.close()
|
|
|
|
###########################
|
|
def getVddVss ( cell, y ) :
|
|
'''This function returns a string 'vdd' or 'vss' according to the variance between y and the reference cell. y is in slices'''
|
|
|
|
global reference
|
|
|
|
if reference == [] : raise ErrorMessage(2,"getVddVss : Reference is not token.")
|
|
|
|
# in order to know if it is vdd or vss
|
|
distance = y - int ( DbU_getLambda ( reference[1] ) ) / 50
|
|
|
|
if distance < 0 : distance = -distance
|
|
|
|
orientation = reference[2]
|
|
|
|
if orientation in [0,4] :
|
|
if distance % 2 : return "vdd"
|
|
else : return "vss"
|
|
elif orientation in [2,6] :
|
|
if distance % 2 : return "vss"
|
|
else : return "vdd"
|
|
else :
|
|
raise ErrorMessage(2,"get_vdd_vss : Illegal orientation of reference %s.\n"%orientation)
|
|
|
|
###########################
|
|
def getPadHeight ( cell ) :
|
|
'''This function returns the pad height if there is at least one pad'''
|
|
|
|
padFound = 0
|
|
|
|
for instance in cell.getInstances():
|
|
if isPad ( instance ):
|
|
pad_height = instance.getMasterCell().getAbutmentBox().getHeight()
|
|
padFound = 1
|
|
break
|
|
|
|
if padFound : return pad_height
|
|
else : raise ErrorMessage(2,"getPadHeight : No pad found.")
|
|
|
|
###################
|
|
def isPad ( ins ) :
|
|
'''This function returns 1 if the instance is a pad'''
|
|
|
|
if re.search ( "p.*_px", str ( ins.getMasterCell().getName() ) ) \
|
|
or re.search ( "p.*_sp", str ( ins.getMasterCell().getName() ) ):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
################################
|
|
def isInternalPowerPad ( ins ) :
|
|
'''This function returns 1 if pad is an internal power pad'''
|
|
if re.search ( "pvddi", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
################################
|
|
def isExternalPowerPad ( ins ) :
|
|
'''This function returns 1 if pad is an external power pad'''
|
|
if re.search ( "pvdde", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
#################################
|
|
def isInternalGroundPad ( ins ) :
|
|
'''This function returns 1 if pad is an internal ground pad'''
|
|
if re.search ( "pvssi", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
#################################
|
|
def isExternalGroundPad ( ins ) :
|
|
'''This function returns 1 if pad is an external ground pad'''
|
|
if re.search ( "pvsse", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
################################
|
|
def isInternalClockPad ( ins ) :
|
|
'''This function returns 1 if pad is an internal clock pad'''
|
|
if re.search ( "pvssick_", str ( ins.getMasterCell().getName() ) ) \
|
|
or re.search ( "pvddick_", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
################################
|
|
def isExternalClockPad ( ins ) :
|
|
'''This function returns 1 if pad is an external clock pad'''
|
|
if re.search ( "pvsseck_", str ( ins.getMasterCell().getName() ) ) \
|
|
or re.search ( "pvddeck_", str ( ins.getMasterCell().getName() ) ) :
|
|
return 1
|
|
else:
|
|
return 0
|
|
|
|
#########################
|
|
def affichePad ( cell ) :
|
|
global pad_north, pad_south, pad_east, pad_west
|
|
|
|
print "Pads in the north are :"
|
|
for pad in pad_north : print cell.getInstance ( pad.getName() ).getMasterCell().getName()
|
|
|
|
print "Pads in the south are :"
|
|
for pad in pad_south : print cell.getInstance ( pad.getName() ).getMasterCell().getName()
|
|
|
|
print "Pads in the east are :"
|
|
for pad in pad_east : print cell.getInstance ( pad.getName() ).getMasterCell().getName()
|
|
|
|
print "Pads in the west are :"
|
|
for pad in pad_west : print cell.getInstance ( pad.getName() ).getMasterCell().getName()
|
|
|
|
############
|
|
def searchVddVss ( cell, *args ) :
|
|
'''This function searches plots providing vdd and vss, and returns four lists'''
|
|
|
|
global pad_north, pad_south, pad_east, pad_west
|
|
|
|
# MACRO pour les directions d'access des pins
|
|
UNDEFINED = 0
|
|
NORTH = 1
|
|
SOUTH = 2
|
|
EAST = 3
|
|
WEST = 4
|
|
|
|
pad_list = [pad_east, pad_west, pad_north, pad_south]
|
|
|
|
for i in range ( len ( args ) ) :
|
|
|
|
for ins in pad_list[i] :
|
|
model = ins.getMasterCell()
|
|
transformation = ins.getTransformation()
|
|
|
|
if isInternalPowerPad ( ins ) or isExternalPowerPad ( ins ) \
|
|
or isInternalGroundPad ( ins ) or isExternalGroundPad ( ins ) :
|
|
# on connecte les pins vddi
|
|
for element in model.getNet("vddi").getPins():
|
|
layer = element.getLayer()
|
|
|
|
X = transformation.getX ( element.getX(), element.getY() )
|
|
Y = transformation.getY ( element.getX(), element.getY() )
|
|
|
|
args[i].append ( dict ( [['N', "vdd"], ['L',layer], ['X',X], ['Y',Y], ['C',0]] ) )
|
|
|
|
# on connecte les pins vssi
|
|
for element in model.getNet("vssi").getPins():
|
|
layer = element.getLayer()
|
|
|
|
X = transformation.getX ( element.getX(), element.getY() )
|
|
Y = transformation.getY ( element.getX(), element.getY() )
|
|
|
|
args[i].append ( dict ( [['N', "vss"], ['L',layer], ['X',X], ['Y', Y],['C',0]] ) )
|
|
|
|
########################
|
|
def createGrid ( my_tuple ) :
|
|
|
|
global ck_contact_list
|
|
global _Xmin, _Ymin, _Xmax, _Ymax
|
|
|
|
net, cell = my_tuple
|
|
|
|
def FindNearestPosition ( pos, poslist ) :
|
|
bestDistance = pos - poslist[0]
|
|
bestPos = poslist[0]
|
|
|
|
for x in poslist[1:] :
|
|
distance = pos - x
|
|
if distance <= 0 :
|
|
distance *= -1
|
|
if bestDistance > distance : return x
|
|
else :
|
|
if bestDistance > distance :
|
|
bestPos = x
|
|
bestDistance = pos - bestPos
|
|
return bestPos
|
|
|
|
def CreateZ ( contact1, contact2 ) :
|
|
centerX = (contact1.getX() + contact2.getX() ) / 2
|
|
centerX = centerX - (centerX % DbU_lambda(5))
|
|
zContact1 = Contact.create ( net, via5, centerX, contact1.getY(), DbU_lambda(11), DbU_lambda(11) )
|
|
zContact2 = Contact.create ( net, via5, centerX, contact2.getY(), DbU_lambda(11), DbU_lambda(11) )
|
|
|
|
Horizontal.create ( contact1, zContact1, metal6, contact1.getY(), DbU_lambda(12) )
|
|
Vertical.create ( zContact1, zContact2, metal5, zContact1.getX(), DbU_lambda(12) )
|
|
Horizontal.create ( zContact2, contact2, metal6, zContact2.getY(), DbU_lambda(12) )
|
|
|
|
def CreateN ( contact1, contact2 ) :
|
|
centerY = ( contact1.getY() + contact2.getY() ) / 2
|
|
centerY = centerY - ( centerY % DbU_lambda(5) )
|
|
nContact1 = Contact.create ( net, via5, contact1.getX(), centerY, DbU_lambda(11), DbU_lambda(11) )
|
|
nContact2 = Contact.create ( net, via5, contact2.getX(), centerY, DbU_lambda(11), DbU_lambda(11) )
|
|
|
|
Vertical.create ( contact1, nContact1, metal5, contact1.getX(), DbU_lambda(12) )
|
|
Horizontal.create ( nContact1, nContact2, metal6, nContact1.getY(), DbU_lambda(12) )
|
|
Vertical.create ( nContact2, contact2, metal5, nContact2.getX(), DbU_lambda(12) )
|
|
|
|
def FindPositionForContact ( position, contactlist1, contactlist2 ) :
|
|
def PositionIsInTargetRange ( position, target ) :
|
|
return position >= ( target - DbU_lambda(10) ) and position <= ( target + DbU_lambda(10) )
|
|
|
|
if contactlist1 == [] and contactlist2 == [] : return position
|
|
|
|
if contactlist1 != [] and contactlist2 != [] :
|
|
nearest1 = FindNearestPosition ( position, contactlist1 )
|
|
nearest2 = FindNearestPosition ( position, contactlist2 )
|
|
|
|
if ( not PositionIsInTargetRange(position, nearest1) ) and ( not PositionIsInTargetRange(position, nearest2) ) : return position
|
|
|
|
if PositionIsInTargetRange ( position, nearest1 ) :
|
|
if nearest2 > nearest1 : return position + DbU_lambda(12)
|
|
else : return position - DbU_lambda(12)
|
|
|
|
if PositionIsInTargetRange ( position, nearest2 ) :
|
|
if nearest1 > nearest2 : return position + DbU_lambda(12)
|
|
else : return position - DbU_lambda(12)
|
|
|
|
if contactlist1 != [] : contactlist = contactlist1
|
|
else : contactlist = contactlist2
|
|
|
|
nearest = FindNearestPosition ( position, contactlist )
|
|
|
|
if PositionIsInTargetRange ( position, nearest ) :
|
|
if position > nearest : return position + DbU_lambda(12)
|
|
else : return position - DbU_lambda(12)
|
|
else :
|
|
return position
|
|
|
|
#_Xmin = None
|
|
#_Ymin = None
|
|
#_Xmax = None
|
|
#_Ymax = None
|
|
coreBox = cell.getInstance('core').getAbutmentBox()
|
|
#print coreBox
|
|
_Xmin = coreBox.getXMin()
|
|
_Ymin = coreBox.getYMin()
|
|
_Xmax = coreBox.getXMax()
|
|
_Ymax = coreBox.getYMax()
|
|
ck_contact_list = []
|
|
|
|
getNetInstances ( cell, net, Transformation ( 0, 0, Transformation.Orientation.ID ) )
|
|
|
|
db = DataBase.getDB()
|
|
via1 = db.getTechnology().getLayer ( "VIA12" )
|
|
via2 = db.getTechnology().getLayer ( "VIA23" )
|
|
via3 = db.getTechnology().getLayer ( "VIA34" )
|
|
via4 = db.getTechnology().getLayer ( "VIA45" )
|
|
via5 = db.getTechnology().getLayer ( "VIA56" )
|
|
metal5 = db.getTechnology().getLayer ( "METAL5" )
|
|
metal6 = db.getTechnology().getLayer ( "METAL6" )
|
|
|
|
gridBoundingBox = Box()
|
|
|
|
for contact in ck_contact_list : gridBoundingBox.merge ( contact[0], contact[1] )
|
|
|
|
#the Bounding Box is inflated in function of the VIA_5 rule
|
|
gridBoundingBox.inflate ( DbU_lambda(15) )
|
|
|
|
#Create the Bounding Box grid
|
|
NEContact = Contact.create ( net, via5, gridBoundingBox.getXMin(), gridBoundingBox.getYMax() , DbU_lambda(11), DbU_lambda(11) )
|
|
NWContact = Contact.create ( net, via5, gridBoundingBox.getXMax(), gridBoundingBox.getYMax() , DbU_lambda(11), DbU_lambda(11) )
|
|
SEContact = Contact.create ( net, via5, gridBoundingBox.getXMin(), gridBoundingBox.getYMin() , DbU_lambda(11), DbU_lambda(11) )
|
|
SWContact = Contact.create ( net, via5, gridBoundingBox.getXMax(), gridBoundingBox.getYMin() , DbU_lambda(11), DbU_lambda(11) )
|
|
northSegment = Segment ( NEContact, NWContact, metal6, DbU_lambda(12) )
|
|
southSegment = Segment ( SEContact, SWContact, metal6, DbU_lambda(12) )
|
|
eastSegment = Segment ( NEContact, SEContact, metal5, DbU_lambda(12) )
|
|
westSegment = Segment ( NWContact, SWContact, metal5, DbU_lambda(12) )
|
|
|
|
northContacts = []
|
|
southContacts = []
|
|
eastContacts = []
|
|
westContacts = []
|
|
|
|
#connect the pins to the grid
|
|
plugList = []
|
|
#Fill a list with the plugs ... we are going to modify the underlying collection ;)
|
|
for plug in net.getPlugs():
|
|
plugList.append ( plug )
|
|
|
|
for plug in plugList:
|
|
instance = plug.getInstance()
|
|
if isPad ( instance ) :
|
|
# Connect this plug to the grid ...
|
|
masterNet = plug.getMasterNet()
|
|
transformation = instance.getTransformation()
|
|
|
|
for comp in NetExternalComponents.get(masterNet):
|
|
x = transformation.getX ( comp.getX(), comp.getY() )
|
|
y = transformation.getY ( comp.getX(), comp.getY() )
|
|
#layer = element.getLayer ()
|
|
#if re.search ( "METAL2", str ( layer ) ) \
|
|
# and ( ( element.getY() - element.getHalfHeight() ) < pad_inst.getMasterCell().getAbutmentBox().getYMin() ) :
|
|
|
|
if x >= gridBoundingBox.getXMin() and x <= gridBoundingBox.getXMax() :
|
|
layer = metal5
|
|
if y < gridBoundingBox.getYMin() :
|
|
if x == gridBoundingBox.getXMin() :
|
|
gridContact = NWContact
|
|
elif x == gridBoundingBox.getXMax() :
|
|
gridContact = NEContact
|
|
else :
|
|
gridContact = Contact.create(southSegment, via5, x, 0, DbU_lambda(11), DbU_lambda(11))
|
|
southContacts.append(x)
|
|
|
|
elif y > gridBoundingBox.getYMax() :
|
|
if x == gridBoundingBox.getXMin() :
|
|
gridContact = SWContact
|
|
elif x == gridBoundingBox.getXMax() :
|
|
gridBoundingBox = SEContact
|
|
else :
|
|
gridContact = Contact.create(northSegment, via5, x, 0, DbU_lambda(11), DbU_lambda(11))
|
|
northContacts.append(x)
|
|
else :
|
|
raise ErrorMessage(2,"RouteCK : bad pad placement.")
|
|
|
|
elif y >= gridBoundingBox.getYMin() and y <= gridBoundingBox.getYMax() :
|
|
layer = metal6
|
|
if x < gridBoundingBox.getXMin() :
|
|
if y == gridBoundingBox.getYMin() :
|
|
gridContact = SWContact
|
|
elif y == gridBoundingBox.getYMax() :
|
|
gridContact = NWContact
|
|
else :
|
|
gridContact = Contact.create(eastSegment, via5, 0, y, DbU_lambda(11), DbU_lambda(11))
|
|
eastContacts.append(y)
|
|
elif x > gridBoundingBox.getXMax() :
|
|
if y == gridBoundingBox.getYMin() :
|
|
gridContact = SEContact
|
|
elif y == gridBoundingBox.getYMax() :
|
|
gridContact = SWContact
|
|
else :
|
|
gridContact = Contact.create(westSegment, via5, 0, y, DbU_lambda(11), DbU_lambda(11))
|
|
westContacts.append(y)
|
|
else :
|
|
raise ErrorMessage(2,"RouteCK : bad pad placement.")
|
|
|
|
else :
|
|
message = [ "pyRouteCk: The pads <%s> must be in direct regard of the clock grid" % str(instance.getName())
|
|
, "Clock grid is %s" % str(gridBoundingBox)
|
|
]
|
|
raise ErrorMessage(2,message)
|
|
|
|
compContact = Contact.create ( net, via5, x, y, DbU_lambda(11), DbU_lambda(11) )
|
|
|
|
Segment ( compContact, gridContact, layer , DbU_lambda(12) )
|
|
|
|
break # just one component ...
|
|
|
|
|
|
# create the internal grid 200x200
|
|
nbVTracks = gridBoundingBox.getWidth() / DbU_lambda(200)
|
|
widthVTracks = gridBoundingBox.getWidth() / nbVTracks
|
|
nbHTracks = gridBoundingBox.getHeight() / DbU_lambda(200)
|
|
heightHTracks = gridBoundingBox.getHeight() / nbHTracks
|
|
via12Side = DbU.fromLambda(1.0)
|
|
via23Side = DbU.fromLambda(1.0)
|
|
via34Side = DbU.fromLambda(1.0)
|
|
via45Side = DbU.fromLambda(1.0)
|
|
via56Side = DbU.fromLambda(1.0)
|
|
|
|
xList = []
|
|
yList = []
|
|
for i in range ( 1, nbVTracks ) :
|
|
x = gridBoundingBox.getXMin() + i * widthVTracks
|
|
x = x - (x % DbU_lambda(5))
|
|
x = FindPositionForContact(x, northContacts, southContacts)
|
|
|
|
contact1 = Contact.create ( southSegment, via5, x, 0, DbU_lambda(11), DbU_lambda(11))
|
|
contact2 = Contact.create ( northSegment, via5, x, 0, DbU_lambda(11), DbU_lambda(11))
|
|
|
|
Segment ( contact1, contact2, metal5, DbU_lambda(12) )
|
|
|
|
xList.append ( x )
|
|
|
|
for i in range ( 1, nbHTracks ) :
|
|
y = gridBoundingBox.getYMin() + i * heightHTracks
|
|
y = y - ( y % DbU_lambda(5) )
|
|
y = FindPositionForContact ( y, eastContacts, westContacts )
|
|
|
|
contact1 = Contact.create ( westSegment, via5, 0, y, DbU_lambda(11), DbU_lambda(11) )
|
|
contact2 = Contact.create ( eastSegment, via5, 0, y, DbU_lambda(11), DbU_lambda(11) )
|
|
|
|
horizontal = Segment ( contact1, contact2, metal6, DbU_lambda(12) )
|
|
|
|
yList.append ( y )
|
|
|
|
for x in xList : Contact.create ( horizontal, via5, x, 0, DbU_lambda(11), DbU_lambda(11) )
|
|
|
|
# Connection to the grid
|
|
# Cette liste contient les contacts qui sont deja crees
|
|
ck_contact_list_created = []
|
|
|
|
# Now connect all the internal contacts to the grid
|
|
for contact in ck_contact_list :
|
|
xContact = contact[0]
|
|
yContact = contact[1]
|
|
plugContact = Contact.create ( net, via1 , xContact, yContact, via12Side, via12Side )
|
|
#find the closest x,y on grid
|
|
xList.insert ( 0, gridBoundingBox.getXMin() )
|
|
yList.insert ( 0, gridBoundingBox.getYMin() )
|
|
xList.append ( gridBoundingBox.getXMax() )
|
|
yList.append ( gridBoundingBox.getYMax() )
|
|
|
|
xTarget = FindNearestPosition ( xContact, xList )
|
|
yTarget = FindNearestPosition ( yContact, yList )
|
|
|
|
xDistance = abs ( xTarget - xContact )
|
|
yDistance = abs ( yTarget - yContact )
|
|
|
|
Contact.create(net, via2, xContact, yContact, via23Side, via23Side )
|
|
Contact.create(net, via3, xContact, yContact, via34Side, via34Side )
|
|
Contact.create(net, via4, xContact, yContact, via45Side, via45Side )
|
|
|
|
if xDistance != 0 or yDistance != 0 :
|
|
if ( xDistance <= yDistance + DbU_lambda(10) ): # test pour faire un horizontal
|
|
if xDistance != 0 :
|
|
if abs(xDistance) <= DbU_lambda(3) :
|
|
gridContact = Contact.create ( net, metal5, xTarget, yContact, via56Side, via56Side )
|
|
layer = metal5
|
|
else :
|
|
Contact.create ( net, via5, xContact, yContact, via56Side, via56Side )
|
|
gridContact = Contact.create ( net, via5, xTarget, yContact, via56Side, via56Side )
|
|
layer = metal6
|
|
Horizontal.create( gridContact, plugContact, layer, gridContact.getY(), DbU_lambda(2) )
|
|
else :
|
|
gridContact = Contact.create ( net, via5, xTarget, yContact, via56Side, via56Side )
|
|
else:
|
|
if yDistance != 0 :
|
|
if abs(yDistance) <= DbU_lambda(3) :
|
|
layer = metal6
|
|
gridContact = Contact.create ( net, metal6, xContact, yTarget, via56Side, via56Side )
|
|
Contact.create ( net, via5, xContact, yContact, via56Side, via56Side )
|
|
else :
|
|
gridContact = Contact.create ( net, via5, xContact, yTarget, via56Side, via56Side )
|
|
layer = metal5
|
|
Vertical.create ( gridContact, plugContact, layer, gridContact.getX(), DbU_lambda(2) )
|
|
else :
|
|
gridContact = Contact.create ( net, via5, xContact, yTarget, via56Side, via56Side )
|
|
|
|
del _Xmin
|
|
del _Ymin
|
|
del _Xmax
|
|
del _Ymax
|
|
del ck_contact_list
|
|
|
|
############################################
|
|
def getNetInstances ( cell, net, transformation) :
|
|
'''This function is used to cover instances with standard model, which are connected to "net"
|
|
transformation is the transformation of the instance which model contains this net'''
|
|
|
|
global ck_contact_list_to_create, ck_contact_list
|
|
global _Xmin, _Ymin, _Xmax, _Ymax
|
|
|
|
for plug in net.getPlugs(): # parcourir les plugs de ce net
|
|
ins = plug.getInstance()
|
|
|
|
# Si c est une instance de type leaf
|
|
if ins.isLeaf() :
|
|
if ins.getPlacementStatus() == Instance.PlacementStatus.UNPLACED :
|
|
raise ErrorMessage(2,"getNetInstances : instance %s is unplaced" % str(ins.getName()))
|
|
else :
|
|
if not isPad ( ins ) :
|
|
# get transformation final de cette instance
|
|
ins_transformation = transformation.getTransformation ( ins.getTransformation() )
|
|
|
|
nbSeg = 0
|
|
for segment in plug.getMasterNet().getSegments():
|
|
layer = segment.getLayer()
|
|
if NetExternalComponents.isExternal(segment) \
|
|
and ( re.search ( "METAL1", layer.getName() ) \
|
|
or re.search ( "METAL2", layer.getName() ) ):
|
|
# avoir x ,y de contact a placer
|
|
_x = ins_transformation.getX ( segment.getSourceX(), segment.getSourceY() )
|
|
_y = ins_transformation.getY ( segment.getSourceX(), segment.getSourceY() )
|
|
|
|
#print ins, ":", segment, ",", nbSeg, ",", _x, ",", _y
|
|
nbSeg += 1
|
|
ck_contact_list_to_create.append ( (_x, _y) )
|
|
|
|
ck_contact_list.append ( (_x, _y) )
|
|
|
|
newbox = ins_transformation.getBox ( ins.getMasterCell().getAbutmentBox() ) # get new box
|
|
Height = newbox.getHeight()
|
|
Width = newbox.getWidth()
|
|
Xmin = newbox.getXMin()
|
|
Ymin = newbox.getYMin()
|
|
Xmax = newbox.getXMax()
|
|
Ymax = newbox.getYMax()
|
|
#print " placer contact in ", _x, " ", _y , " in the net ", plug.getMasterNet().getName() ,
|
|
#print " of instance ", plug.getInstance().getName() , " in ", Xmin , " ", Ymin ,
|
|
#print " of model ", plug.getInstance().getMasterCell().getName(), "\n"
|
|
|
|
# Positionner la grille
|
|
if ( Xmin < _Xmin ) or ( _Xmin == None ) : _Xmin = Xmin
|
|
if ( Ymin < _Ymin ) or ( _Ymin == None ) : _Ymin = Ymin
|
|
if ( Xmax > _Xmax ) or ( _Xmax == None ) : _Xmax = Xmax
|
|
if ( Ymax > _Ymax ) or ( _Ymax == None ) : _Ymax = Ymax
|
|
break
|
|
|
|
if not nbSeg :
|
|
raise ErrorMessage(2,"getNetInstances : net %s in model %s does not have a segment\n" % ( str ( plug.getMasterNet().getName()), str(ins.getMasterCell().getName()) ) )
|
|
|
|
if ( not ck_contact_list ) : print "Error in function getNetInstances : no segment found"
|
|
|
|
else :
|
|
if ins.getPlacementStatus() == Instance.PlacementStatus.UNPLACED :
|
|
raise ErrorMessage(2,"getNetInstances : instance %s is unplaced" % str(ins.getName()))
|
|
else :
|
|
getNetInstances ( cell, plug.getMasterNet(), transformation.getTransformation ( ins.getTransformation () ))
|
|
|
|
############################
|
|
def getNonCLayer ( layer ) :
|
|
'''This function returns the nonC layer corresponding to the one given as argument'''
|
|
|
|
metal1 = DataBase.getDB ().getTechnology ().getLayer ( "METAL1" )
|
|
metal2 = DataBase.getDB ().getTechnology ().getLayer ( "METAL2" )
|
|
metal3 = DataBase.getDB ().getTechnology ().getLayer ( "METAL3" )
|
|
metal4 = DataBase.getDB ().getTechnology ().getLayer ( "METAL4" )
|
|
metal5 = DataBase.getDB ().getTechnology ().getLayer ( "METAL5" )
|
|
metal6 = DataBase.getDB ().getTechnology ().getLayer ( "METAL6" )
|
|
|
|
if re.search ( "CMETAL1", str ( layer.getName() ) ) : return metal1
|
|
if re.search ( "CMETAL2", str ( layer.getName() ) ) : return metal2
|
|
if re.search ( "CMETAL3", str ( layer.getName() ) ) : return metal3
|
|
if re.search ( "CMETAL4", str ( layer.getName() ) ) : return metal4
|
|
if re.search ( "CMETAL5", str ( layer.getName() ) ) : return metal5
|
|
if re.search ( "CMETAL6", str ( layer.getName() ) ) : return metal6
|
|
|
|
return layer
|
|
|
|
######################################################
|
|
def Segment ( component1, component2, layer, width ) :
|
|
'''This function creates a segment linking component1 and component2'''
|
|
|
|
if component1.getX() == component2.getX() : return Vertical.create ( component1, component2, layer, component1.getX(), width )
|
|
elif component1.getY() == component2.getY() : return Horizontal.create ( component1, component2, layer, component1.getY(), width )
|
|
else:
|
|
raise ErrorMessage(2,"Segment : the components must be horizontaly or verticaly aligned.")
|