Merge remote-tracking branch 'origin/dev' into tech_migration

This commit is contained in:
mrg 2020-02-25 00:36:43 +00:00
commit e80677caf7
16 changed files with 427 additions and 319 deletions

4
.gitignore vendored
View File

@ -1,8 +1,10 @@
.DS_Store .DS_Store
*~ *~
*.orig
*.rej
*.pyc *.pyc
*.aux *.aux
*.out *.out
*.toc *.toc
*.synctex.gz *.synctex.gz
**/model_data **/model_data

View File

@ -116,6 +116,15 @@ class cell_properties():
self._dff_buff_array = _dff_buff_array(use_custom_ports = False, self._dff_buff_array = _dff_buff_array(use_custom_ports = False,
add_body_contacts = False) add_body_contacts = False)
self._write_driver = _cell({'din': 'din',
'bl' : 'bl',
'br' : 'br',
'en' : 'en'})
self._sense_amp = _cell({'bl' : 'bl',
'br' : 'br',
'dout' : 'dout',
'en' : 'en'})
@property @property
def bitcell(self): def bitcell(self):
return self._bitcell return self._bitcell
@ -132,3 +141,10 @@ class cell_properties():
def dff_buff_array(self): def dff_buff_array(self):
return self._dff_buff_array return self._dff_buff_array
@property
def write_driver(self):
return self._write_driver
@property
def sense_amp(self):
return self._sense_amp

View File

@ -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:

View File

@ -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]

View File

@ -180,30 +180,30 @@ class delay(simulation):
def create_read_bit_measures(self): def create_read_bit_measures(self):
""" Adds bit measurements for read0 and read1 cycles """ """ Adds bit measurements for read0 and read1 cycles """
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} self.read_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE) meas_cycles = (sram_op.READ_ZERO, sram_op.READ_ONE)
for cycle in meas_cycles: for cycle in meas_cycles:
meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
for polarity,meas in single_bit_meas.items(): for polarity,meas in single_bit_meas.items():
meas.meta_str = cycle meas.meta_str = cycle
self.bit_meas[polarity].append(meas) self.read_bit_meas[polarity].append(meas)
# Dictionary values are lists, reduce to a single list of measurements # Dictionary values are lists, reduce to a single list of measurements
return [meas for meas_list in self.bit_meas.values() for meas in meas_list] return [meas for meas_list in self.read_bit_meas.values() for meas in meas_list]
def create_write_bit_measures(self): def create_write_bit_measures(self):
""" Adds bit measurements for write0 and write1 cycles """ """ Adds bit measurements for write0 and write1 cycles """
self.bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]} self.write_bit_meas = {bit_polarity.NONINVERTING:[], bit_polarity.INVERTING:[]}
meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE) meas_cycles = (sram_op.WRITE_ZERO, sram_op.WRITE_ONE)
for cycle in meas_cycles: for cycle in meas_cycles:
meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name) meas_tag = "a{}_b{}_{}".format(self.probe_address, self.probe_data, cycle.name)
single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data) single_bit_meas = self.get_bit_measures(meas_tag, self.probe_address, self.probe_data)
for polarity,meas in single_bit_meas.items(): for polarity,meas in single_bit_meas.items():
meas.meta_str = cycle meas.meta_str = cycle
self.bit_meas[polarity].append(meas) self.write_bit_meas[polarity].append(meas)
# Dictionary values are lists, reduce to a single list of measurements # Dictionary values are lists, reduce to a single list of measurements
return [meas for meas_list in self.bit_meas.values() for meas in meas_list] return [meas for meas_list in self.write_bit_meas.values() for meas in meas_list]
def get_bit_measures(self, meas_tag, probe_address, probe_data): def get_bit_measures(self, meas_tag, probe_address, probe_data):
""" """
@ -649,8 +649,9 @@ class delay(simulation):
if (time_out <= 0): if (time_out <= 0):
debug.error("Timed out, could not find a feasible period.",2) debug.error("Timed out, could not find a feasible period.",2)
# Clear any write target ports and set read port # Write ports are assumed non-critical to timing, so the first available is used
self.targ_write_ports = [port] self.targ_write_ports = [self.write_ports[0]]
# Set target read port for simulation
self.targ_read_ports = [port] self.targ_read_ports = [port]
debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port)) debug.info(1, "Trying feasible period: {0}ns on Port {1}".format(feasible_period, port))
@ -733,7 +734,8 @@ class delay(simulation):
# First, check that the memory has the right values at the right times # First, check that the memory has the right values at the right times
if not self.check_bit_measures(): if not self.check_bit_measures(self.read_bit_meas) or \
not self.check_bit_measures(self.write_bit_meas):
return(False,{}) return(False,{})
for port in self.targ_write_ports: for port in self.targ_write_ports:
@ -824,13 +826,13 @@ class delay(simulation):
return dout_success return dout_success
def check_bit_measures(self): def check_bit_measures(self, bit_measures):
""" """
Checks the measurements which represent the internal storage voltages Checks the measurements which represent the internal storage voltages
at the end of the read cycle. at the end of the read cycle.
""" """
success = False success = False
for polarity, meas_list in self.bit_meas.items(): for polarity, meas_list in bit_measures.items():
for meas in meas_list: for meas in meas_list:
val = meas.retrieve_measure() val = meas.retrieve_measure()
debug.info(2,"{}={}".format(meas.name, val)) debug.info(2,"{}={}".format(meas.name, val))
@ -965,7 +967,8 @@ class delay(simulation):
# Binary search algorithm to find the min period (max frequency) of input port # Binary search algorithm to find the min period (max frequency) of input port
time_out = 25 time_out = 25
self.targ_write_ports = [port] # Write ports are assumed non-critical to timing, so the first available is used
self.targ_write_ports = [self.write_ports[0]]
self.targ_read_ports = [port] self.targ_read_ports = [port]
while True: while True:
time_out -= 1 time_out -= 1
@ -1253,8 +1256,8 @@ class delay(simulation):
""" """
# Using this requires setting at least one port to target for simulation. # Using this requires setting at least one port to target for simulation.
if len(self.targ_write_ports) == 0 and len(self.targ_read_ports) == 0: if len(self.targ_write_ports) == 0 or len(self.targ_read_ports) == 0:
debug.error("No port selected for characterization.",1) debug.error("Write and read port must be specified for characterization.",1)
self.set_stimulus_variables() self.set_stimulus_variables()
# Get any available read/write port in case only a single write or read ports is being characterized. # Get any available read/write port in case only a single write or read ports is being characterized.

