mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 's8_update' into dev
Add lpp to addText(), remove reference to specific technology in gdsMill
This commit is contained in:
commit
4c9b3c5864
|
|
@ -51,7 +51,7 @@ class geometry:
|
||||||
y = item[0] * math.sin(angle) + item[1] * mirr * math.cos(angle) + offset[1]
|
y = item[0] * math.sin(angle) + item[1] * mirr * math.cos(angle) + offset[1]
|
||||||
coordinate += [[x, y]]
|
coordinate += [[x, y]]
|
||||||
return coordinate
|
return coordinate
|
||||||
|
|
||||||
def normalize(self):
|
def normalize(self):
|
||||||
""" Re-find the LL and UR points after a transform """
|
""" Re-find the LL and UR points after a transform """
|
||||||
(first, second) = self.boundary
|
(first, second) = self.boundary
|
||||||
|
|
@ -64,14 +64,14 @@ class geometry:
|
||||||
def update_boundary(self):
|
def update_boundary(self):
|
||||||
""" Update the boundary with a new placement. """
|
""" Update the boundary with a new placement. """
|
||||||
self.compute_boundary(self.offset, self.mirror, self.rotate)
|
self.compute_boundary(self.offset, self.mirror, self.rotate)
|
||||||
|
|
||||||
def compute_boundary(self, offset=vector(0, 0), mirror="", rotate=0):
|
def compute_boundary(self, offset=vector(0, 0), mirror="", rotate=0):
|
||||||
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
""" Transform with offset, mirror and rotation to get the absolute pin location.
|
||||||
We must then re-find the ll and ur. The master is the cell instance. """
|
We must then re-find the ll and ur. The master is the cell instance. """
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
self.boundary = [vector(0,0), vector(0,0)]
|
self.boundary = [vector(0,0), vector(0,0)]
|
||||||
return
|
return
|
||||||
|
|
||||||
(ll, ur) = [vector(0, 0), vector(self.width, self.height)]
|
(ll, ur) = [vector(0, 0), vector(self.width, self.height)]
|
||||||
|
|
||||||
if mirror == "MX":
|
if mirror == "MX":
|
||||||
|
|
@ -83,7 +83,7 @@ class geometry:
|
||||||
elif mirror == "XY":
|
elif mirror == "XY":
|
||||||
ll = ll.scale(-1, -1)
|
ll = ll.scale(-1, -1)
|
||||||
ur = ur.scale(-1, -1)
|
ur = ur.scale(-1, -1)
|
||||||
|
|
||||||
if rotate == 90:
|
if rotate == 90:
|
||||||
ll = ll.rotate_scale(-1, 1)
|
ll = ll.rotate_scale(-1, 1)
|
||||||
ur = ur.rotate_scale(-1, 1)
|
ur = ur.rotate_scale(-1, 1)
|
||||||
|
|
@ -96,19 +96,19 @@ class geometry:
|
||||||
|
|
||||||
self.boundary = [offset + ll, offset + ur]
|
self.boundary = [offset + ll, offset + ur]
|
||||||
self.normalize()
|
self.normalize()
|
||||||
|
|
||||||
def ll(self):
|
def ll(self):
|
||||||
""" Return the lower left corner """
|
""" Return the lower left corner """
|
||||||
return self.boundary[0]
|
return self.boundary[0]
|
||||||
|
|
||||||
def ur(self):
|
def ur(self):
|
||||||
""" Return the upper right corner """
|
""" Return the upper right corner """
|
||||||
return self.boundary[1]
|
return self.boundary[1]
|
||||||
|
|
||||||
def lr(self):
|
def lr(self):
|
||||||
""" Return the lower right corner """
|
""" Return the lower right corner """
|
||||||
return vector(self.boundary[1].x, self.boundary[0].y)
|
return vector(self.boundary[1].x, self.boundary[0].y)
|
||||||
|
|
||||||
def ul(self):
|
def ul(self):
|
||||||
""" Return the upper left corner """
|
""" Return the upper left corner """
|
||||||
return vector(self.boundary[0].x, self.boundary[1].y)
|
return vector(self.boundary[0].x, self.boundary[1].y)
|
||||||
|
|
@ -132,12 +132,12 @@ class geometry:
|
||||||
def cx(self):
|
def cx(self):
|
||||||
""" Return the center x """
|
""" Return the center x """
|
||||||
return 0.5 * (self.boundary[0].x + self.boundary[1].x)
|
return 0.5 * (self.boundary[0].x + self.boundary[1].x)
|
||||||
|
|
||||||
def cy(self):
|
def cy(self):
|
||||||
""" Return the center y """
|
""" Return the center y """
|
||||||
return 0.5 * (self.boundary[0].y + self.boundary[1].y)
|
return 0.5 * (self.boundary[0].y + self.boundary[1].y)
|
||||||
|
|
||||||
|
|
||||||
class instance(geometry):
|
class instance(geometry):
|
||||||
"""
|
"""
|
||||||
An instance of an instance/module with a specified location and
|
An instance of an instance/module with a specified location and
|
||||||
|
|
@ -148,7 +148,7 @@ class instance(geometry):
|
||||||
geometry.__init__(self)
|
geometry.__init__(self)
|
||||||
debug.check(mirror not in ["R90", "R180", "R270"],
|
debug.check(mirror not in ["R90", "R180", "R270"],
|
||||||
"Please use rotation and not mirroring during instantiation.")
|
"Please use rotation and not mirroring during instantiation.")
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.mod = mod
|
self.mod = mod
|
||||||
self.gds = mod.gds
|
self.gds = mod.gds
|
||||||
|
|
@ -166,7 +166,7 @@ class instance(geometry):
|
||||||
self.width = round_to_grid(mod.width)
|
self.width = round_to_grid(mod.width)
|
||||||
self.height = round_to_grid(mod.height)
|
self.height = round_to_grid(mod.height)
|
||||||
self.compute_boundary(offset, mirror, rotate)
|
self.compute_boundary(offset, mirror, rotate)
|
||||||
|
|
||||||
debug.info(4, "creating instance: " + self.name)
|
debug.info(4, "creating instance: " + self.name)
|
||||||
|
|
||||||
def get_blockages(self, lpp, top=False):
|
def get_blockages(self, lpp, top=False):
|
||||||
|
|
@ -202,11 +202,11 @@ class instance(geometry):
|
||||||
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
new_blockages.append(self.transform_coords(b,self.offset, mirr, angle))
|
||||||
return new_blockages
|
return new_blockages
|
||||||
|
|
||||||
|
|
||||||
def gds_write_file(self, new_layout):
|
def gds_write_file(self, new_layout):
|
||||||
"""Recursively writes all the sub-modules in this instance"""
|
"""Recursively writes all the sub-modules in this instance"""
|
||||||
debug.info(4, "writing instance: " + self.name)
|
debug.info(4, "writing instance: " + self.name)
|
||||||
# make sure to write out my module/structure
|
# make sure to write out my module/structure
|
||||||
# (it will only be written the first time though)
|
# (it will only be written the first time though)
|
||||||
self.mod.gds_write_file(self.gds)
|
self.mod.gds_write_file(self.gds)
|
||||||
# now write an instance of my module/structure
|
# now write an instance of my module/structure
|
||||||
|
|
@ -215,7 +215,7 @@ class instance(geometry):
|
||||||
offsetInMicrons=self.offset,
|
offsetInMicrons=self.offset,
|
||||||
mirror=self.mirror,
|
mirror=self.mirror,
|
||||||
rotate=self.rotate)
|
rotate=self.rotate)
|
||||||
|
|
||||||
def place(self, offset, mirror="R0", rotate=0):
|
def place(self, offset, mirror="R0", rotate=0):
|
||||||
""" This updates the placement of an instance. """
|
""" This updates the placement of an instance. """
|
||||||
# Update the placement of an already added instance
|
# Update the placement of an already added instance
|
||||||
|
|
@ -224,8 +224,8 @@ class instance(geometry):
|
||||||
self.rotate = rotate
|
self.rotate = rotate
|
||||||
self.update_boundary()
|
self.update_boundary()
|
||||||
debug.info(3, "placing instance {}".format(self))
|
debug.info(3, "placing instance {}".format(self))
|
||||||
|
|
||||||
|
|
||||||
def get_pin(self,name,index=-1):
|
def get_pin(self,name,index=-1):
|
||||||
""" Return an absolute pin that is offset and transformed based on
|
""" Return an absolute pin that is offset and transformed based on
|
||||||
this instance location. Index will return one of several pins."""
|
this instance location. Index will return one of several pins."""
|
||||||
|
|
@ -243,20 +243,20 @@ class instance(geometry):
|
||||||
def get_num_pins(self, name):
|
def get_num_pins(self, name):
|
||||||
""" Return the number of pins of a given name """
|
""" Return the number of pins of a given name """
|
||||||
return len(self.mod.get_pins(name))
|
return len(self.mod.get_pins(name))
|
||||||
|
|
||||||
def get_pins(self,name):
|
def get_pins(self,name):
|
||||||
""" Return an absolute pin that is offset and transformed based on
|
""" Return an absolute pin that is offset and transformed based on
|
||||||
this instance location. """
|
this instance location. """
|
||||||
|
|
||||||
import copy
|
import copy
|
||||||
pin = copy.deepcopy(self.mod.get_pins(name))
|
pin = copy.deepcopy(self.mod.get_pins(name))
|
||||||
|
|
||||||
new_pins = []
|
new_pins = []
|
||||||
for p in pin:
|
for p in pin:
|
||||||
p.transform(self.offset,self.mirror,self.rotate)
|
p.transform(self.offset,self.mirror,self.rotate)
|
||||||
new_pins.append(p)
|
new_pins.append(p)
|
||||||
return new_pins
|
return new_pins
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.name + " " + self.mirror + " R=" + str(self.rotate) + ")"
|
return "( inst: " + self.name + " @" + str(self.offset) + " mod=" + self.mod.name + " " + self.mirror + " R=" + str(self.rotate) + ")"
|
||||||
|
|
@ -293,7 +293,7 @@ class path(geometry):
|
||||||
def get_blockages(self, layer):
|
def get_blockages(self, layer):
|
||||||
""" Fail since we don't support paths yet. """
|
""" Fail since we don't support paths yet. """
|
||||||
assert(0)
|
assert(0)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "path: layer=" + self.layerNumber + " w=" + self.width
|
return "path: layer=" + self.layerNumber + " w=" + self.width
|
||||||
|
|
@ -329,6 +329,7 @@ class label(geometry):
|
||||||
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
debug.info(4, "writing label (" + str(self.layerNumber) + "): " + self.text)
|
||||||
new_layout.addText(text=self.text,
|
new_layout.addText(text=self.text,
|
||||||
layerNumber=self.layerNumber,
|
layerNumber=self.layerNumber,
|
||||||
|
purposeNumber=self.layerPurpose,
|
||||||
offsetInMicrons=self.offset,
|
offsetInMicrons=self.offset,
|
||||||
magnification=self.zoom,
|
magnification=self.zoom,
|
||||||
rotate=None)
|
rotate=None)
|
||||||
|
|
@ -336,7 +337,7 @@ class label(geometry):
|
||||||
def get_blockages(self, layer):
|
def get_blockages(self, layer):
|
||||||
""" Returns an empty list since text cannot be blockages. """
|
""" Returns an empty list since text cannot be blockages. """
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "label: " + self.text + " layer=" + str(self.layerNumber)
|
return "label: " + self.text + " layer=" + str(self.layerNumber)
|
||||||
|
|
@ -345,7 +346,7 @@ class label(geometry):
|
||||||
""" override print function output """
|
""" override print function output """
|
||||||
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
|
return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )"
|
||||||
|
|
||||||
|
|
||||||
class rectangle(geometry):
|
class rectangle(geometry):
|
||||||
"""Represents a rectangular shape"""
|
"""Represents a rectangular shape"""
|
||||||
|
|
||||||
|
|
@ -363,7 +364,7 @@ class rectangle(geometry):
|
||||||
|
|
||||||
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
debug.info(4, "creating rectangle (" + str(self.layerNumber) + "): "
|
||||||
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
+ str(self.width) + "x" + str(self.height) + " @ " + str(self.offset))
|
||||||
|
|
||||||
def get_blockages(self, layer):
|
def get_blockages(self, layer):
|
||||||
""" Returns a list of one rectangle if it is on this layer"""
|
""" Returns a list of one rectangle if it is on this layer"""
|
||||||
if self.layerNumber == layer:
|
if self.layerNumber == layer:
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class pin_layout:
|
||||||
|
|
||||||
debug.check(self.width() > 0, "Zero width pin.")
|
debug.check(self.width() > 0, "Zero width pin.")
|
||||||
debug.check(self.height() > 0, "Zero height pin.")
|
debug.check(self.height() > 0, "Zero height pin.")
|
||||||
|
|
||||||
# if it's a string, use the name
|
# if it's a string, use the name
|
||||||
if type(layer_name_pp) == str:
|
if type(layer_name_pp) == str:
|
||||||
self._layer = layer_name_pp
|
self._layer = layer_name_pp
|
||||||
|
|
@ -93,17 +93,17 @@ class pin_layout:
|
||||||
is a major speedup, if pin_layout is used as a key for dicts.
|
is a major speedup, if pin_layout is used as a key for dicts.
|
||||||
"""
|
"""
|
||||||
return self._hash
|
return self._hash
|
||||||
|
|
||||||
def __lt__(self, other):
|
def __lt__(self, other):
|
||||||
""" Provide a function for ordering items by the ll point """
|
""" Provide a function for ordering items by the ll point """
|
||||||
(ll, ur) = self.rect
|
(ll, ur) = self.rect
|
||||||
(oll, our) = other.rect
|
(oll, our) = other.rect
|
||||||
|
|
||||||
if ll.x < oll.x and ll.y < oll.y:
|
if ll.x < oll.x and ll.y < oll.y:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
""" Check if these are the same pins for duplicate checks """
|
""" Check if these are the same pins for duplicate checks """
|
||||||
if isinstance(other, self.__class__):
|
if isinstance(other, self.__class__):
|
||||||
|
|
@ -128,14 +128,14 @@ class pin_layout:
|
||||||
max_y = max(max_y, pin.ur().y)
|
max_y = max(max_y, pin.ur().y)
|
||||||
|
|
||||||
self.rect = [vector(min_x, min_y), vector(max_x, max_y)]
|
self.rect = [vector(min_x, min_y), vector(max_x, max_y)]
|
||||||
|
|
||||||
def fix_minarea(self):
|
def fix_minarea(self):
|
||||||
"""
|
"""
|
||||||
Try to fix minimum area rule.
|
Try to fix minimum area rule.
|
||||||
"""
|
"""
|
||||||
min_area = drc("{}_minarea".format(self.layer))
|
min_area = drc("{}_minarea".format(self.layer))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def inflate(self, spacing=None):
|
def inflate(self, spacing=None):
|
||||||
"""
|
"""
|
||||||
Inflate the rectangle by the spacing (or other rule)
|
Inflate the rectangle by the spacing (or other rule)
|
||||||
|
|
@ -143,12 +143,12 @@ class pin_layout:
|
||||||
"""
|
"""
|
||||||
if not spacing:
|
if not spacing:
|
||||||
spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
|
spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
|
||||||
|
|
||||||
(ll, ur) = self.rect
|
(ll, ur) = self.rect
|
||||||
spacing = vector(spacing, spacing)
|
spacing = vector(spacing, spacing)
|
||||||
newll = ll - spacing
|
newll = ll - spacing
|
||||||
newur = ur + spacing
|
newur = ur + spacing
|
||||||
|
|
||||||
return (newll, newur)
|
return (newll, newur)
|
||||||
|
|
||||||
def intersection(self, other):
|
def intersection(self, other):
|
||||||
|
|
@ -191,7 +191,7 @@ class pin_layout:
|
||||||
y_overlaps = True
|
y_overlaps = True
|
||||||
|
|
||||||
return y_overlaps
|
return y_overlaps
|
||||||
|
|
||||||
def xcontains(self, other):
|
def xcontains(self, other):
|
||||||
""" Check if shape contains the x overlap """
|
""" Check if shape contains the x overlap """
|
||||||
(ll, ur) = self.rect
|
(ll, ur) = self.rect
|
||||||
|
|
@ -205,13 +205,13 @@ class pin_layout:
|
||||||
(oll, our) = other.rect
|
(oll, our) = other.rect
|
||||||
|
|
||||||
return (oll.y >= ll.y and our.y <= ur.y)
|
return (oll.y >= ll.y and our.y <= ur.y)
|
||||||
|
|
||||||
def contains(self, other):
|
def contains(self, other):
|
||||||
""" Check if a shape contains another rectangle """
|
""" Check if a shape contains another rectangle """
|
||||||
# If it is the same shape entirely, it is contained!
|
# If it is the same shape entirely, it is contained!
|
||||||
if self == other:
|
if self == other:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Can only overlap on the same layer
|
# Can only overlap on the same layer
|
||||||
if not self.same_lpp(self.lpp, other.lpp):
|
if not self.same_lpp(self.lpp, other.lpp):
|
||||||
return False
|
return False
|
||||||
|
|
@ -230,13 +230,13 @@ class pin_layout:
|
||||||
if shape.contains(self):
|
if shape.contains(self):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def overlaps(self, other):
|
def overlaps(self, other):
|
||||||
""" Check if a shape overlaps with a rectangle """
|
""" Check if a shape overlaps with a rectangle """
|
||||||
# Can only overlap on the same layer
|
# Can only overlap on the same layer
|
||||||
if not self.same_lpp(self.lpp, other.lpp):
|
if not self.same_lpp(self.lpp, other.lpp):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
x_overlaps = self.xoverlaps(other)
|
x_overlaps = self.xoverlaps(other)
|
||||||
y_overlaps = self.yoverlaps(other)
|
y_overlaps = self.yoverlaps(other)
|
||||||
|
|
||||||
|
|
@ -245,11 +245,11 @@ class pin_layout:
|
||||||
def area(self):
|
def area(self):
|
||||||
""" Return the area. """
|
""" Return the area. """
|
||||||
return self.height()*self.width()
|
return self.height()*self.width()
|
||||||
|
|
||||||
def height(self):
|
def height(self):
|
||||||
""" Return height. Abs is for pre-normalized value."""
|
""" Return height. Abs is for pre-normalized value."""
|
||||||
return abs(self.rect[1].y-self.rect[0].y)
|
return abs(self.rect[1].y-self.rect[0].y)
|
||||||
|
|
||||||
def width(self):
|
def width(self):
|
||||||
""" Return width. Abs is for pre-normalized value."""
|
""" Return width. Abs is for pre-normalized value."""
|
||||||
return abs(self.rect[1].x-self.rect[0].x)
|
return abs(self.rect[1].x-self.rect[0].x)
|
||||||
|
|
@ -260,7 +260,7 @@ class pin_layout:
|
||||||
ll = vector(min(first[0], second[0]), min(first[1], second[1]))
|
ll = vector(min(first[0], second[0]), min(first[1], second[1]))
|
||||||
ur = vector(max(first[0], second[0]), max(first[1], second[1]))
|
ur = vector(max(first[0], second[0]), max(first[1], second[1]))
|
||||||
self.rect=[ll, ur]
|
self.rect=[ll, ur]
|
||||||
|
|
||||||
def transform(self, offset, mirror, rotate):
|
def transform(self, offset, mirror, rotate):
|
||||||
"""
|
"""
|
||||||
Transform with offset, mirror and rotation
|
Transform with offset, mirror and rotation
|
||||||
|
|
@ -278,7 +278,7 @@ class pin_layout:
|
||||||
elif mirror == "XY":
|
elif mirror == "XY":
|
||||||
ll = ll.scale(-1, -1)
|
ll = ll.scale(-1, -1)
|
||||||
ur = ur.scale(-1, -1)
|
ur = ur.scale(-1, -1)
|
||||||
|
|
||||||
if rotate == 90:
|
if rotate == 90:
|
||||||
ll = ll.rotate_scale(-1, 1)
|
ll = ll.rotate_scale(-1, 1)
|
||||||
ur = ur.rotate_scale(-1, 1)
|
ur = ur.rotate_scale(-1, 1)
|
||||||
|
|
@ -303,7 +303,7 @@ class pin_layout:
|
||||||
def cy(self):
|
def cy(self):
|
||||||
""" Center y """
|
""" Center y """
|
||||||
return 0.5*(self.rect[0].y+self.rect[1].y)
|
return 0.5*(self.rect[0].y+self.rect[1].y)
|
||||||
|
|
||||||
# The four possible corners
|
# The four possible corners
|
||||||
def ll(self):
|
def ll(self):
|
||||||
""" Lower left point """
|
""" Lower left point """
|
||||||
|
|
@ -320,7 +320,7 @@ class pin_layout:
|
||||||
def ur(self):
|
def ur(self):
|
||||||
""" Upper right point """
|
""" Upper right point """
|
||||||
return self.rect[1]
|
return self.rect[1]
|
||||||
|
|
||||||
# The possible y edge values
|
# The possible y edge values
|
||||||
def uy(self):
|
def uy(self):
|
||||||
""" Upper y value """
|
""" Upper y value """
|
||||||
|
|
@ -331,15 +331,15 @@ class pin_layout:
|
||||||
return self.rect[0].y
|
return self.rect[0].y
|
||||||
|
|
||||||
# The possible x edge values
|
# The possible x edge values
|
||||||
|
|
||||||
def lx(self):
|
def lx(self):
|
||||||
""" Left x value """
|
""" Left x value """
|
||||||
return self.rect[0].x
|
return self.rect[0].x
|
||||||
|
|
||||||
def rx(self):
|
def rx(self):
|
||||||
""" Right x value """
|
""" Right x value """
|
||||||
return self.rect[1].x
|
return self.rect[1].x
|
||||||
|
|
||||||
# The edge centers
|
# The edge centers
|
||||||
def rc(self):
|
def rc(self):
|
||||||
""" Right center point """
|
""" Right center point """
|
||||||
|
|
@ -350,7 +350,7 @@ class pin_layout:
|
||||||
""" Left center point """
|
""" Left center point """
|
||||||
return vector(self.rect[0].x,
|
return vector(self.rect[0].x,
|
||||||
0.5*(self.rect[0].y+self.rect[1].y))
|
0.5*(self.rect[0].y+self.rect[1].y))
|
||||||
|
|
||||||
def uc(self):
|
def uc(self):
|
||||||
""" Upper center point """
|
""" Upper center point """
|
||||||
return vector(0.5*(self.rect[0].x+self.rect[1].x),
|
return vector(0.5*(self.rect[0].x+self.rect[1].x),
|
||||||
|
|
@ -378,6 +378,7 @@ class pin_layout:
|
||||||
# imported into Magic.
|
# imported into Magic.
|
||||||
newLayout.addText(text=self.name,
|
newLayout.addText(text=self.name,
|
||||||
layerNumber=layer_num,
|
layerNumber=layer_num,
|
||||||
|
purposeNumber=purpose,
|
||||||
offsetInMicrons=self.center(),
|
offsetInMicrons=self.center(),
|
||||||
magnification=GDS["zoom"],
|
magnification=GDS["zoom"],
|
||||||
rotate=None)
|
rotate=None)
|
||||||
|
|
@ -392,7 +393,7 @@ class pin_layout:
|
||||||
|
|
||||||
dy = min(r1_ur.y, r2_ur.y) - max(r1_ll.y, r2_ll.y)
|
dy = min(r1_ur.y, r2_ur.y) - max(r1_ll.y, r2_ll.y)
|
||||||
dx = min(r1_ur.x, r2_ur.x) - max(r1_ll.x, r2_ll.x)
|
dx = min(r1_ur.x, r2_ur.x) - max(r1_ll.x, r2_ll.x)
|
||||||
|
|
||||||
if dx >= 0 and dy >= 0:
|
if dx >= 0 and dy >= 0:
|
||||||
return [dx, dy]
|
return [dx, dy]
|
||||||
else:
|
else:
|
||||||
|
|
@ -407,7 +408,7 @@ class pin_layout:
|
||||||
|
|
||||||
def dist(x1, y1, x2, y2):
|
def dist(x1, y1, x2, y2):
|
||||||
return math.sqrt((x2-x1)**2 + (y2-y1)**2)
|
return math.sqrt((x2-x1)**2 + (y2-y1)**2)
|
||||||
|
|
||||||
left = r2_ur.x < r1_ll.x
|
left = r2_ur.x < r1_ll.x
|
||||||
right = r1_ur.x < r2_ll.x
|
right = r1_ur.x < r2_ll.x
|
||||||
bottom = r2_ur.y < r1_ll.y
|
bottom = r2_ur.y < r1_ll.y
|
||||||
|
|
@ -432,7 +433,7 @@ class pin_layout:
|
||||||
else:
|
else:
|
||||||
# rectangles intersect
|
# rectangles intersect
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def overlap_length(self, other):
|
def overlap_length(self, other):
|
||||||
"""
|
"""
|
||||||
Calculate the intersection segment and determine its length
|
Calculate the intersection segment and determine its length
|
||||||
|
|
@ -453,7 +454,7 @@ class pin_layout:
|
||||||
# This is where we had a corner intersection or none
|
# This is where we had a corner intersection or none
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def compute_overlap_segment(self, other):
|
def compute_overlap_segment(self, other):
|
||||||
"""
|
"""
|
||||||
Calculate the intersection segment of two rectangles
|
Calculate the intersection segment of two rectangles
|
||||||
|
|
@ -469,19 +470,19 @@ class pin_layout:
|
||||||
r2_lr = vector(r2_ur.x, r2_ll.y)
|
r2_lr = vector(r2_ur.x, r2_ll.y)
|
||||||
|
|
||||||
from itertools import tee
|
from itertools import tee
|
||||||
|
|
||||||
def pairwise(iterable):
|
def pairwise(iterable):
|
||||||
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
|
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
|
||||||
a, b = tee(iterable)
|
a, b = tee(iterable)
|
||||||
next(b, None)
|
next(b, None)
|
||||||
return zip(a, b)
|
return zip(a, b)
|
||||||
|
|
||||||
# R1 edges CW
|
# R1 edges CW
|
||||||
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
|
r1_cw_points = [r1_ll, r1_ul, r1_ur, r1_lr, r1_ll]
|
||||||
r1_edges = []
|
r1_edges = []
|
||||||
for (p, q) in pairwise(r1_cw_points):
|
for (p, q) in pairwise(r1_cw_points):
|
||||||
r1_edges.append([p, q])
|
r1_edges.append([p, q])
|
||||||
|
|
||||||
# R2 edges CW
|
# R2 edges CW
|
||||||
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
|
r2_cw_points = [r2_ll, r2_ul, r2_ur, r2_lr, r2_ll]
|
||||||
r2_edges = []
|
r2_edges = []
|
||||||
|
|
@ -509,9 +510,9 @@ class pin_layout:
|
||||||
q.y <= max(p.y, r.y) and \
|
q.y <= max(p.y, r.y) and \
|
||||||
q.y >= min(p.y, r.y):
|
q.y >= min(p.y, r.y):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def segment_intersection(self, s1, s2):
|
def segment_intersection(self, s1, s2):
|
||||||
"""
|
"""
|
||||||
Determine the intersection point of two segments
|
Determine the intersection point of two segments
|
||||||
|
|
@ -524,22 +525,22 @@ class pin_layout:
|
||||||
a1 = b.y - a.y
|
a1 = b.y - a.y
|
||||||
b1 = a.x - b.x
|
b1 = a.x - b.x
|
||||||
c1 = a1*a.x + b1*a.y
|
c1 = a1*a.x + b1*a.y
|
||||||
|
|
||||||
# Line CD represented as a2x + b2y = c2
|
# Line CD represented as a2x + b2y = c2
|
||||||
a2 = d.y - c.y
|
a2 = d.y - c.y
|
||||||
b2 = c.x - d.x
|
b2 = c.x - d.x
|
||||||
c2 = a2*c.x + b2*c.y
|
c2 = a2*c.x + b2*c.y
|
||||||
|
|
||||||
determinant = a1*b2 - a2*b1
|
determinant = a1*b2 - a2*b1
|
||||||
|
|
||||||
if determinant != 0:
|
if determinant != 0:
|
||||||
x = (b2*c1 - b1*c2)/determinant
|
x = (b2*c1 - b1*c2)/determinant
|
||||||
y = (a1*c2 - a2*c1)/determinant
|
y = (a1*c2 - a2*c1)/determinant
|
||||||
|
|
||||||
r = vector(x, y).snap_to_grid()
|
r = vector(x, y).snap_to_grid()
|
||||||
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
|
if self.on_segment(a, r, b) and self.on_segment(c, r, d):
|
||||||
return r
|
return r
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def same_lpp(self, lpp1, lpp2):
|
def same_lpp(self, lpp1, lpp2):
|
||||||
|
|
@ -549,5 +550,5 @@ class pin_layout:
|
||||||
"""
|
"""
|
||||||
if lpp1[1] == None or lpp2[1] == None:
|
if lpp1[1] == None or lpp2[1] == None:
|
||||||
return lpp1[0] == lpp2[0]
|
return lpp1[0] == lpp2[0]
|
||||||
|
|
||||||
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,5 @@
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from globals import OPTS
|
|
||||||
# default purpose layer is used for addText() in vlsiLayout.py
|
|
||||||
if OPTS.tech_name == "s8":
|
|
||||||
purposeLayer=20
|
|
||||||
else:
|
|
||||||
purposeLayer=0
|
|
||||||
|
|
||||||
class GdsStructure:
|
class GdsStructure:
|
||||||
"""Class represent a GDS Structure Object"""
|
"""Class represent a GDS Structure Object"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
@ -147,7 +140,7 @@ class GdsText:
|
||||||
self.elementFlags=""
|
self.elementFlags=""
|
||||||
self.plex=""
|
self.plex=""
|
||||||
self.drawingLayer=""
|
self.drawingLayer=""
|
||||||
self.purposeLayer=purposeLayer
|
self.purposeLayer=0
|
||||||
self.transFlags=[0,0,0]
|
self.transFlags=[0,0,0]
|
||||||
self.magFactor=""
|
self.magFactor=""
|
||||||
self.rotateAngle=""
|
self.rotateAngle=""
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class VlsiLayout:
|
||||||
modDate.hour,
|
modDate.hour,
|
||||||
modDate.minute,
|
modDate.minute,
|
||||||
modDate.second)
|
modDate.second)
|
||||||
|
|
||||||
self.info = dict() #information gathered from the GDSII header
|
self.info = dict() #information gathered from the GDSII header
|
||||||
self.info['units']=self.units
|
self.info['units']=self.units
|
||||||
self.info['dates']=(modDate.year,
|
self.info['dates']=(modDate.year,
|
||||||
|
|
@ -52,12 +52,12 @@ class VlsiLayout:
|
||||||
modDate.second)
|
modDate.second)
|
||||||
self.info['libraryName']=libraryName
|
self.info['libraryName']=libraryName
|
||||||
self.info['gdsVersion']=gdsVersion
|
self.info['gdsVersion']=gdsVersion
|
||||||
|
|
||||||
self.xyTree = [] #This will contain a list of all structure names
|
self.xyTree = [] #This will contain a list of all structure names
|
||||||
#expanded to include srefs / arefs separately.
|
#expanded to include srefs / arefs separately.
|
||||||
#each structure will have an X,Y,offset, and rotate associated
|
#each structure will have an X,Y,offset, and rotate associated
|
||||||
#with it. Populate via traverseTheHierarchy method.
|
#with it. Populate via traverseTheHierarchy method.
|
||||||
|
|
||||||
#temp variables used in delegate functions
|
#temp variables used in delegate functions
|
||||||
self.tempCoordinates=None
|
self.tempCoordinates=None
|
||||||
self.tempPassFail = True
|
self.tempPassFail = True
|
||||||
|
|
@ -73,14 +73,14 @@ class VlsiLayout:
|
||||||
if(rotateAngle):
|
if(rotateAngle):
|
||||||
angle = math.radians(float(rotateAngle))
|
angle = math.radians(float(rotateAngle))
|
||||||
|
|
||||||
coordinatesRotate = [] #this will hold the rotated values
|
coordinatesRotate = [] #this will hold the rotated values
|
||||||
for coordinate in coordinatesToRotate:
|
for coordinate in coordinatesToRotate:
|
||||||
# This is the CCW rotation matrix
|
# This is the CCW rotation matrix
|
||||||
newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle)
|
newX = coordinate[0]*math.cos(angle) - coordinate[1]*math.sin(angle)
|
||||||
newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle)
|
newY = coordinate[0]*math.sin(angle) + coordinate[1]*math.cos(angle)
|
||||||
coordinatesRotate.extend((newX,newY))
|
coordinatesRotate.extend((newX,newY))
|
||||||
return coordinatesRotate
|
return coordinatesRotate
|
||||||
|
|
||||||
def rename(self,newName):
|
def rename(self,newName):
|
||||||
#take the root structure and copy it to a new structure with the new name
|
#take the root structure and copy it to a new structure with the new name
|
||||||
self.structures[newName] = self.structures[self.rootStructureName]
|
self.structures[newName] = self.structures[self.rootStructureName]
|
||||||
|
|
@ -129,8 +129,8 @@ class VlsiLayout:
|
||||||
modDate.hour,
|
modDate.hour,
|
||||||
modDate.minute,
|
modDate.minute,
|
||||||
modDate.second)
|
modDate.second)
|
||||||
|
|
||||||
|
|
||||||
#repopulate the 2d map so drawing occurs correctly
|
#repopulate the 2d map so drawing occurs correctly
|
||||||
self.prepareForWrite()
|
self.prepareForWrite()
|
||||||
|
|
||||||
|
|
@ -155,15 +155,15 @@ class VlsiLayout:
|
||||||
debug.check(len(structureNames)==1,"Multiple possible root structures in the layout: {}".format(str(structureNames)))
|
debug.check(len(structureNames)==1,"Multiple possible root structures in the layout: {}".format(str(structureNames)))
|
||||||
self.rootStructureName = structureNames[0]
|
self.rootStructureName = structureNames[0]
|
||||||
|
|
||||||
|
|
||||||
def traverseTheHierarchy(self, startingStructureName=None, delegateFunction = None,
|
def traverseTheHierarchy(self, startingStructureName=None, delegateFunction = None,
|
||||||
transformPath = [], rotateAngle = 0, transFlags = [0,0,0], coordinates = (0,0)):
|
transformPath = [], rotateAngle = 0, transFlags = [0,0,0], coordinates = (0,0)):
|
||||||
#since this is a recursive function, must deal with the default
|
#since this is a recursive function, must deal with the default
|
||||||
#parameters explicitly
|
#parameters explicitly
|
||||||
if startingStructureName == None:
|
if startingStructureName == None:
|
||||||
startingStructureName = self.rootStructureName
|
startingStructureName = self.rootStructureName
|
||||||
|
|
||||||
#set up the rotation matrix
|
#set up the rotation matrix
|
||||||
if(rotateAngle == None or rotateAngle == ""):
|
if(rotateAngle == None or rotateAngle == ""):
|
||||||
angle = 0
|
angle = 0
|
||||||
else:
|
else:
|
||||||
|
|
@ -193,10 +193,10 @@ class VlsiLayout:
|
||||||
try:
|
try:
|
||||||
if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others?
|
if(len(self.structures[startingStructureName].srefs)>0): #does this structure reference any others?
|
||||||
#if so, go through each and call this function again
|
#if so, go through each and call this function again
|
||||||
#if not, return back to the caller (caller can be this function)
|
#if not, return back to the caller (caller can be this function)
|
||||||
for sref in self.structures[startingStructureName].srefs:
|
for sref in self.structures[startingStructureName].srefs:
|
||||||
#here, we are going to modify the sref coordinates based on the parent objects rotation
|
#here, we are going to modify the sref coordinates based on the parent objects rotation
|
||||||
self.traverseTheHierarchy(startingStructureName = sref.sName,
|
self.traverseTheHierarchy(startingStructureName = sref.sName,
|
||||||
delegateFunction = delegateFunction,
|
delegateFunction = delegateFunction,
|
||||||
transformPath = transformPath,
|
transformPath = transformPath,
|
||||||
rotateAngle = sref.rotateAngle,
|
rotateAngle = sref.rotateAngle,
|
||||||
|
|
@ -204,12 +204,12 @@ class VlsiLayout:
|
||||||
coordinates = sref.coordinates)
|
coordinates = sref.coordinates)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
debug.error("Could not find structure {} in GDS file.".format(startingStructureName),-1)
|
debug.error("Could not find structure {} in GDS file.".format(startingStructureName),-1)
|
||||||
|
|
||||||
#MUST HANDLE AREFs HERE AS WELL
|
#MUST HANDLE AREFs HERE AS WELL
|
||||||
#when we return, drop the last transform from the transformPath
|
#when we return, drop the last transform from the transformPath
|
||||||
del transformPath[-1]
|
del transformPath[-1]
|
||||||
return
|
return
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.deduceHierarchy()
|
self.deduceHierarchy()
|
||||||
# self.traverseTheHierarchy()
|
# self.traverseTheHierarchy()
|
||||||
|
|
@ -217,17 +217,17 @@ class VlsiLayout:
|
||||||
|
|
||||||
for layerNumber in self.layerNumbersInUse:
|
for layerNumber in self.layerNumbersInUse:
|
||||||
self.processLabelPins((layerNumber, None))
|
self.processLabelPins((layerNumber, None))
|
||||||
|
|
||||||
|
|
||||||
def populateCoordinateMap(self):
|
def populateCoordinateMap(self):
|
||||||
def addToXyTree(startingStructureName = None,transformPath = None):
|
def addToXyTree(startingStructureName = None,transformPath = None):
|
||||||
uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors
|
uVector = np.array([[1.0],[0.0],[0.0]]) #start with normal basis vectors
|
||||||
vVector = np.array([[0.0],[1.0],[0.0]])
|
vVector = np.array([[0.0],[1.0],[0.0]])
|
||||||
origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector)
|
origin = np.array([[0.0],[0.0],[1.0]]) #and an origin (Z component is 1.0 to indicate position instead of vector)
|
||||||
#make a copy of all the transforms and reverse it
|
#make a copy of all the transforms and reverse it
|
||||||
reverseTransformPath = transformPath[:]
|
reverseTransformPath = transformPath[:]
|
||||||
if len(reverseTransformPath) > 1:
|
if len(reverseTransformPath) > 1:
|
||||||
reverseTransformPath.reverse()
|
reverseTransformPath.reverse()
|
||||||
#now go through each transform and apply them to our basis and origin in succession
|
#now go through each transform and apply them to our basis and origin in succession
|
||||||
for transform in reverseTransformPath:
|
for transform in reverseTransformPath:
|
||||||
origin = np.dot(transform[0], origin) #rotate
|
origin = np.dot(transform[0], origin) #rotate
|
||||||
|
|
@ -237,20 +237,20 @@ class VlsiLayout:
|
||||||
uVector = np.dot(transform[1], uVector) #scale
|
uVector = np.dot(transform[1], uVector) #scale
|
||||||
vVector = np.dot(transform[1], vVector) #scale
|
vVector = np.dot(transform[1], vVector) #scale
|
||||||
origin = np.dot(transform[2], origin) #translate
|
origin = np.dot(transform[2], origin) #translate
|
||||||
#we don't need to do a translation on the basis vectors
|
#we don't need to do a translation on the basis vectors
|
||||||
#uVector = transform[2] * uVector #translate
|
#uVector = transform[2] * uVector #translate
|
||||||
#vVector = transform[2] * vVector #translate
|
#vVector = transform[2] * vVector #translate
|
||||||
#populate the xyTree with each structureName and coordinate space
|
#populate the xyTree with each structureName and coordinate space
|
||||||
self.xyTree.append((startingStructureName,origin,uVector,vVector))
|
self.xyTree.append((startingStructureName,origin,uVector,vVector))
|
||||||
self.traverseTheHierarchy(delegateFunction = addToXyTree)
|
self.traverseTheHierarchy(delegateFunction = addToXyTree)
|
||||||
|
|
||||||
def microns(self, userUnits):
|
def microns(self, userUnits):
|
||||||
"""Utility function to convert user units to microns"""
|
"""Utility function to convert user units to microns"""
|
||||||
userUnit = self.units[1]/self.units[0]
|
userUnit = self.units[1]/self.units[0]
|
||||||
userUnitsPerMicron = userUnit / userunit
|
userUnitsPerMicron = userUnit / userunit
|
||||||
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
|
layoutUnitsPerMicron = userUnitsPerMicron / self.units[0]
|
||||||
return userUnits / layoutUnitsPerMicron
|
return userUnits / layoutUnitsPerMicron
|
||||||
|
|
||||||
def userUnits(self, microns):
|
def userUnits(self, microns):
|
||||||
"""Utility function to convert microns to user units"""
|
"""Utility function to convert microns to user units"""
|
||||||
userUnit = self.units[1]/self.units[0]
|
userUnit = self.units[1]/self.units[0]
|
||||||
|
|
@ -270,7 +270,7 @@ class VlsiLayout:
|
||||||
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
debug.info(0,"DEBUG: GdsMill vlsiLayout: changeRoot: %s "%newRoot)
|
debug.info(0,"DEBUG: GdsMill vlsiLayout: changeRoot: %s "%newRoot)
|
||||||
|
|
||||||
# Determine if newRoot exists
|
# Determine if newRoot exists
|
||||||
# layoutToAdd (default) or nameOfLayout
|
# layoutToAdd (default) or nameOfLayout
|
||||||
if (newRoot == 0 | ((newRoot not in self.structures) & ~create)):
|
if (newRoot == 0 | ((newRoot not in self.structures) & ~create)):
|
||||||
|
|
@ -282,19 +282,19 @@ class VlsiLayout:
|
||||||
self.rootStructureName = newRoot
|
self.rootStructureName = newRoot
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def addInstance(self,layoutToAdd,nameOfLayout=0,offsetInMicrons=(0,0),mirror=None,rotate=None):
|
def addInstance(self,layoutToAdd,nameOfLayout=0,offsetInMicrons=(0,0),mirror=None,rotate=None):
|
||||||
"""
|
"""
|
||||||
Method to insert one layout into another at a particular offset.
|
Method to insert one layout into another at a particular offset.
|
||||||
"""
|
"""
|
||||||
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
||||||
if self.debug:
|
if self.debug:
|
||||||
debug.info(0,"DEBUG: GdsMill vlsiLayout: addInstance: type {0}, nameOfLayout {1}".format(type(layoutToAdd),nameOfLayout))
|
debug.info(0,"DEBUG: GdsMill vlsiLayout: addInstance: type {0}, nameOfLayout {1}".format(type(layoutToAdd),nameOfLayout))
|
||||||
debug.info(0,"DEBUG: name={0} offset={1} mirror={2} rotate={3}".format(layoutToAdd.rootStructureName,offsetInMicrons, mirror, rotate))
|
debug.info(0,"DEBUG: name={0} offset={1} mirror={2} rotate={3}".format(layoutToAdd.rootStructureName,offsetInMicrons, mirror, rotate))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Determine if we are instantiating the root design of
|
# Determine if we are instantiating the root design of
|
||||||
# layoutToAdd (default) or nameOfLayout
|
# layoutToAdd (default) or nameOfLayout
|
||||||
if nameOfLayout == 0:
|
if nameOfLayout == 0:
|
||||||
StructureFound = True
|
StructureFound = True
|
||||||
|
|
@ -303,7 +303,7 @@ class VlsiLayout:
|
||||||
StructureName = nameOfLayout #layoutToAdd
|
StructureName = nameOfLayout #layoutToAdd
|
||||||
StructureFound = False
|
StructureFound = False
|
||||||
for structure in layoutToAdd.structures:
|
for structure in layoutToAdd.structures:
|
||||||
if StructureName in structure:
|
if StructureName in structure:
|
||||||
if self.debug:
|
if self.debug:
|
||||||
debug.info(1,"DEBUG: Structure %s Found"%StructureName)
|
debug.info(1,"DEBUG: Structure %s Found"%StructureName)
|
||||||
StructureFound = True
|
StructureFound = True
|
||||||
|
|
@ -311,7 +311,7 @@ class VlsiLayout:
|
||||||
debug.check(StructureFound,"Could not find layout to instantiate {}".format(StructureName))
|
debug.check(StructureFound,"Could not find layout to instantiate {}".format(StructureName))
|
||||||
|
|
||||||
|
|
||||||
# If layoutToAdd is a unique object (not this), then copy hierarchy,
|
# If layoutToAdd is a unique object (not this), then copy hierarchy,
|
||||||
# otherwise, if it is a text name of an internal structure, use it.
|
# otherwise, if it is a text name of an internal structure, use it.
|
||||||
|
|
||||||
if layoutToAdd != self:
|
if layoutToAdd != self:
|
||||||
|
|
@ -330,7 +330,7 @@ class VlsiLayout:
|
||||||
layoutToAddSref.coordinates = offsetInLayoutUnits
|
layoutToAddSref.coordinates = offsetInLayoutUnits
|
||||||
|
|
||||||
if mirror or rotate:
|
if mirror or rotate:
|
||||||
|
|
||||||
layoutToAddSref.transFlags = [0,0,0]
|
layoutToAddSref.transFlags = [0,0,0]
|
||||||
# transFlags = (mirror around x-axis, magnification, rotation)
|
# transFlags = (mirror around x-axis, magnification, rotation)
|
||||||
# If magnification or rotation is true, it is the flags are then
|
# If magnification or rotation is true, it is the flags are then
|
||||||
|
|
@ -356,7 +356,7 @@ class VlsiLayout:
|
||||||
|
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
|
self.structures[self.rootStructureName].srefs.append(layoutToAddSref)
|
||||||
|
|
||||||
def addBox(self,layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
|
def addBox(self,layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), width=1.0, height=1.0,center=False):
|
||||||
"""
|
"""
|
||||||
Method to add a box to a layout
|
Method to add a box to a layout
|
||||||
|
|
@ -373,7 +373,7 @@ class VlsiLayout:
|
||||||
(offsetInLayoutUnits[0],offsetInLayoutUnits[1]+heightInLayoutUnits),
|
(offsetInLayoutUnits[0],offsetInLayoutUnits[1]+heightInLayoutUnits),
|
||||||
offsetInLayoutUnits]
|
offsetInLayoutUnits]
|
||||||
else:
|
else:
|
||||||
startPoint = (offsetInLayoutUnits[0]-widthInLayoutUnits/2.0, offsetInLayoutUnits[1]-heightInLayoutUnits/2.0)
|
startPoint = (offsetInLayoutUnits[0]-widthInLayoutUnits/2.0, offsetInLayoutUnits[1]-heightInLayoutUnits/2.0)
|
||||||
coordinates=[startPoint,
|
coordinates=[startPoint,
|
||||||
(startPoint[0]+widthInLayoutUnits,startPoint[1]),
|
(startPoint[0]+widthInLayoutUnits,startPoint[1]),
|
||||||
(startPoint[0]+widthInLayoutUnits,startPoint[1]+heightInLayoutUnits),
|
(startPoint[0]+widthInLayoutUnits,startPoint[1]+heightInLayoutUnits),
|
||||||
|
|
@ -386,7 +386,7 @@ class VlsiLayout:
|
||||||
boundaryToAdd.purposeLayer = purposeNumber
|
boundaryToAdd.purposeLayer = purposeNumber
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
|
self.structures[self.rootStructureName].boundaries.append(boundaryToAdd)
|
||||||
|
|
||||||
def addPath(self, layerNumber=0, purposeNumber=0, coordinates=[(0,0)], width=1.0):
|
def addPath(self, layerNumber=0, purposeNumber=0, coordinates=[(0,0)], width=1.0):
|
||||||
"""
|
"""
|
||||||
Method to add a path to a layout
|
Method to add a path to a layout
|
||||||
|
|
@ -405,11 +405,12 @@ class VlsiLayout:
|
||||||
pathToAdd.coordinates = layoutUnitCoordinates
|
pathToAdd.coordinates = layoutUnitCoordinates
|
||||||
#add the sref to the root structure
|
#add the sref to the root structure
|
||||||
self.structures[self.rootStructureName].paths.append(pathToAdd)
|
self.structures[self.rootStructureName].paths.append(pathToAdd)
|
||||||
|
|
||||||
def addText(self, text, layerNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
|
def addText(self, text, layerNumber=0, purposeNumber=0, offsetInMicrons=(0,0), magnification=0.1, rotate = None):
|
||||||
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
offsetInLayoutUnits = (self.userUnits(offsetInMicrons[0]),self.userUnits(offsetInMicrons[1]))
|
||||||
textToAdd = GdsText()
|
textToAdd = GdsText()
|
||||||
textToAdd.drawingLayer = layerNumber
|
textToAdd.drawingLayer = layerNumber
|
||||||
|
textToAdd.purposeLayer = purposeNumber
|
||||||
textToAdd.coordinates = [offsetInLayoutUnits]
|
textToAdd.coordinates = [offsetInLayoutUnits]
|
||||||
textToAdd.transFlags = [0,0,0]
|
textToAdd.transFlags = [0,0,0]
|
||||||
textToAdd.textString = self.padText(text)
|
textToAdd.textString = self.padText(text)
|
||||||
|
|
@ -438,7 +439,7 @@ class VlsiLayout:
|
||||||
return 1
|
return 1
|
||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def intersectionPoint(self,startPoint1,endPoint1,startPoint2,endPoint2):
|
def intersectionPoint(self,startPoint1,endPoint1,startPoint2,endPoint2):
|
||||||
if((endPoint1[0]-startPoint1[0])!=0 and (endPoint2[0]-startPoint2[0])!=0):
|
if((endPoint1[0]-startPoint1[0])!=0 and (endPoint2[0]-startPoint2[0])!=0):
|
||||||
pSlope = (endPoint1[1]-startPoint1[1])/(endPoint1[0]-startPoint1[0])
|
pSlope = (endPoint1[1]-startPoint1[1])/(endPoint1[0]-startPoint1[0])
|
||||||
|
|
@ -458,7 +459,7 @@ class VlsiLayout:
|
||||||
newY = None
|
newY = None
|
||||||
elif((endPoint1[0]-startPoint1[0])==0 and (endPoint2[0]-startPoint2[0])!=0):
|
elif((endPoint1[0]-startPoint1[0])==0 and (endPoint2[0]-startPoint2[0])!=0):
|
||||||
qSlope = (endPoint2[1]-startPoint2[1])/(endPoint2[0]-startPoint2[0])
|
qSlope = (endPoint2[1]-startPoint2[1])/(endPoint2[0]-startPoint2[0])
|
||||||
qIntercept = startPoint2[1]-qSlope*startPoint2[0]
|
qIntercept = startPoint2[1]-qSlope*startPoint2[0]
|
||||||
newX=endPoint1[0]
|
newX=endPoint1[0]
|
||||||
newY=qSlope*newX+qIntercept
|
newY=qSlope*newX+qIntercept
|
||||||
elif((endPoint1[0]-startPoint1[0])!=0 and (endPoint2[0]-startPoint2[0])==0):
|
elif((endPoint1[0]-startPoint1[0])!=0 and (endPoint2[0]-startPoint2[0])==0):
|
||||||
|
|
@ -467,14 +468,14 @@ class VlsiLayout:
|
||||||
newX=endPoint2[0]
|
newX=endPoint2[0]
|
||||||
newY=pSlope*newX+pIntercept
|
newY=pSlope*newX+pIntercept
|
||||||
return (newX,newY)
|
return (newX,newY)
|
||||||
|
|
||||||
def isCollinear(self,testPoint,point1,point2):
|
def isCollinear(self,testPoint,point1,point2):
|
||||||
slope1 = (testPoint[1]-point1[1])/(testPoint[0]-point1[0])
|
slope1 = (testPoint[1]-point1[1])/(testPoint[0]-point1[0])
|
||||||
slope2 = (point2[1]-point1[1])/(point2[0]-point1[0])
|
slope2 = (point2[1]-point1[1])/(point2[0]-point1[0])
|
||||||
if slope1 == slope2:
|
if slope1 == slope2:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def doShapesIntersect(self,shape1Coordinates, shape2Coordinates):
|
def doShapesIntersect(self,shape1Coordinates, shape2Coordinates):
|
||||||
"""
|
"""
|
||||||
Utility function to determine if 2 arbitrary shapes intersect.
|
Utility function to determine if 2 arbitrary shapes intersect.
|
||||||
|
|
@ -491,7 +492,7 @@ class VlsiLayout:
|
||||||
if(self.isBounded(intersect,startPoint1,endPoint1) and self.isBounded(intersect,startPoint2,endPoint2)):
|
if(self.isBounded(intersect,startPoint1,endPoint1) and self.isBounded(intersect,startPoint2,endPoint2)):
|
||||||
return True #these shapes overlap!
|
return True #these shapes overlap!
|
||||||
return False #these shapes are ok
|
return False #these shapes are ok
|
||||||
|
|
||||||
def isPointInsideOfBox(self,pointCoordinates,boxCoordinates):
|
def isPointInsideOfBox(self,pointCoordinates,boxCoordinates):
|
||||||
"""
|
"""
|
||||||
Check if a point is contained in the shape
|
Check if a point is contained in the shape
|
||||||
|
|
@ -516,7 +517,7 @@ class VlsiLayout:
|
||||||
pointCoordinates[1]<bottomBound):
|
pointCoordinates[1]<bottomBound):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates):
|
def isShapeInsideOfBox(self,shapeCoordinates, boxCoordinates):
|
||||||
"""
|
"""
|
||||||
Go through every point in the shape to test if they are all inside the box.
|
Go through every point in the shape to test if they are all inside the box.
|
||||||
|
|
@ -525,8 +526,8 @@ class VlsiLayout:
|
||||||
if not self.isPointInsideOfBox(point,boxCoordinates):
|
if not self.isPointInsideOfBox(point,boxCoordinates):
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0):
|
def fillAreaDensity(self, layerToFill = 0, offsetInMicrons = (0,0), coverageWidth = 100.0, coverageHeight = 100.0, minSpacing = 0.22, blockSize = 1.0):
|
||||||
effectiveBlock = blockSize+minSpacing
|
effectiveBlock = blockSize+minSpacing
|
||||||
widthInBlocks = int(coverageWidth/effectiveBlock)
|
widthInBlocks = int(coverageWidth/effectiveBlock)
|
||||||
|
|
@ -545,7 +546,7 @@ class VlsiLayout:
|
||||||
shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1]))
|
shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1]))
|
||||||
joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates)
|
joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates)
|
||||||
if joint:
|
if joint:
|
||||||
self.tempPassFail = False
|
self.tempPassFail = False
|
||||||
common = self.isShapeInsideOfBox(shiftedBoundaryCoordinates,self.tempCoordinates)
|
common = self.isShapeInsideOfBox(shiftedBoundaryCoordinates,self.tempCoordinates)
|
||||||
if common:
|
if common:
|
||||||
self.tempPassFail = False
|
self.tempPassFail = False
|
||||||
|
|
@ -558,11 +559,11 @@ class VlsiLayout:
|
||||||
shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1]))
|
shiftedBoundaryCoordinates.append((shapeCoordinate[0]+coordinates[0],shapeCoordinate[1]+coordinates[1]))
|
||||||
joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates)
|
joint = self.doShapesIntersect(self.tempCoordinates, shiftedBoundaryCoordinates)
|
||||||
if joint:
|
if joint:
|
||||||
self.tempPassFail = False
|
self.tempPassFail = False
|
||||||
common = self.isShapeInsideOfBox(shiftedBoundaryCoordinates,self.tempCoordinates)
|
common = self.isShapeInsideOfBox(shiftedBoundaryCoordinates,self.tempCoordinates)
|
||||||
if common:
|
if common:
|
||||||
self.tempPassFail = False
|
self.tempPassFail = False
|
||||||
|
|
||||||
for yIndex in range(0,heightInBlocks):
|
for yIndex in range(0,heightInBlocks):
|
||||||
for xIndex in range(0,widthInBlocks):
|
for xIndex in range(0,widthInBlocks):
|
||||||
percentDone = (float((yIndex*heightInBlocks)+xIndex) / (heightInBlocks*widthInBlocks))*100
|
percentDone = (float((yIndex*heightInBlocks)+xIndex) / (heightInBlocks*widthInBlocks))*100
|
||||||
|
|
@ -581,7 +582,7 @@ class VlsiLayout:
|
||||||
passFailRecord.append(self.tempPassFail)
|
passFailRecord.append(self.tempPassFail)
|
||||||
print("Percent Complete:"+str(percentDone))
|
print("Percent Complete:"+str(percentDone))
|
||||||
|
|
||||||
|
|
||||||
passFailIndex=0
|
passFailIndex=0
|
||||||
for yIndex in range(0,heightInBlocks):
|
for yIndex in range(0,heightInBlocks):
|
||||||
for xIndex in range(0,widthInBlocks):
|
for xIndex in range(0,widthInBlocks):
|
||||||
|
|
@ -632,7 +633,7 @@ class VlsiLayout:
|
||||||
self.units[0]*cellBoundary[1]],
|
self.units[0]*cellBoundary[1]],
|
||||||
[self.units[0]*cellBoundary[2],
|
[self.units[0]*cellBoundary[2],
|
||||||
self.units[0]*cellBoundary[3]]]
|
self.units[0]*cellBoundary[3]]]
|
||||||
|
|
||||||
def measureSizeInStructure(self, structure, cellBoundary):
|
def measureSizeInStructure(self, structure, cellBoundary):
|
||||||
(structureName, structureOrigin,
|
(structureName, structureOrigin,
|
||||||
structureuVector, structurevVector) = structure
|
structureuVector, structurevVector) = structure
|
||||||
|
|
@ -645,7 +646,7 @@ class VlsiLayout:
|
||||||
thisBoundary[2]+structureOrigin[0],thisBoundary[3]+structureOrigin[1]]
|
thisBoundary[2]+structureOrigin[0],thisBoundary[3]+structureOrigin[1]]
|
||||||
cellBoundary=self.updateBoundary(thisBoundary,cellBoundary)
|
cellBoundary=self.updateBoundary(thisBoundary,cellBoundary)
|
||||||
return cellBoundary
|
return cellBoundary
|
||||||
|
|
||||||
def updateBoundary(self,thisBoundary,cellBoundary):
|
def updateBoundary(self,thisBoundary,cellBoundary):
|
||||||
[left_bott_X,left_bott_Y,right_top_X,right_top_Y]=thisBoundary
|
[left_bott_X,left_bott_Y,right_top_X,right_top_Y]=thisBoundary
|
||||||
# If any are None
|
# If any are None
|
||||||
|
|
@ -672,7 +673,7 @@ class VlsiLayout:
|
||||||
lpp):
|
lpp):
|
||||||
text_list.append(Text)
|
text_list.append(Text)
|
||||||
return text_list
|
return text_list
|
||||||
|
|
||||||
def getPinShape(self, pin_name):
|
def getPinShape(self, pin_name):
|
||||||
"""
|
"""
|
||||||
Search for a pin label and return the largest enclosing rectangle
|
Search for a pin label and return the largest enclosing rectangle
|
||||||
|
|
@ -693,7 +694,7 @@ class VlsiLayout:
|
||||||
max_pins.append(max_pin)
|
max_pins.append(max_pin)
|
||||||
|
|
||||||
return max_pins
|
return max_pins
|
||||||
|
|
||||||
|
|
||||||
def getAllPinShapes(self, pin_name):
|
def getAllPinShapes(self, pin_name):
|
||||||
"""
|
"""
|
||||||
|
|
@ -716,7 +717,7 @@ class VlsiLayout:
|
||||||
"""
|
"""
|
||||||
# Get the labels on a layer in the root level
|
# Get the labels on a layer in the root level
|
||||||
labels = self.getTexts(lpp)
|
labels = self.getTexts(lpp)
|
||||||
|
|
||||||
# Get all of the shapes on the layer at all levels
|
# Get all of the shapes on the layer at all levels
|
||||||
# and transform them to the current level
|
# and transform them to the current level
|
||||||
shapes = self.getAllShapes(lpp)
|
shapes = self.getAllShapes(lpp)
|
||||||
|
|
@ -730,7 +731,7 @@ class VlsiLayout:
|
||||||
pin_shapes.append((lpp, boundary))
|
pin_shapes.append((lpp, boundary))
|
||||||
|
|
||||||
label_text = label.textString
|
label_text = label.textString
|
||||||
|
|
||||||
# Remove the padding if it exists
|
# Remove the padding if it exists
|
||||||
if label_text[-1] == "\x00":
|
if label_text[-1] == "\x00":
|
||||||
label_text = label_text[0:-1]
|
label_text = label_text[0:-1]
|
||||||
|
|
@ -740,7 +741,7 @@ class VlsiLayout:
|
||||||
except KeyError:
|
except KeyError:
|
||||||
self.pins[label_text] = []
|
self.pins[label_text] = []
|
||||||
self.pins[label_text].append(pin_shapes)
|
self.pins[label_text].append(pin_shapes)
|
||||||
|
|
||||||
def getBlockages(self, lpp):
|
def getBlockages(self, lpp):
|
||||||
"""
|
"""
|
||||||
Return all blockages on a given layer in
|
Return all blockages on a given layer in
|
||||||
|
|
@ -755,7 +756,7 @@ class VlsiLayout:
|
||||||
for i in range(0, len(boundary), 2):
|
for i in range(0, len(boundary), 2):
|
||||||
vectors.append((boundary[i], boundary[i+1]))
|
vectors.append((boundary[i], boundary[i+1]))
|
||||||
blockages.append(vectors)
|
blockages.append(vectors)
|
||||||
|
|
||||||
return blockages
|
return blockages
|
||||||
|
|
||||||
def getAllShapes(self, lpp):
|
def getAllShapes(self, lpp):
|
||||||
|
|
@ -870,7 +871,7 @@ class VlsiLayout:
|
||||||
"""
|
"""
|
||||||
Rotate a coordinate in space.
|
Rotate a coordinate in space.
|
||||||
"""
|
"""
|
||||||
# MRG: 9/3/18 Incorrect matrix multiplication!
|
# MRG: 9/3/18 Incorrect matrix multiplication!
|
||||||
# This is fixed to be:
|
# This is fixed to be:
|
||||||
# |u[0] v[0]| |x| |x'|
|
# |u[0] v[0]| |x| |x'|
|
||||||
# |u[1] v[1]|x|y|=|y'|
|
# |u[1] v[1]|x|y|=|y'|
|
||||||
|
|
@ -892,7 +893,7 @@ class VlsiLayout:
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def sameLPP(lpp1, lpp2):
|
def sameLPP(lpp1, lpp2):
|
||||||
"""
|
"""
|
||||||
Check if the layers and purposes are the same.
|
Check if the layers and purposes are the same.
|
||||||
|
|
@ -900,14 +901,13 @@ def sameLPP(lpp1, lpp2):
|
||||||
"""
|
"""
|
||||||
if lpp1[1] == None or lpp2[1] == None:
|
if lpp1[1] == None or lpp2[1] == None:
|
||||||
return lpp1[0] == lpp2[0]
|
return lpp1[0] == lpp2[0]
|
||||||
|
|
||||||
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
return lpp1[0] == lpp2[0] and lpp1[1] == lpp2[1]
|
||||||
|
|
||||||
|
|
||||||
def boundaryArea(A):
|
def boundaryArea(A):
|
||||||
"""
|
"""
|
||||||
Returns boundary area for sorting.
|
Returns boundary area for sorting.
|
||||||
"""
|
"""
|
||||||
area_A=(A[2]-A[0])*(A[3]-A[1])
|
area_A=(A[2]-A[0])*(A[3]-A[1])
|
||||||
return area_A
|
return area_A
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue