Merge branch 'dev' into automated_analytical_model

This commit is contained in:
Hunter Nichols 2021-05-26 18:42:24 -07:00
commit b3bcf48d2e
14 changed files with 386 additions and 116 deletions

View File

@ -1161,6 +1161,8 @@ class layout():
height=ur.y - ll.y,
width=ur.x - ll.x)
self.bbox = [self.bounding_box.ll(), self.bounding_box.ur()]
def add_enclosure(self, insts, layer="nwell", extend=0, leftx=None, rightx=None, topy=None, boty=None):
"""
Add a layer that surrounds the given instances. Useful
@ -1341,7 +1343,182 @@ class layout():
layer=layer,
offset=peri_pin_loc)
def add_power_ring(self, bbox):
def add_dnwell(self, bbox=None, inflate=1):
""" Create a dnwell, along with nwell moat at border. """
if "dnwell" not in techlayer:
return
if not bbox:
bbox = [self.find_lowest_coords(),
self.find_highest_coords()]
# Find the corners
[ll, ur] = bbox
# Possibly inflate the bbox
nwell_offset = vector(self.nwell_width, self.nwell_width)
ll -= nwell_offset.scale(inflate, inflate)
ur += nwell_offset.scale(inflate, inflate)
# Other corners
ul = vector(ll.x, ur.y)
lr = vector(ur.x, ll.y)
# Add the dnwell
self.add_rect("dnwell",
offset=ll,
height=ur.y - ll.y,
width=ur.x - ll.x)
# Add the moat
self.add_path("nwell", [ll, lr, ur, ul, ll - vector(0, 0.5 * self.nwell_width)])
# Add the taps
layer_stack = self.active_stack
tap_spacing = 2
nwell_offset = vector(self.nwell_width, self.nwell_width)
# Every nth tap is connected to gnd
period = 5
# BOTTOM
count = 0
loc = ll + nwell_offset.scale(tap_spacing, 0)
end_loc = lr - nwell_offset.scale(tap_spacing, 0)
while loc.x < end_loc.x:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
if count % period:
self.add_via_stack_center(from_layer="li",
to_layer="m1",
offset=loc)
else:
self.add_power_pin(name="gnd",
loc=loc,
start_layer="li")
count += 1
loc += nwell_offset.scale(tap_spacing, 0)
# TOP
count = 0
loc = ul + nwell_offset.scale(tap_spacing, 0)
end_loc = ur - nwell_offset.scale(tap_spacing, 0)
while loc.x < end_loc.x:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
if count % period:
self.add_via_stack_center(from_layer="li",
to_layer="m1",
offset=loc)
else:
self.add_power_pin(name="gnd",
loc=loc,
start_layer="li")
count += 1
loc += nwell_offset.scale(tap_spacing, 0)
# LEFT
count = 0
loc = ll + nwell_offset.scale(0, tap_spacing)
end_loc = ul - nwell_offset.scale(0, tap_spacing)
while loc.y < end_loc.y:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
if count % period:
self.add_via_stack_center(from_layer="li",
to_layer="m2",
offset=loc)
else:
self.add_power_pin(name="gnd",
loc=loc,
start_layer="li")
count += 1
loc += nwell_offset.scale(0, tap_spacing)
# RIGHT
count = 0
loc = lr + nwell_offset.scale(0, tap_spacing)
end_loc = ur - nwell_offset.scale(0, tap_spacing)
while loc.y < end_loc.y:
self.add_via_center(layers=layer_stack,
offset=loc,
implant_type="n",
well_type="n")
if count % period:
self.add_via_stack_center(from_layer="li",
to_layer="m2",
offset=loc)
else:
self.add_power_pin(name="gnd",
loc=loc,
start_layer="li")
count += 1
loc += nwell_offset.scale(0, tap_spacing)
# Add the gnd ring
self.add_ring([ll, ur])
def add_ring(self, bbox=None, width_mult=8, offset=0):
"""
Add a ring around the bbox
"""
# Ring size/space/pitch
wire_width = self.m2_width * width_mult
half_width = 0.5 * wire_width
wire_space = self.m2_space
wire_pitch = wire_width + wire_space
# Find the corners
if not bbox:
bbox = [self.find_lowest_coords(),
self.find_highest_coords()]
[ll, ur] = bbox
ul = vector(ll.x, ur.y)
lr = vector(ur.x, ll.y)
ll += vector(-offset * wire_pitch,
-offset * wire_pitch)
lr += vector(offset * wire_pitch,
-offset * wire_pitch)
ur += vector(offset * wire_pitch,
offset * wire_pitch)
ul += vector(-offset * wire_pitch,
offset * wire_pitch)
half_offset = vector(half_width, half_width)
self.add_path("m1", [ll - half_offset.scale(1, 0), lr + half_offset.scale(1, 0)], width=wire_width)
self.add_path("m1", [ul - half_offset.scale(1, 0), ur + half_offset.scale(1, 0)], width=wire_width)
self.add_path("m2", [ll - half_offset.scale(0, 1), ul + half_offset.scale(0, 1)], width=wire_width)
self.add_path("m2", [lr - half_offset.scale(0, 1), ur + half_offset.scale(0, 1)], width=wire_width)
# Find the number of vias for this pitch
supply_vias = 1
from sram_factory import factory
while True:
c = factory.create(module_type="contact",
layer_stack=self.m1_stack,
dimensions=(supply_vias, supply_vias))
if c.second_layer_width < wire_width and c.second_layer_height < wire_width:
supply_vias += 1
else:
supply_vias -= 1
break
via_points = [ll, lr, ur, ul]
for pt in via_points:
self.add_via_center(layers=self.m1_stack,
offset=pt,
size=(supply_vias,
supply_vias))
def add_power_ring(self):
"""
Create vdd and gnd power rings around an area of the bounding box
argument. Must have a supply_rail_width and supply_rail_pitch
@ -1350,7 +1527,7 @@ class layout():
modules..
"""
[ll, ur] = bbox
[ll, ur] = self.bbox
supply_rail_spacing = self.supply_rail_pitch - self.supply_rail_width
height = (ur.y - ll.y) + 3 * self.supply_rail_pitch - supply_rail_spacing

View File

@ -110,24 +110,25 @@ class lef:
# For each pin, remove the blockage and add the pin
for pin_name in self.pins:
pin = self.get_pin(pin_name)
inflated_pin = pin.inflated_pin(multiple=1)
another_iteration_needed = True
while another_iteration_needed:
another_iteration_needed = False
old_blockages = list(self.blockages[pin.layer])
for blockage in old_blockages:
if blockage.overlaps(inflated_pin):
intersection_shape = blockage.intersection(inflated_pin)
# If it is zero area, don't add the pin
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
continue
another_iteration_needed = True
# Remove the old blockage and add the new ones
self.blockages[pin.layer].remove(blockage)
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages)
pins = self.get_pins(pin_name)
for pin in pins:
inflated_pin = pin.inflated_pin(multiple=1)
another_iteration_needed = True
while another_iteration_needed:
another_iteration_needed = False
old_blockages = list(self.blockages[pin.layer])
for blockage in old_blockages:
if blockage.overlaps(inflated_pin):
intersection_shape = blockage.intersection(inflated_pin)
# If it is zero area, don't add the pin
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
continue
another_iteration_needed = True
# Remove the old blockage and add the new ones
self.blockages[pin.layer].remove(blockage)
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages)
def lef_write_header(self):
""" Header of LEF file """

View File

@ -6,6 +6,7 @@
# All rights reserved.
#
import math
from tech import spice
class verilog:
@ -28,10 +29,19 @@ class verilog:
else:
self.vf.write("\n")
try:
self.vdd_name = spice["power"]
except KeyError:
self.vdd_name = "vdd"
try:
self.gnd_name = spice["ground"]
except KeyError:
self.gnd_name = "gnd"
self.vf.write("module {0}(\n".format(self.name))
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" vdd,\n")
self.vf.write(" gnd,\n")
self.vf.write(" {},\n".format(self.vdd_name))
self.vf.write(" {},\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:
@ -71,8 +81,8 @@ class verilog:
self.vf.write("\n")
self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" inout vdd;\n")
self.vf.write(" inout gnd;\n")
self.vf.write(" inout {};\n".format(self.vdd_name))
self.vf.write(" inout {};\n".format(self.gnd_name))
self.vf.write("`endif\n")
for port in self.all_ports:

View File

@ -15,6 +15,7 @@ from .charutils import *
import tech
import numpy as np
from globals import OPTS
from tech import spice
class lib:
@ -22,6 +23,15 @@ class lib:
def __init__(self, out_dir, sram, sp_file, use_model=OPTS.analytical_delay):
try:
self.vdd_name = spice["power"]
except KeyError:
self.vdd_name = "vdd"
try:
self.gnd_name = spice["ground"]
except KeyError:
self.gnd_name = "gnd"
self.out_dir = out_dir
self.sram = sram
self.sp_file = sp_file
@ -274,8 +284,8 @@ class lib:
self.lib.write(" default_max_fanout : 4.0 ;\n")
self.lib.write(" default_connection_class : universal ;\n\n")
self.lib.write(" voltage_map ( VDD, {} );\n".format(self.voltage))
self.lib.write(" voltage_map ( GND, 0 );\n\n")
self.lib.write(" voltage_map ( {0}, {1} );\n".format(self.vdd_name.upper(), self.voltage))
self.lib.write(" voltage_map ( {0}, 0 );\n\n".format(self.gnd_name.upper()))
def create_list(self,values):
""" Helper function to create quoted, line wrapped list """
@ -607,12 +617,12 @@ class lib:
self.lib.write(" }\n")
def write_pg_pin(self):
self.lib.write(" pg_pin(vdd) {\n")
self.lib.write(" voltage_name : VDD;\n")
self.lib.write(" pg_pin({0}) ".format(self.vdd_name) + "{\n")
self.lib.write(" voltage_name : {};\n".format(self.vdd_name.upper()))
self.lib.write(" pg_type : primary_power;\n")
self.lib.write(" }\n\n")
self.lib.write(" pg_pin(gnd) {\n")
self.lib.write(" voltage_name : GND;\n")
self.lib.write(" pg_pin({0}) ".format(self.gnd_name) + "{\n")
self.lib.write(" voltage_name : {};\n".format(self.gnd_name.upper()))
self.lib.write(" pg_type : primary_ground;\n")
self.lib.write(" }\n\n")

View File

@ -22,7 +22,7 @@ from globals import OPTS
class stimuli():
""" Class for providing stimuli functions """
def __init__(self, stim_file, corner):
def __init__(self, stim_file, corner):
self.vdd_name = "vdd"
self.gnd_name = "gnd"
self.pmos_name = tech.spice["pmos"]

View File

@ -8,7 +8,7 @@ num_words = 1024
human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8)
# Allow byte writes
write_size = 8 # Bits
#write_size = 8 # Bits
# Dual port
num_rw_ports = 0

View File

@ -9,7 +9,8 @@ nominal_corner_only = True
# Local wordlines have issues with met3 power routing for now
#local_array_size = 16
#route_supplies = False
#route_supplies = "ring"
route_supplies = "left"
check_lvsdrc = True
#perimeter_pins = False
#netlist_only = True

View File

@ -613,8 +613,8 @@ def report_status():
# If write size is more than half of the word size,
# then it doesn't need a write mask. It would be writing
# the whole word.
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size/2):
debug.error("Write size needs to be between 1 bit and {0} bits/2.".format(OPTS.word_size))
if (OPTS.write_size < 1 or OPTS.write_size > OPTS.word_size / 2):
debug.error("Write size needs to be between 1 bit and {0} bits.".format(int(OPTS.word_size / 2)))
if not OPTS.tech_name:
debug.error("Tech name must be specified in config file.")

View File

@ -132,25 +132,25 @@ class grid:
# Add the left/right columns
if side=="all" or side=="left":
for x in range(self.ll.x + offset, self.ll.x + width + offset, 1):
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
for y in range(self.ll.y + offset + margin, self.ur.y - offset - margin, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
if side=="all" or side=="right":
for x in range(self.ur.x - width - offset, self.ur.x - offset, 1):
for y in range(self.ll.y + margin, self.ur.y - margin, 1):
for y in range(self.ll.y + offset + margin, self.ur.y - offset - margin, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
if side=="all" or side=="bottom":
for y in range(self.ll.y + offset, self.ll.y + width + offset, 1):
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
for x in range(self.ll.x + offset + margin, self.ur.x - offset - margin, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))
if side=="all" or side=="top":
for y in range(self.ur.y - width - offset, self.ur.y - offset, 1):
for x in range(self.ll.x + margin, self.ur.x - margin, 1):
for x in range(self.ll.x + offset + margin, self.ur.x - offset - margin, 1):
for layer in layers:
perimeter_list.append(vector3d(x, y, layer))

View File

@ -75,6 +75,9 @@ class router(router_tech):
self.margin = margin
self.init_bbox(bbox, margin)
# New pins if we create a ring or side pins or etc.
self.new_pins = {}
def init_bbox(self, bbox=None, margin=0):
"""
Initialize the ll,ur values with the paramter or using the layout boundary.
@ -895,20 +898,89 @@ class router(router_tech):
Adds a supply pin to the perimeter and resizes the bounding box.
"""
pg = pin_group(name, [], self)
if name == "vdd":
offset = width
if name == "gnd":
offset = width + 1
else:
offset = 0
offset = 1
if side in ["left", "right"]:
layers = [1]
else:
layers = [0]
pg.grids = set(self.rg.get_perimeter_list(side=side,
width=width,
margin=self.margin,
offset=offset,
layers=[1]))
layers=layers))
pg.enclosures = pg.compute_enclosures()
pg.pins = set(pg.enclosures)
debug.check(len(pg.pins)==1, "Too many pins for a side supply.")
self.cell.pin_map[name].update(pg.pins)
self.pin_groups[name].append(pg)
self.new_pins[name] = pg.pins
def add_ring_supply_pin(self, name, width=2):
"""
Adds a ring supply pin that goes inside the given bbox.
"""
pg = pin_group(name, [], self)
# Offset the vdd inside one ring width
# Units are in routing grids
if name == "gnd":
offset = width + 1
else:
offset = 1
# LEFT
left_grids = set(self.rg.get_perimeter_list(side="left",
width=width,
margin=self.margin,
offset=offset,
layers=[1]))
# RIGHT
right_grids = set(self.rg.get_perimeter_list(side="right",
width=width,
margin=self.margin,
offset=offset,
layers=[1]))
# TOP
top_grids = set(self.rg.get_perimeter_list(side="top",
width=width,
margin=self.margin,
offset=offset,
layers=[0]))
# BOTTOM
bottom_grids = set(self.rg.get_perimeter_list(side="bottom",
width=width,
margin=self.margin,
offset=offset,
layers=[0]))
horizontal_layer_grids = left_grids | right_grids
# Must move to the same layer to find layer 1 corner grids
vertical_layer_grids = set()
for x in top_grids | bottom_grids:
vertical_layer_grids.add(vector3d(x.x, x.y, 1))
# Add vias in the overlap points
horizontal_corner_grids = vertical_layer_grids & horizontal_layer_grids
for g in horizontal_corner_grids:
self.add_via(g)
# The big pin group, but exclude the corners from the pins
pg.grids = (left_grids | right_grids | top_grids | bottom_grids)
pg.enclosures = pg.compute_enclosures()
pg.pins = set(pg.enclosures)
self.cell.pin_map[name].update(pg.pins)
self.pin_groups[name].append(pg)
self.new_pins[name] = pg.pins
def get_new_pins(self, name):
return self.new_pins[name]
def add_perimeter_target(self, side="all"):
"""