View File

@ -81,17 +81,25 @@ class lib:
self.lib_files = [] self.lib_files = []
# Nominal corner # Nominal corner
self.add_corner(nom_process, nom_supply, nom_temperature) corner_set = set()
nom_corner = (nom_process, nom_supply, nom_temperature)
corner_set.add(nom_corner)
if not OPTS.nominal_corner_only: if not OPTS.nominal_corner_only:
# Temperature corners # Temperature corners
self.add_corner(nom_process, nom_supply, min_temperature) corner_set.add((nom_process, nom_supply, min_temperature))
self.add_corner(nom_process, nom_supply, max_temperature) corner_set.add((nom_process, nom_supply, max_temperature))
# Supply corners # Supply corners
self.add_corner(nom_process, min_supply, nom_temperature) corner_set.add((nom_process, min_supply, nom_temperature))
self.add_corner(nom_process, max_supply, nom_temperature) corner_set.add((nom_process, max_supply, nom_temperature))
# Process corners # Process corners
self.add_corner(min_process, nom_supply, nom_temperature) corner_set.add((min_process, nom_supply, nom_temperature))
self.add_corner(max_process, nom_supply, nom_temperature) corner_set.add((max_process, nom_supply, nom_temperature))
# Enforce that nominal corner is the first to be characterized
self.add_corner(*nom_corner)
corner_set.remove(nom_corner)
for corner_tuple in corner_set:
self.add_corner(*corner_tuple)
def add_corner(self, proc, volt, temp): def add_corner(self, proc, volt, temp):
self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name, self.corner_name = "{0}_{1}_{2}V_{3}C".format(self.sram.name,

View File

@ -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=""

View File

@ -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

View File

@ -647,7 +647,7 @@ class control_logic(design.design):
if self.port_type=="rw": if self.port_type=="rw":
input_name = "we_bar" input_name = "we_bar"
else: else:
input_name = "cs_bar" input_name = "cs"
# GATE FOR S_EN # GATE FOR S_EN
self.s_en_gate_inst = self.add_inst(name="buf_s_en_and", self.s_en_gate_inst = self.add_inst(name="buf_s_en_and",
mod=self.sen_and3) mod=self.sen_and3)
@ -670,7 +670,7 @@ class control_logic(design.design):
if self.port_type=="rw": if self.port_type=="rw":
input_name = "we_bar" input_name = "we_bar"
else: else:
input_name = "cs_bar" input_name = "cs"
sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name]) sen_map = zip(["A", "B", "C"], ["rbl_bl_delay", "gated_clk_bar", input_name])
self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets) self.connect_vertical_bus(sen_map, self.s_en_gate_inst, self.rail_offsets)

