mirror of https://github.com/VLSIDA/OpenRAM.git
Fix unit during gds read. Fix blockage and pin rounding bugs.
This commit is contained in:
parent
614ff23e3a
commit
aa950c3b21
|
|
@ -678,7 +678,6 @@ class VlsiLayout:
|
|||
|
||||
pin_boundary=self.readPinInStructureList(label_coordinate, label_layer)
|
||||
debug.info(debug_level, "Find pin covers "+str(label_name)+" at "+str(pin_boundary))
|
||||
|
||||
pin_boundary=[pin_boundary[0]*self.units[0],pin_boundary[1]*self.units[0],
|
||||
pin_boundary[2]*self.units[0],pin_boundary[3]*self.units[0]]
|
||||
return [label_name, label_layer, pin_boundary]
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ class layout:
|
|||
if gds_file == None:
|
||||
gds_file = self.gds_file
|
||||
debug.info(3, "Printing %s" % gds_file)
|
||||
arrayCellLayout = gdsMill.VlsiLayout()
|
||||
arrayCellLayout = gdsMill.VlsiLayout(units=GDS["unit"])
|
||||
reader = gdsMill.Gds2reader(arrayCellLayout, debugToTerminal=1)
|
||||
reader.loadFromFile(gds_file)
|
||||
|
||||
|
|
|
|||
|
|
@ -6,26 +6,41 @@ class cell:
|
|||
visited, etc.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.visited = False
|
||||
self.path = False
|
||||
|
||||
self.blocked = False
|
||||
|
||||
self.source = False
|
||||
self.target = False
|
||||
|
||||
|
||||
def get_color(self):
|
||||
|
||||
r=g=b=0
|
||||
count=0
|
||||
# Blues are horizontal
|
||||
if self.blocked:
|
||||
return ImageColor.getrgb("Green")
|
||||
# Reds are source/sink
|
||||
if self.source or self.target:
|
||||
return ImageColor.getrgb("Red")
|
||||
[r1,g1,b1] = ImageColor.getrgb("Green")
|
||||
r+=r1
|
||||
g+=g1
|
||||
b+=b1
|
||||
count+=1
|
||||
|
||||
if self.source or self.target:
|
||||
[r1,g1,b1] = ImageColor.getrgb("Red")
|
||||
r+=r1
|
||||
g+=g1
|
||||
b+=b1
|
||||
count+=1
|
||||
|
||||
if self.path:
|
||||
return ImageColor.getrgb("Blue")
|
||||
[r1,g1,b1] = ImageColor.getrgb("Blue")
|
||||
r+=r1
|
||||
g+=g1
|
||||
b+=b1
|
||||
count+=1
|
||||
|
||||
return [255,255,255]
|
||||
if count>0:
|
||||
return [int(r/count),int(g/count),int(b/count)]
|
||||
else:
|
||||
return [255,255,255]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ class grid:
|
|||
|
||||
|
||||
|
||||
def view(self,):
|
||||
def view(self):
|
||||
"""
|
||||
View the data by creating an RGB array and mapping the data
|
||||
structure to the RGB color palette.
|
||||
"""
|
||||
|
||||
v_map = np.zeros((self.width,self.height,3), 'uint8')
|
||||
mid_map = np.ones((25,self.height,3), 'uint8')
|
||||
mid_map = np.ones((25,self.height,3), 'uint8')
|
||||
h_map = np.ones((self.width,self.height,3), 'uint8')
|
||||
|
||||
# We shouldn't have a path greater than 50% the HPWL
|
||||
|
|
@ -50,11 +50,17 @@ class grid:
|
|||
for y in range(self.height):
|
||||
h_map[x,y] = self.map[vector3d(x,y,0)].get_color()
|
||||
v_map[x,y] = self.map[vector3d(x,y,1)].get_color()
|
||||
# This is just for scale
|
||||
if x==0 and y==0:
|
||||
h_map[x,y] = [0,0,0]
|
||||
v_map[x,y] = [0,0,0]
|
||||
|
||||
v_img = Image.fromarray(v_map, 'RGB').rotate(90)
|
||||
mid_img = Image.fromarray(mid_map, 'RGB').rotate(90)
|
||||
#v_img.show()
|
||||
mid_img = Image.fromarray(mid_map, 'RGB').rotate(90)
|
||||
h_img = Image.fromarray(h_map, 'RGB').rotate(90)
|
||||
|
||||
#h_img.show()
|
||||
|
||||
# concatenate them into a plot with the two layers
|
||||
img = Image.new('RGB', (2*self.width+25, self.height))
|
||||
img.paste(h_img, (0,0))
|
||||
|
|
@ -64,13 +70,19 @@ class grid:
|
|||
img.save("test.png")
|
||||
|
||||
def set_property(self,ll,ur,z,name,value=True):
|
||||
for x in range(int(ll[0]),int(ur[0])):
|
||||
for y in range(int(ll[1]),int(ur[1])):
|
||||
assert(ur[1] >= ll[1] and ur[0] >= ll[0])
|
||||
assert(ll[0]<self.width and ll[0]>=0)
|
||||
assert(ll[1]<self.height and ll[1]>=0)
|
||||
assert(ur[0]<self.width and ur[0]>=0)
|
||||
assert(ur[1]<self.height and ur[1]>=0)
|
||||
for x in range(int(ll[0]),int(ur[0])+1):
|
||||
for y in range(int(ll[1]),int(ur[1])+1):
|
||||
debug.info(3," Adding {3} x={0} y={1} z={2}".format(str(ll),str(ur),z,name))
|
||||
setattr (self.map[vector3d(x,y,z)], name, True)
|
||||
getattr (self, name).append(vector3d(x,y,z))
|
||||
|
||||
def add_blockage(self,ll,ur,z):
|
||||
debug.info(1,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
||||
debug.info(2,"Adding blockage ll={0} ur={1} z={2}".format(str(ll),str(ur),z))
|
||||
self.set_property(ll,ur,z,"blocked")
|
||||
|
||||
def set_source(self,ll,ur,z):
|
||||
|
|
@ -106,14 +118,17 @@ class grid:
|
|||
# Keep expanding and adding to the priority queue until we are done
|
||||
while not self.q.empty():
|
||||
(cost,path) = self.q.get()
|
||||
debug.info(2,"Expanding: cost=" + str(cost) + " " + str(path))
|
||||
debug.info(2,"Expanding: cost=" + str(cost))
|
||||
debug.info(3,str(path))
|
||||
|
||||
# expand the last element
|
||||
neighbors = self.expand_dirs(path[-1])
|
||||
neighbors = self.expand_dirs(path)
|
||||
debug.info(2,"Neighbors: " + str(neighbors))
|
||||
|
||||
for n in neighbors:
|
||||
newpath = path + [n]
|
||||
self.map[n].visited=True
|
||||
|
||||
# check if we hit the target and are done
|
||||
if self.is_target(n):
|
||||
return newpath
|
||||
|
|
@ -122,6 +137,7 @@ class grid:
|
|||
cost = len(newpath) + self.cost_to_target(n)
|
||||
self.q.put((cost,newpath))
|
||||
|
||||
self.view()
|
||||
debug.error("Unable to route path. Expand area?",-1)
|
||||
|
||||
def is_target(self,point):
|
||||
|
|
@ -130,34 +146,37 @@ class grid:
|
|||
"""
|
||||
return point in self.target
|
||||
|
||||
def expand_dirs(self,point):
|
||||
def expand_dirs(self,path):
|
||||
"""
|
||||
Expand each of the four cardinal directions plus up or down
|
||||
but not expanding to blocked cells. Always follow horizontal/vertical
|
||||
routing layer requirements. Extend in the future if not routable?
|
||||
"""
|
||||
# expand from the last point
|
||||
point = path[-1]
|
||||
neighbors = []
|
||||
# check z layer for enforced direction routing
|
||||
if point.z==0:
|
||||
east = point + vector3d(1,0,0)
|
||||
west= point + vector3d(-11,0,0)
|
||||
if east.x<self.width and not self.map[east].blocked:
|
||||
if east.x<self.width and not self.map[east].blocked and not self.map[east].visited:
|
||||
neighbors.append(east)
|
||||
if west.x>=0 and not self.map[west].blocked:
|
||||
if west.x>=0 and not self.map[west].blocked and not self.map[west].visited:
|
||||
neighbors.append(west)
|
||||
|
||||
up = point + vector3d(0,0,1)
|
||||
if not self.map[up].blocked:
|
||||
if not self.map[up].blocked and not self.map[up].visited:
|
||||
neighbors.append(up)
|
||||
elif point.z==1:
|
||||
north = point + vector3d(0,1,0)
|
||||
south = point + vector3d(0,-1,0)
|
||||
if north.y<self.height and not self.map[north].blocked:
|
||||
if north.y<self.height and not self.map[north].blocked and not self.map[north].visited:
|
||||
neighbors.append(north)
|
||||
if south.y>=0 and not self.map[south].blocked:
|
||||
if south.y>=0 and not self.map[south].blocked and not self.map[south].visited:
|
||||
neighbors.append(south)
|
||||
|
||||
down = point + vector3d(0,0,-1)
|
||||
if not self.map[down].blocked:
|
||||
if not self.map[down].blocked and not self.map[down].visited:
|
||||
neighbors.append(down)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,34 +20,21 @@ class router:
|
|||
|
||||
"""
|
||||
self.gds_name = gds_name
|
||||
self.layout = gdsMill.VlsiLayout()
|
||||
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
|
||||
self.reader = gdsMill.Gds2reader(self.layout)
|
||||
self.reader.loadFromFile(gds_name)
|
||||
self.top_name = self.layout.rootStructureName
|
||||
self.unit = float(self.layout.info['units'][0])
|
||||
print "Units:",self.unit
|
||||
|
||||
self.pin_names = []
|
||||
self.pin_shapes = {}
|
||||
self.pin_layers = {}
|
||||
|
||||
self.boundary = self.layout.measureBoundary(self.top_name)
|
||||
#print "Boundary: ",self.boundary
|
||||
self.ll = vector(self.boundary[0])
|
||||
self.ur = vector(self.boundary[1])
|
||||
self.size = self.ur - self.ll
|
||||
self.width = self.size.x
|
||||
self.height = self.size.y
|
||||
|
||||
print "Boundary: ",self.boundary
|
||||
print "Size: ", self.width,self.height
|
||||
|
||||
# to scale coordinates by units
|
||||
self.unit_factor = [self.unit] * 2
|
||||
|
||||
# We will offset so ll is at (0,0)
|
||||
self.offset = self.ll
|
||||
print "Offset: ",self.offset
|
||||
|
||||
|
||||
|
||||
def set_top(self,top_name):
|
||||
""" If we want to route something besides the top-level cell."""
|
||||
|
|
@ -82,9 +69,20 @@ class router:
|
|||
|
||||
def create_routing_grid(self):
|
||||
""" Create a routing grid that spans given area. Wires cannot exist outside region. """
|
||||
# We will add a halo around the boundary
|
||||
# of this many tracks
|
||||
track_halo = 2
|
||||
# We will offset so ll is at (-track_halo*track_width,-track_halo*track_width)
|
||||
track_width_offset = vector([track_halo*self.track_width]*2)
|
||||
self.offset = self.ll - track_width_offset
|
||||
print "Offset: ",self.offset
|
||||
width = self.size.x
|
||||
height = self.size.y
|
||||
print "Size: ", width,height
|
||||
|
||||
self.width_in_tracks = int(math.ceil(self.width/self.track_width))
|
||||
self.height_in_tracks = int(math.ceil(self.height/self.track_width))
|
||||
# pad the tracks on each side by the halo as well
|
||||
self.width_in_tracks = int(math.ceil(width/self.track_width)) + 2*track_halo
|
||||
self.height_in_tracks = int(math.ceil(height/self.track_width)) + 2*track_halo
|
||||
|
||||
print "Size (in tracks): ", self.width_in_tracks, self.height_in_tracks
|
||||
|
||||
|
|
@ -94,8 +92,12 @@ class router:
|
|||
def find_pin(self,pin):
|
||||
""" Finds the offsets to the gds pins """
|
||||
(pin_name,pin_layer,pin_shape) = self.layout.readPin(str(pin))
|
||||
debug.info(3,"Find pin {0} layer {1} shape {2}".format(pin_name,str(pin_layer),str(pin_shape)))
|
||||
# repack the shape as a pair of vectors rather than four values
|
||||
new_shape = self.convert_to_tracks([vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])])
|
||||
shape=[vector(pin_shape[0],pin_shape[1]),vector(pin_shape[2],pin_shape[3])]
|
||||
print shape
|
||||
new_shape = self.convert_to_tracks(shape,round_bigger=False)
|
||||
print new_shape
|
||||
self.pin_names.append(pin_name)
|
||||
self.pin_shapes[str(pin)] = new_shape
|
||||
self.pin_layers[str(pin)] = pin_layer
|
||||
|
|
@ -109,10 +111,16 @@ class router:
|
|||
self.write_obstacle(self.top_name)
|
||||
|
||||
|
||||
def route(self):
|
||||
def route(self,layers,src, dest):
|
||||
self.set_layers(layers)
|
||||
self.create_routing_grid()
|
||||
self.set_source(src)
|
||||
self.set_target(dest)
|
||||
self.find_blockages()
|
||||
path = self.rg.route()
|
||||
debug.info(0,"Found path: " + str(path))
|
||||
self.rg.set_path(path)
|
||||
debug.info(0,"Found path. ")
|
||||
debug.info(2,str(path))
|
||||
return path
|
||||
|
||||
def add_route(self,start, end, layerstack):
|
||||
""" Add a wire route from the start to the end point"""
|
||||
|
|
@ -136,13 +144,21 @@ class router:
|
|||
coordinate += [(x, y)]
|
||||
return coordinate
|
||||
|
||||
def min_max_coord(self, coordTrans):
|
||||
def convert_shape_to_units(self, shape):
|
||||
""" Scale a shape (two vector list) to user units """
|
||||
unit_factor = [tech.GDS["unit"][0]] * 2
|
||||
ll=shape[0].scale(unit_factor)
|
||||
ur=shape[1].scale(unit_factor)
|
||||
return [ll,ur]
|
||||
|
||||
|
||||
def min_max_coord(self, coord):
|
||||
"""Find the lowest and highest corner of a Rectangle"""
|
||||
coordinate = []
|
||||
minx = min(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
maxx = max(coordTrans[0][0], coordTrans[1][0], coordTrans[2][0], coordTrans[3][0])
|
||||
miny = min(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
maxy = max(coordTrans[0][1], coordTrans[1][1], coordTrans[2][1], coordTrans[3][1])
|
||||
minx = min(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
|
||||
maxx = max(coord[0][0], coord[1][0], coord[2][0], coord[3][0])
|
||||
miny = min(coord[0][1], coord[1][1], coord[2][1], coord[3][1])
|
||||
maxy = max(coord[0][1], coord[1][1], coord[2][1], coord[3][1])
|
||||
coordinate += [vector(minx, miny)]
|
||||
coordinate += [vector(maxx, maxy)]
|
||||
return coordinate
|
||||
|
|
@ -150,49 +166,45 @@ class router:
|
|||
def set_source(self,name):
|
||||
shape = self.find_pin(name)
|
||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||
debug.info(0,"Set source: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
debug.info(1,"Set source: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
self.rg.set_source(shape[0],shape[1],zindex)
|
||||
|
||||
|
||||
def set_target(self,name):
|
||||
shape = self.find_pin(name)
|
||||
zindex = 0 if self.pin_layers[name]==self.horiz_layer_number else 1
|
||||
debug.info(0,"Set target: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
debug.info(1,"Set target: " + str(name) + " " + str(shape) + " z=" + str(zindex))
|
||||
self.rg.set_target(shape[0],shape[1],zindex)
|
||||
|
||||
def write_obstacle(self, sref, mirr = 1, angle = math.radians(float(0)), xyShift = (0, 0)):
|
||||
"""Recursive write boundaries on each Structure in GDS file to LEF"""
|
||||
|
||||
for boundary in self.layout.structures[sref].boundaries:
|
||||
coordTrans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
|
||||
shape = self.min_max_coord(coordTrans)
|
||||
coord_trans = self.translate_coordinates(boundary.coordinates, mirr, angle, xyShift)
|
||||
shape_coords = self.min_max_coord(coord_trans)
|
||||
shape = self.convert_shape_to_units(shape_coords)
|
||||
|
||||
if boundary.drawingLayer in [self.vert_layer_number,self.horiz_layer_number]:
|
||||
ll_microns=shape[0].scale(self.unit_factor)
|
||||
ur_microns=shape[1].scale(self.unit_factor)
|
||||
|
||||
shape_tracks=self.convert_to_tracks([ll_microns,ur_microns])
|
||||
# We round the pins down, so we must do this to skip them
|
||||
pin_shape_tracks=self.convert_to_tracks(shape,round_bigger=False)
|
||||
|
||||
# don't add a blockage if this shape was a pin shape
|
||||
if shape_tracks not in self.pin_shapes.values():
|
||||
if pin_shape_tracks not in self.pin_shapes.values():
|
||||
# inflate the ll and ur by 1 track in each direction
|
||||
[ll,ur]=shape_tracks
|
||||
ll = vector(0,0).max(ll + vector(-1,-1))
|
||||
ur = vector(self.width_in_tracks-1,self.height_in_tracks-1).min(ur + vector(1,1))
|
||||
[ll,ur]=self.convert_to_tracks(shape)
|
||||
zlayer = 0 if boundary.drawingLayer==self.horiz_layer_number else 1
|
||||
debug.info(1,"Blockage: "+str([ll,ur])+" z="+str(zlayer))
|
||||
self.rg.add_blockage(ll,ur,zlayer)
|
||||
else:
|
||||
debug.info(2,"Skip: "+str(shape_tracks))
|
||||
debug.info(2,"Skip: "+str(pin_shape_tracks))
|
||||
|
||||
|
||||
# recurse given the mirror, angle, etc.
|
||||
for cur_sref in self.layout.structures[sref].srefs:
|
||||
sMirr = 1
|
||||
if sref.transFlags[0] == True:
|
||||
if cur_sref.transFlags[0] == True:
|
||||
sMirr = -1
|
||||
sAngle = math.radians(float(0))
|
||||
if sref.rotateAngle:
|
||||
if cur_sref.rotateAngle:
|
||||
sAngle = math.radians(float(cur_sref.rotateAngle))
|
||||
sAngle += angle
|
||||
x = cur_sref.coordinates[0]
|
||||
|
|
@ -201,23 +213,27 @@ class router:
|
|||
newY = (x)*math.sin(angle) + mirr*(y)*math.cos(angle) + xyShift[1]
|
||||
sxyShift = (newX, newY)
|
||||
|
||||
self.write_obstacle(cur_sref.sName, layer,sMirr, sAngle, sxyShift)
|
||||
self.write_obstacle(cur_sref.sName, sMirr, sAngle, sxyShift)
|
||||
|
||||
def convert_to_tracks(self,shape):
|
||||
def convert_to_tracks(self,shape,round_bigger=True):
|
||||
"""
|
||||
Convert a rectangular shape into track units.
|
||||
"""
|
||||
[ll,ur] = shape
|
||||
|
||||
# offset lowest corner object to to (0,0)
|
||||
# offset lowest corner object to to (-track halo,-track halo)
|
||||
ll = snap_to_grid(ll-self.offset)
|
||||
ur = snap_to_grid(ur-self.offset)
|
||||
|
||||
# always round down, because we will add a track
|
||||
# to inflate each obstacle object later.
|
||||
# whereas pins should be conservative
|
||||
ll = ll.scale(self.track_factor).ceil()
|
||||
ur = ur.scale(self.track_factor).floor()
|
||||
# Always round blockage shapes up.
|
||||
if round_bigger:
|
||||
ll = ll.scale(self.track_factor).floor()
|
||||
ur = ur.scale(self.track_factor).ceil()
|
||||
# Always round pin shapes down
|
||||
else:
|
||||
ll = ll.scale(self.track_factor).round()
|
||||
ur = ur.scale(self.track_factor).round()
|
||||
|
||||
|
||||
return [ll,ur]
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ sys.path.append(os.path.join(sys.path[0],".."))
|
|||
import globals
|
||||
import debug
|
||||
import calibre
|
||||
import vector
|
||||
|
||||
class no_blockages_test(unittest.TestCase):
|
||||
|
||||
|
|
@ -17,18 +16,24 @@ class no_blockages_test(unittest.TestCase):
|
|||
globals.init_openram("config_{0}".format(OPTS.tech_name))
|
||||
|
||||
import router
|
||||
import wire
|
||||
import tech
|
||||
#r=router.router("A_to_B_no_blockages.gds")
|
||||
r=router.router("A_to_B_m1m2_blockages.gds")
|
||||
#r=router.router("A_to_B_m1m2_blockages.gds")
|
||||
#r=router.router("A_to_B_m1m2_same_layer_pins.gds")
|
||||
r=router.router("A_to_B_m1m2_diff_layer_pins.gds")
|
||||
layer_stack =("metal1","via1","metal2")
|
||||
path=r.route(layer_stack,src="A",dest="B")
|
||||
|
||||
r.set_layers(("metal1","via1","metal2"))
|
||||
|
||||
r.create_routing_grid()
|
||||
r.set_source("A")
|
||||
r.set_target("B")
|
||||
r.find_blockages()
|
||||
r.route()
|
||||
# For debug, to view the result as an image
|
||||
r.rg.set_path(path)
|
||||
r.rg.view()
|
||||
|
||||
OPTS.check_lvsdrc = False
|
||||
|
||||
#w = wire.wire(layer_stack, path)
|
||||
OPTS.check_lvsdrc = True
|
||||
#self.local_check(w)
|
||||
|
||||
#drc_errors = calibre.run_drc(name, gds_name)
|
||||
drc_errors = 1
|
||||
|
||||
|
|
@ -39,6 +44,11 @@ class no_blockages_test(unittest.TestCase):
|
|||
|
||||
|
||||
|
||||
def local_check(self, w):
|
||||
tempgds = OPTS.openram_temp + "temp.gds"
|
||||
w.gds_write(tempgds)
|
||||
self.assertFalse(calibre.run_drc(w.name, tempgds))
|
||||
os.remove(tempgds)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -21,12 +21,19 @@ def snap_to_grid(offset):
|
|||
return out_offset
|
||||
|
||||
|
||||
def gdsPinToOffset(gdsPin):
|
||||
def gds_pin_center(gdsPin):
|
||||
"""
|
||||
This returns the center of a pin shape
|
||||
"""
|
||||
boundary = gdsPin[2]
|
||||
return [0.5 * (boundary[0] + boundary[2]), 0.5 * (boundary[1] + boundary[3])]
|
||||
|
||||
|
||||
def auto_measure_libcell(pin_list, name, units, layer):
|
||||
"""
|
||||
Open a GDS file and find the pins in pin_list as text on a given layer.
|
||||
Return these as a set of properties including the cell width/height too.
|
||||
"""
|
||||
cell_gds = OPTS.openram_tech + "gds_lib/" + str(name) + ".gds"
|
||||
cell_vlsi = gdsMill.VlsiLayout(units=units)
|
||||
reader = gdsMill.Gds2reader(cell_vlsi)
|
||||
|
|
@ -39,7 +46,7 @@ def auto_measure_libcell(pin_list, name, units, layer):
|
|||
[cell["width"], cell["height"]] = measure_result
|
||||
|
||||
for pin in pin_list:
|
||||
cell[str(pin)] = gdsPinToOffset(cell_vlsi.readPin(str(pin)))
|
||||
cell[str(pin)] = gds_pin_center(cell_vlsi.readPin(str(pin)))
|
||||
return cell
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ class vector():
|
|||
|
||||
def __str__(self):
|
||||
""" override print function output """
|
||||
return "vector:["+str(self.x)+", "+str(self.y)+"]"
|
||||
return "["+str(self.x)+","+str(self.y)+"]"
|
||||
|
||||
def __repr__(self):
|
||||
""" override print function output """
|
||||
return "["+str(self.x)+", "+str(self.y)+"]"
|
||||
return "["+str(self.x)+","+str(self.y)+"]"
|
||||
|
||||
def __setitem__(self, index, value):
|
||||
"""
|
||||
|
|
@ -113,6 +113,13 @@ class vector():
|
|||
"""
|
||||
return vector(int(math.ceil(self.x)),int(math.ceil(self.y)))
|
||||
|
||||
def round(self):
|
||||
"""
|
||||
Override round function
|
||||
"""
|
||||
return vector(int(round(self.x)),int(round(self.y)))
|
||||
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Override the default Equals behavior"""
|
||||
if isinstance(other, self.__class__):
|
||||
|
|
|
|||
Loading…
Reference in New Issue