View File

@ -21,7 +21,7 @@ class supply_tree_router(router):
routes a grid to connect the supply on the two layers.
"""
def __init__(self, layers, design, bbox=None, side_pin=None):
def __init__(self, layers, design, bbox=None, pin_type=None):
"""
This will route on layers in design. It will get the blockages from
either the gds file name or the design itself (by saving to a gds file).
@ -33,7 +33,10 @@ class supply_tree_router(router):
# The pin escape router already made the bounding box big enough,
# so we can use the regular bbox here.
self.side_pin = side_pin
if pin_type:
debug.check(pin_type in ["left", "right", "top", "bottom", "tree", "ring"],
"Invalid pin type {}".format(pin_type))
self.pin_type = pin_type
router.__init__(self,
layers,
design,
@ -65,10 +68,13 @@ class supply_tree_router(router):
print_time("Finding pins and blockages", datetime.now(), start_time, 3)
# Add side pins if enabled
if self.side_pin:
self.add_side_supply_pin(self.vdd_name)
self.add_side_supply_pin(self.gnd_name)
if self.pin_type in ["left", "right", "top", "bottom"]:
self.add_side_supply_pin(self.vdd_name, side=self.pin_type)
self.add_side_supply_pin(self.gnd_name, side=self.pin_type)
elif self.pin_type == "ring":
self.add_ring_supply_pin(self.vdd_name)
self.add_ring_supply_pin(self.gnd_name)
# Route the supply pins to the supply rails
# Route vdd first since we want it to be shorter
start_time = datetime.now()

View File

@ -5,9 +5,9 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import debug
import math
class vector3d():
"""
This is the vector3d class to represent a 3D coordinate.
@ -22,20 +22,20 @@ class vector3d():
self.x = x[0]
self.y = x[1]
self.z = x[2]
#will take inputs as the values of a coordinate
# will take inputs as the values of a coordinate
else:
self.x = x
self.y = y
self.z = z
self._hash = hash((self.x,self.y,self.z))
self._hash = hash((self.x, self.y, self.z))
def __str__(self):
""" override print function output """
return "v3d["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
return "v3d[" + str(self.x) + ", " + str(self.y) + ", " + str(self.z) + "]"
def __repr__(self):
""" override print function output """
return "v3d["+str(self.x)+", "+str(self.y)+", "+str(self.z)+"]"
return "v3d[" + str(self.x) + ", " + str(self.y) + ", " + str(self.z) + "]"
def __setitem__(self, index, value):
"""
@ -74,7 +74,6 @@ class vector3d():
"""
return vector3d(self.x + other[0], self.y + other[1], self.z + other[2])
def __radd__(self, other):
"""
Override + function (right add)
@ -98,7 +97,6 @@ class vector3d():
"""
return self._hash
def __rsub__(self, other):
"""
Override - function (right)
@ -107,7 +105,7 @@ class vector3d():
def rotate(self):
""" pass a copy of rotated vector3d, without altering the vector3d! """
return vector3d(self.y,self.x,self.z)
return vector3d(self.y, self.x, self.z)
def scale(self, x_factor, y_factor=None,z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
@ -115,7 +113,7 @@ class vector3d():
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.x*x_factor,self.y*y_factor,self.z*z_factor)
return vector3d(self.x * x_factor, self.y * y_factor, self.z * z_factor)
def rotate_scale(self, x_factor, y_factor=None, z_factor=None):
""" pass a copy of scaled vector3d, without altering the vector3d! """
@ -123,25 +121,25 @@ class vector3d():
z_factor=x_factor[2]
y_factor=x_factor[1]
x_factor=x_factor[0]
return vector3d(self.y*x_factor,self.x*y_factor,self.z*z_factor)
return vector3d(self.y * x_factor, self.x * y_factor, self.z * z_factor)
def floor(self):
"""
Override floor function
"""
return vector3d(int(math.floor(self.x)),int(math.floor(self.y)), self.z)
return vector3d(int(math.floor(self.x)), int(math.floor(self.y)), self.z)
def ceil(self):
"""
Override ceil function
"""
return vector3d(int(math.ceil(self.x)),int(math.ceil(self.y)), self.z)
return vector3d(int(math.ceil(self.x)), int(math.ceil(self.y)), self.z)
def round(self):
"""
Override round function
"""
return vector3d(int(round(self.x)),int(round(self.y)), self.z)
return vector3d(int(round(self.x)), int(round(self.y)), self.z)
def __eq__(self, other):
"""Override the default Equals behavior"""
@ -164,30 +162,29 @@ class vector3d():
def max(self, other):
""" Max of both values """
return vector3d(max(self.x,other.x),max(self.y,other.y),max(self.z,other.z))
return vector3d(max(self.x, other.x), max(self.y, other.y), max(self.z, other.z))
def min(self, other):
""" Min of both values """
return vector3d(min(self.x,other.x),min(self.y,other.y),min(self.z,other.z))
return vector3d(min(self.x, other.x), min(self.y, other.y), min(self.z, other.z))
def distance(self, other):
""" Return the manhattan distance between two values """
return abs(self.x-other.x)+abs(self.y-other.y)
return abs(self.x - other.x) + abs(self.y - other.y)
def euclidean_distance(self, other):
""" Return the euclidean distance between two values """
return math.sqrt((self.x-other.x)**2+(self.y-other.y)**2)
return math.sqrt((self.x - other.x)**2 + (self.y - other.y)**2)
def adjacent(self, other):
""" Is the one grid adjacent in any planar direction to the other """
if self == other + vector3d(1,0,0):
if self == other + vector3d(1, 0, 0):
return True
elif self == other + vector3d(-1,0,0):
elif self == other + vector3d(-1, 0, 0):
return True
elif self == other + vector3d(0,1,0):
elif self == other + vector3d(0, 1, 0):
return True
elif self == other + vector3d(0,-1,0):
elif self == other + vector3d(0, -1, 0):
return True
else:
return False

View File

@ -326,6 +326,9 @@ class sram_1bank(sram_base):
# they might create some blockages
self.add_layout_pins()
# Some technologies have an isolation
self.add_dnwell(inflate=2)
# Route the pins to the perimeter
if OPTS.perimeter_pins:
self.route_escape_pins()

View File

@ -15,6 +15,7 @@ from design import design
from verilog import verilog
from lef import lef
from sram_factory import factory
from tech import spice, layer
class sram_base(design, verilog, lef):
@ -81,8 +82,20 @@ class sram_base(design, verilog, lef):
for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
# Standard supply and ground names
try:
self.vdd_name = spice["power"]
except KeyError:
self.vdd_name = "vdd"
try:
self.gnd_name = spice["ground"]
except KeyError:
self.gnd_name = "gnd"
self.add_pin(self.vdd_name, "POWER")
self.add_pin(self.gnd_name, "GROUND")
self.ext_supplies = [self.vdd_name, self.gnd_name]
self.ext_supply = {"vdd" : self.vdd_name, "gnd" : self.gnd_name}
def add_global_pex_labels(self):
"""
@ -224,7 +237,7 @@ class sram_base(design, verilog, lef):
# This will either be used to route or left unconnected.
for pin_name in ["vdd", "gnd"]:
for inst in self.insts:
self.copy_power_pins(inst, pin_name)
self.copy_power_pins(inst, pin_name, self.ext_supply[pin_name])
try:
from tech import power_grid
@ -234,42 +247,21 @@ class sram_base(design, verilog, lef):
# Route a M3/M4 grid
grid_stack = self.m3_stack
# lowest_coord = self.find_lowest_coords()
# highest_coord = self.find_highest_coords()
# # Add two rails to the side
# if OPTS.route_supplies == "side":
# supply_pins = {}
# # Find the lowest leftest pin for vdd and gnd
# for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]:
# pin_width = 8 * getattr(self, "{}_width".format(grid_stack[2]))
# pin_space = 2 * getattr(self, "{}_space".format(grid_stack[2]))
# supply_pitch = pin_width + pin_space
# # Add side power rails on left from bottom to top
# # These have a temporary name and will be connected later.
# # They are here to reserve space now and ensure other pins go beyond
# # their perimeter.
# supply_height = highest_coord.y - lowest_coord.y
# supply_pins[pin_name] = self.add_layout_pin(text=pin_name,
# layer=grid_stack[2],
# offset=lowest_coord + vector(pin_index * supply_pitch, 0),
# width=pin_width,
# height=supply_height)
if not OPTS.route_supplies:
# Do not route the power supply (leave as must-connect pins)
return
elif OPTS.route_supplies == "grid":
from supply_grid_router import supply_grid_router as router
rtr=router(grid_stack, self)
else:
from supply_tree_router import supply_tree_router as router
rtr=router(grid_stack,
self,
pin_type=OPTS.route_supplies)
rtr=router(grid_stack, self, side_pin=(OPTS.route_supplies == "side"))
rtr.route()
if OPTS.route_supplies == "side":
if OPTS.route_supplies in ["left", "right", "top", "bottom", "ring"]:
# Find the lowest leftest pin for vdd and gnd
for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles
@ -282,13 +274,14 @@ class sram_base(design, verilog, lef):
# Remove the pin shape(s)
self.remove_layout_pin(pin_name)
# Get the lowest, leftest pin
pin = rtr.get_ll_pin(pin_name)
self.add_layout_pin(pin_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
# Get new pins
pins = rtr.get_new_pins(pin_name)
for pin in pins:
self.add_layout_pin(self.ext_supply[pin_name],
pin.layer,
pin.ll(),
pin.width(),
pin.height())
elif OPTS.route_supplies:
# Update these as we may have routed outside the region (perimeter pins)
@ -319,7 +312,7 @@ class sram_base(design, verilog, lef):
route_width,
pin.height())
self.add_layout_pin(pin_name,
self.add_layout_pin(self.ext_supply[pin_name],
pin.layer,
pin_offset,
pin_width,
@ -571,7 +564,7 @@ class sram_base(design, verilog, lef):
temp.append("bank_spare_wen{0}[{1}]".format(port, bit))
for port in self.all_ports:
temp.append("wl_en{0}".format(port))
temp.extend(["vdd", "gnd"])
temp.extend(self.ext_supplies)
self.connect_inst(temp)
return self.bank_insts[-1]
@ -620,7 +613,7 @@ class sram_base(design, verilog, lef):
inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size))
outputs.append("a{}[{}]".format(port, bit + self.col_addr_size))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
return insts
@ -638,7 +631,7 @@ class sram_base(design, verilog, lef):
inputs.append("addr{}[{}]".format(port, bit))
outputs.append("a{}[{}]".format(port, bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
return insts
@ -660,7 +653,7 @@ class sram_base(design, verilog, lef):
inputs.append("din{}[{}]".format(port, bit))
outputs.append("bank_din{}[{}]".format(port, bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
return insts
@ -682,7 +675,7 @@ class sram_base(design, verilog, lef):
inputs.append("wmask{}[{}]".format(port, bit))
outputs.append("bank_wmask{}[{}]".format(port, bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
return insts
@ -704,7 +697,7 @@ class sram_base(design, verilog, lef):
inputs.append("spare_wen{}[{}]".format(port, bit))
outputs.append("bank_spare_wen{}[{}]".format(port, bit))
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port), "vdd", "gnd"])
self.connect_inst(inputs + outputs + ["clk_buf{}".format(port)] + self.ext_supplies)
return insts
@ -735,7 +728,7 @@ class sram_base(design, verilog, lef):
if port in self.write_ports:
temp.append("w_en{}".format(port))
temp.append("p_en_bar{}".format(port))
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port), "vdd", "gnd"])
temp.extend(["wl_en{}".format(port), "clk_buf{}".format(port)] + self.ext_supplies)
self.connect_inst(temp)
return insts