View File

@ -8,6 +8,7 @@ from tech import drc, parameter
import debug import debug
import design import design
from sram_factory import factory from sram_factory import factory
from collections import namedtuple
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -46,7 +47,19 @@ class port_data(design.design):
# br lines are connect from the precharger # br lines are connect from the precharger
return self.precharge.get_br_names() return self.precharge.get_br_names()
def get_bl_name(self, port=0):
bl_name = "bl"
if len(self.all_ports) == 1:
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0):
br_name = "br"
if len(self.all_ports) == 1:
return br_name
else:
return br_name + "{}".format(port)
def create_netlist(self): def create_netlist(self):
self.precompute_constants() self.precompute_constants()
@ -94,8 +107,8 @@ class port_data(design.design):
self.add_pin("rbl_bl","INOUT") self.add_pin("rbl_bl","INOUT")
self.add_pin("rbl_br","INOUT") self.add_pin("rbl_br","INOUT")
for bit in range(self.num_cols): for bit in range(self.num_cols):
bl_name = self.precharge_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.precharge_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
self.add_pin("{0}_{1}".format(bl_name, bit),"INOUT") self.add_pin("{0}_{1}".format(bl_name, bit),"INOUT")
self.add_pin("{0}_{1}".format(br_name, bit),"INOUT") self.add_pin("{0}_{1}".format(br_name, bit),"INOUT")
if self.port in self.read_ports: if self.port in self.read_ports:
@ -253,8 +266,8 @@ class port_data(design.design):
self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port),
mod=self.precharge_array) mod=self.precharge_array)
bl_name = self.precharge_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.precharge_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
# Use left BLs for RBL # Use left BLs for RBL
@ -285,8 +298,8 @@ class port_data(design.design):
self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port), self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port),
mod=self.column_mux_array) mod=self.column_mux_array)
bl_name = self.column_mux_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.column_mux_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for col in range(self.num_cols): for col in range(self.num_cols):
temp.append("{0}_{1}".format(bl_name, col)) temp.append("{0}_{1}".format(bl_name, col))
@ -315,8 +328,8 @@ class port_data(design.design):
self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port), self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port),
mod=self.sense_amp_array) mod=self.sense_amp_array)
bl_name = self.sense_amp_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.sense_amp_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
temp.append("dout_{}".format(bit)) temp.append("dout_{}".format(bit))
@ -341,8 +354,8 @@ class port_data(design.design):
""" Creating Write Driver """ """ Creating Write Driver """
self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port), self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port),
mod=self.write_driver_array) mod=self.write_driver_array)
bl_name = self.write_driver_array.get_bl_name(self.port) bl_name = self.get_bl_name(self.port)
br_name = self.write_driver_array.get_br_name(self.port) br_name = self.get_br_name(self.port)
temp = [] temp = []
for bit in range(self.word_size): for bit in range(self.word_size):
@ -523,13 +536,16 @@ class port_data(design.design):
# Only do this if we have a column mux! # Only do this if we have a column mux!
if self.col_addr_size==0: if self.col_addr_size==0:
return return
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst2 = self.precharge_array_inst inst2 = self.precharge_array_inst
if self.port==0:
self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1) insn2_start_bit = 1 if self.port == 0 else 0
else:
self.connect_bitlines(inst1, inst2, self.num_cols) self.connect_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.num_cols,
inst2_start_bit=insn2_start_bit)
def route_sense_amp_to_column_mux_or_precharge_array(self, port): def route_sense_amp_to_column_mux_or_precharge_array(self, port):
@ -539,46 +555,49 @@ class port_data(design.design):
if self.col_addr_size>0: if self.col_addr_size>0:
# Sense amp is connected to the col mux # Sense amp is connected to the col mux
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bls_templ = "{inst}_out_{bit}"
inst1_br_name = "br_out_{}"
start_bit = 0 start_bit = 0
else: else:
# Sense amp is directly connected to the precharge array # Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}" inst1_bls_templ="{inst}_{bit}"
inst1_br_name = "br_{}"
if self.port==0: if self.port==0:
start_bit=1 start_bit=1
else: else:
start_bit=0 start_bit=0
self.channel_route_bitlines(inst1=inst1,
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, inst1_bls_template=inst1_bls_templ,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) inst2=inst2,
num_bits=self.word_size,
inst1_start_bit=start_bit)
def route_write_driver_to_column_mux_or_precharge_array(self, port): def route_write_driver_to_column_mux_or_precharge_array(self, port):
""" Routing of BL and BR between sense_amp and column mux or precharge array """ """ Routing of BL and BR between sense_amp and column mux or precharge array """
inst2 = self.write_driver_array_inst inst2 = self.write_driver_array_inst
inst2_bl_name = inst2.mod.get_bl_name()
inst2_br_name = inst2.mod.get_br_name()
if self.col_addr_size>0: if self.col_addr_size>0:
# Write driver is connected to the col mux # Write driver is connected to the col mux
inst1 = self.column_mux_array_inst inst1 = self.column_mux_array_inst
inst1_bl_name = "bl_out_{}" inst1_bls_templ = "{inst}_out_{bit}"
inst1_br_name = "br_out_{}"
start_bit = 0 start_bit = 0
else: else:
# Sense amp is directly connected to the precharge array # Sense amp is directly connected to the precharge array
inst1 = self.precharge_array_inst inst1 = self.precharge_array_inst
inst1_bl_name = "bl_{}" inst1_bls_templ="{inst}_{bit}"
inst1_br_name = "br_{}"
if self.port==0: if self.port==0:
start_bit=1 start_bit=1
else: else:
start_bit=0 start_bit=0
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, self.channel_route_bitlines(inst1=inst1, inst2=inst2,
inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) num_bits=self.word_size,
inst1_bls_template=inst1_bls_templ,
inst1_start_bit=start_bit)
def route_write_driver_to_sense_amp(self, port): def route_write_driver_to_sense_amp(self, port):
@ -589,7 +608,9 @@ class port_data(design.design):
# These should be pitch matched in the cell library, # These should be pitch matched in the cell library,
# but just in case, do a channel route. # but just in case, do a channel route.
self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) self.channel_route_bitlines(inst1=inst1,
inst2=inst2,
num_bits=self.word_size)
def route_bitline_pins(self): def route_bitline_pins(self):
@ -635,64 +656,108 @@ class port_data(design.design):
if self.write_mask_and_array_inst: if self.write_mask_and_array_inst:
self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en") self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en")
def channel_route_bitlines(self, inst1, inst2, num_bits, def _group_bitline_instances(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, inst1_bls_template,
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): inst1_start_bit,
inst2_bls_template,
inst2_start_bit):
""" """
Route the bl and br of two modules using the channel router. Groups all the parameters into a named tuple and seperates them into
top and bottom instances.
""" """
inst_group = namedtuple('InstanceGroup', ('inst', 'bls_template',
'bl_name', 'br_name', 'start_bit'))
inst1_group = inst_group(inst1, inst1_bls_template,
inst1.mod.get_bl_name(),
inst1.mod.get_br_name(),
inst1_start_bit)
inst2_group = inst_group(inst2, inst2_bls_template,
inst2.mod.get_bl_name(),
inst2.mod.get_br_name(),
inst2_start_bit)
# determine top and bottom automatically. # determine top and bottom automatically.
# since they don't overlap, we can just check the bottom y coordinate. # since they don't overlap, we can just check the bottom y coordinate.
if inst1.by() < inst2.by(): if inst1.by() < inst2.by():
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) bot_inst_group = inst1_group
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) top_inst_group = inst2_group
else: else:
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) bot_inst_group = inst2_group
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) top_inst_group = inst1_group
return (bot_inst_group, top_inst_group)
def _get_bitline_pins(self, inst_group, bit):
"""
Extracts bl/br pins from an InstanceGroup based on the bit modifier.
"""
full_bl_name = inst_group.bls_template.format(
**{'inst' : inst_group.bl_name,
'bit' : inst_group.start_bit + bit}
)
full_br_name = inst_group.bls_template.format(
**{'inst' : inst_group.br_name,
'bit' : inst_group.start_bit + bit}
)
return (inst_group.inst.get_pin(full_bl_name),
inst_group.inst.get_pin(full_br_name))
def channel_route_bitlines(self, inst1, inst2, num_bits,
inst1_bls_template="{inst}_{bit}",
inst1_start_bit=0,
inst2_bls_template="{inst}_{bit}",
inst2_start_bit=0):
"""
Route the bl and br of two modules using the channel router.
"""
bot_inst_group, top_inst_group = self._group_bitline_instances(
inst1, inst2, num_bits,
inst1_bls_template, inst1_start_bit,
inst2_bls_template, inst2_start_bit)
# Channel route each mux separately since we don't minimize the number # Channel route each mux separately since we don't minimize the number
# of tracks in teh channel router yet. If we did, we could route all the bits at once! # of tracks in teh channel router yet. If we did, we could route all the bits at once!
offset = bottom_inst.ul() + vector(0,self.m1_pitch) offset = bot_inst_group.inst.ul() + vector(0,self.m1_pitch)
for bit in range(num_bits): for bit in range(num_bits):
bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))] bottom_names = self._get_bitline_pins(bot_inst_group, bit)
top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))] top_names = self._get_bitline_pins(top_inst_group, bit)
route_map = list(zip(bottom_names, top_names)) route_map = list(zip(bottom_names, top_names))
self.create_horizontal_channel_route(route_map, offset, self.m1_stack) self.create_horizontal_channel_route(route_map, offset, self.m1_stack)
def connect_bitlines(self, inst1, inst2, num_bits, def connect_bitlines(self, inst1, inst2, num_bits,
inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, inst1_bls_template="{inst}_{bit}",
inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): inst1_start_bit=0,
inst2_bls_template="{inst}_{bit}",
inst2_start_bit=0):
""" """
Connect the bl and br of two modules. Connect the bl and br of two modules.
This assumes that they have sufficient space to create a jog This assumes that they have sufficient space to create a jog
in the middle between the two modules (if needed). in the middle between the two modules (if needed).
""" """
# determine top and bottom automatically. bot_inst_group, top_inst_group = self._group_bitline_instances(
# since they don't overlap, we can just check the bottom y coordinate. inst1, inst2, num_bits,
if inst1.by() < inst2.by(): inst1_bls_template, inst1_start_bit,
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) inst2_bls_template, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) bottom_inst = bot_inst_group.inst
else: top_inst = top_inst_group.inst
(bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit)
(top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit)
for col in range(num_bits): for col in range(num_bits):
bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc() bot_bl_pin, bot_br_pin = self._get_bitline_pins(bot_inst_group, col)
bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc() top_bl_pin, top_br_pin = self._get_bitline_pins(top_inst_group, col)
top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc() bot_bl, bot_br = bot_bl_pin.uc(), bot_br_pin.uc()
top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc() top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc()
yoffset = 0.5*(top_bl.y+bottom_bl.y) yoffset = 0.5*(top_bl.y+bot_bl.y)
self.add_path("m2",[bottom_bl, vector(bottom_bl.x,yoffset), self.add_path("m2",[bot_bl, vector(bot_bl.x,yoffset),
vector(top_bl.x,yoffset), top_bl]) vector(top_bl.x,yoffset), top_bl])
self.add_path("m2",[bottom_br, vector(bottom_br.x,yoffset), self.add_path("m2",[bot_br, vector(bot_br.x,yoffset),
vector(top_br.x,yoffset), top_br]) vector(top_br.x,yoffset), top_br])
def graph_exclude_precharge(self): def graph_exclude_precharge(self):

View File

@ -32,20 +32,13 @@ class precharge_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.pc_cell.get_bl_names() bl_name = self.pc_cell.get_bl_names()
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self):
br_name = self.pc_cell.get_br_names() br_name = self.pc_cell.get_br_names()
if len(self.all_ports) == 1: return br_name
return br_name
else:
return br_name + "{}".format(port)
def add_pins(self): def add_pins(self):
"""Adds pins for spice file""" """Adds pins for spice file"""

View File

@ -9,6 +9,7 @@ import design
import debug import debug
import utils import utils
from tech import GDS,layer, parameter,drc from tech import GDS,layer, parameter,drc
from tech import cell_properties as props
from globals import OPTS from globals import OPTS
import logical_effort import logical_effort
@ -19,8 +20,12 @@ class sense_amp(design.design):
the technology library. the technology library.
Sense amplifier to read a pair of bit-lines. Sense amplifier to read a pair of bit-lines.
""" """
pin_names = [props.sense_amp.pin.bl,
pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"] props.sense_amp.pin.br,
props.sense_amp.pin.dout,
props.sense_amp.pin.en,
props.sense_amp.pin.vdd,
props.sense_amp.pin.gnd]
type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
(width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"])
@ -30,10 +35,18 @@ class sense_amp(design.design):
pin_map = [] pin_map = []
def get_bl_names(self): def get_bl_names(self):
return "bl" return props.sense_amp.pin.bl
def get_br_names(self): def get_br_names(self):
return "br" return props.sense_amp.pin.br
@property
def dout_name(self):
return props.sense_amp.pin.dout
@property
def en_name(self):
return props.sense_amp.pin.en
def __init__(self, name): def __init__(self, name):
design.design.__init__(self, name) design.design.__init__(self, name)
@ -79,11 +92,10 @@ class sense_amp(design.design):
def get_enable_name(self): def get_enable_name(self):
"""Returns name used for enable net""" """Returns name used for enable net"""
#FIXME: A better programmatic solution to designate pins #FIXME: A better programmatic solution to designate pins
enable_name = "en" enable_name = self.en_name
debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name)) debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name))
return enable_name return enable_name
def build_graph(self, graph, inst_name, port_nets): def build_graph(self, graph, inst_name, port_nets):
"""Adds edges based on inputs/outputs. Overrides base class function.""" """Adds edges based on inputs/outputs. Overrides base class function."""
self.add_graph_edges(graph, port_nets) self.add_graph_edges(graph, port_nets)

View File

@ -33,20 +33,21 @@ class sense_amp_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self):
bl_name = "bl"
return bl_name
def get_bl_name(self, port=0): def get_br_name(self):
bl_name = self.amp.get_bl_names() br_name = "br"
if len(self.all_ports) == 1: return br_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): @property
br_name = self.amp.get_br_names() def data_name(self):
if len(self.all_ports) == 1: return "data"
return br_name
else: @property
return br_name + "{}".format(port) def en_name(self):
return "en"
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
@ -69,10 +70,10 @@ class sense_amp_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(0,self.word_size): for i in range(0,self.word_size):
self.add_pin("data_{0}".format(i), "OUTPUT") self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT")
self.add_pin("bl_{0}".format(i), "INPUT") self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT")
self.add_pin("br_{0}".format(i), "INPUT") self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT")
self.add_pin("en", "INPUT") self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -92,10 +93,10 @@ class sense_amp_array(design.design):
name = "sa_d{0}".format(i) name = "sa_d{0}".format(i)
self.local_insts.append(self.add_inst(name=name, self.local_insts.append(self.add_inst(name=name,
mod=self.amp)) mod=self.amp))
self.connect_inst(["bl_{0}".format(i), self.connect_inst([self.get_bl_name() + "_{0}".format(i),
"br_{0}".format(i), self.get_br_name() + "_{0}".format(i),
"data_{0}".format(i), self.data_name + "_{0}".format(i),
"en", "vdd", "gnd"]) self.en_name, "vdd", "gnd"])
def place_sense_amp_array(self): def place_sense_amp_array(self):
from tech import cell_properties from tech import cell_properties
@ -135,22 +136,22 @@ class sense_amp_array(design.design):
start_layer="m2", start_layer="m2",
vertical=True) vertical=True)
bl_pin = inst.get_pin("bl") bl_pin = inst.get_pin(inst.mod.get_bl_names())
br_pin = inst.get_pin("br") br_pin = inst.get_pin(inst.mod.get_br_names())
dout_pin = inst.get_pin("dout") dout_pin = inst.get_pin(inst.mod.dout_name)
self.add_layout_pin(text="bl_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
self.add_layout_pin(text="br_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
height=br_pin.height()) height=br_pin.height())
self.add_layout_pin(text="data_{0}".format(i), self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer="m2",
offset=dout_pin.ll(), offset=dout_pin.ll(),
width=dout_pin.width(), width=dout_pin.width(),
@ -159,8 +160,8 @@ class sense_amp_array(design.design):
def route_rails(self): def route_rails(self):
# add sclk rail across entire array # add sclk rail across entire array
sclk_offset = self.amp.get_pin("en").ll().scale(0,1) sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0,1)
self.add_layout_pin(text="en", self.add_layout_pin(text=self.en_name,
layer="m1", layer="m1",
offset=sclk_offset, offset=sclk_offset,
width=self.width, width=self.width,

View File

@ -37,20 +37,13 @@ class single_level_column_mux_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.mux.get_bl_names() bl_name = self.mux.get_bl_names()
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self, port=0):
br_name = self.mux.get_br_names() br_name = self.mux.get_br_names()
if len(self.all_ports) == 1: return br_name
return br_name
else:
return br_name + "{}".format(port)
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()

View File

@ -10,6 +10,7 @@ import design
import utils import utils
from globals import OPTS from globals import OPTS
from tech import GDS,layer from tech import GDS,layer
from tech import cell_properties as props
class write_driver(design.design): class write_driver(design.design):
""" """
@ -19,7 +20,13 @@ class write_driver(design.design):
the technology library. the technology library.
""" """
pin_names = ["din", "bl", "br", "en", "vdd", "gnd"] pin_names = [props.write_driver.pin.din,
props.write_driver.pin.bl,
props.write_driver.pin.br,
props.write_driver.pin.en,
props.write_driver.pin.vdd,
props.write_driver.pin.gnd]
type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"]
if not OPTS.netlist_only: if not OPTS.netlist_only:
(width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"]) (width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"])
@ -38,10 +45,18 @@ class write_driver(design.design):
self.add_pin_types(self.type_list) self.add_pin_types(self.type_list)
def get_bl_names(self): def get_bl_names(self):
return "bl" return props.write_driver.pin.bl
def get_br_names(self): def get_br_names(self):
return "br" return props.write_driver.pin.br
@property
def din_name(self):
return props.write_driver.pin.din
@property
def en_name(self):
return props.write_driver.pin.en
def get_w_en_cin(self): def get_w_en_cin(self):
"""Get the relative capacitance of a single input""" """Get the relative capacitance of a single input"""

View File

@ -37,19 +37,21 @@ class write_driver_array(design.design):
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
def get_bl_name(self, port=0): def get_bl_name(self):
bl_name = self.driver.get_bl_names() bl_name = "bl"
if len(self.all_ports) == 1: return bl_name
return bl_name
else:
return bl_name + "{}".format(port)
def get_br_name(self, port=0): def get_br_name(self):
br_name = self.driver.get_br_names() br_name = "br"
if len(self.all_ports) == 1: return br_name
return br_name
else: @property
return br_name + "{}".format(port) def data_name(self):
return "data"
@property
def en_name(self):
return "en"
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
@ -71,15 +73,15 @@ class write_driver_array(design.design):
def add_pins(self): def add_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("data_{0}".format(i), "INPUT") self.add_pin(self.data_name + "_{0}".format(i), "INPUT")
for i in range(self.word_size): for i in range(self.word_size):
self.add_pin("bl_{0}".format(i), "OUTPUT") self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT")
self.add_pin("br_{0}".format(i), "OUTPUT") self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT")
if self.write_size: if self.write_size:
for i in range(self.num_wmasks): for i in range(self.num_wmasks):
self.add_pin("en_{0}".format(i), "INPUT") self.add_pin(self.en_name + "_{0}".format(i), "INPUT")
else: else:
self.add_pin("en", "INPUT") self.add_pin(self.en_name, "INPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
@ -102,20 +104,20 @@ class write_driver_array(design.design):
mod=self.driver) mod=self.driver)
if self.write_size: if self.write_size:
self.connect_inst(["data_{0}".format(index), self.connect_inst([self.data_name + "_{0}".format(index),
"bl_{0}".format(index), self.get_bl_name() + "_{0}".format(index),
"br_{0}".format(index), self.get_br_name() + "_{0}".format(index),
"en_{0}".format(windex), "vdd", "gnd"]) self.en_name + "_{0}".format(windex), "vdd", "gnd"])
w+=1 w+=1
# when w equals write size, the next en pin can be connected since we are now at the next wmask bit # when w equals write size, the next en pin can be connected since we are now at the next wmask bit
if w == self.write_size: if w == self.write_size:
w = 0 w = 0
windex+=1 windex+=1
else: else:
self.connect_inst(["data_{0}".format(index), self.connect_inst([self.data_name + "_{0}".format(index),
"bl_{0}".format(index), self.get_bl_name() + "_{0}".format(index),
"br_{0}".format(index), self.get_br_name() + "_{0}".format(index),
"en", "vdd", "gnd"]) self.en_name, "vdd", "gnd"])
def place_write_array(self): def place_write_array(self):
@ -140,21 +142,22 @@ class write_driver_array(design.design):
def add_layout_pins(self): def add_layout_pins(self):
for i in range(self.word_size): for i in range(self.word_size):
din_pin = self.driver_insts[i].get_pin("din") inst = self.driver_insts[i]
self.add_layout_pin(text="data_{0}".format(i), din_pin = inst.get_pin(inst.mod.din_name)
self.add_layout_pin(text=self.data_name + "_{0}".format(i),
layer="m2", layer="m2",
offset=din_pin.ll(), offset=din_pin.ll(),
width=din_pin.width(), width=din_pin.width(),
height=din_pin.height()) height=din_pin.height())
bl_pin = self.driver_insts[i].get_pin("bl") bl_pin = inst.get_pin(inst.mod.get_bl_names())
self.add_layout_pin(text="bl_{0}".format(i), self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=bl_pin.width(), width=bl_pin.width(),
height=bl_pin.height()) height=bl_pin.height())
br_pin = self.driver_insts[i].get_pin("br") br_pin = inst.get_pin(inst.mod.get_br_names())
self.add_layout_pin(text="br_{0}".format(i), self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i),
layer="m2", layer="m2",
offset=br_pin.ll(), offset=br_pin.ll(),
width=br_pin.width(), width=br_pin.width(),
@ -169,7 +172,8 @@ class write_driver_array(design.design):
start_layer = "m2") start_layer = "m2")
if self.write_size: if self.write_size:
for bit in range(self.num_wmasks): for bit in range(self.num_wmasks):
en_pin = self.driver_insts[bit*self.write_size].get_pin("en") inst = self.driver_insts[bit*self.write_size]
en_pin = inst.get_pin(inst.mod.en_name)
# Determine width of wmask modified en_pin with/without col mux # Determine width of wmask modified en_pin with/without col mux
wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing) wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing)
if (self.words_per_row == 1): if (self.words_per_row == 1):
@ -177,15 +181,16 @@ class write_driver_array(design.design):
else: else:
en_gap = self.driver_spacing en_gap = self.driver_spacing
self.add_layout_pin(text="en_{0}".format(bit), self.add_layout_pin(text=self.en_name + "_{0}".format(bit),
layer=en_pin.layer, layer=en_pin.layer,
offset=en_pin.ll(), offset=en_pin.ll(),
width=wmask_en_len-en_gap, width=wmask_en_len-en_gap,
height=en_pin.height()) height=en_pin.height())
else: else:
self.add_layout_pin(text="en", inst = self.driver_insts[0]
self.add_layout_pin(text=self.en_name,
layer="m1", layer="m1",
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1),
width=self.width) width=self.width)