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, height=ur.y - ll.y,
width=ur.x - ll.x) 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): 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 Add a layer that surrounds the given instances. Useful
@ -1341,7 +1343,182 @@ class layout():
layer=layer, layer=layer,
offset=peri_pin_loc) 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 Create vdd and gnd power rings around an area of the bounding box
argument. Must have a supply_rail_width and supply_rail_pitch argument. Must have a supply_rail_width and supply_rail_pitch
@ -1350,7 +1527,7 @@ class layout():
modules.. modules..
""" """
[ll, ur] = bbox [ll, ur] = self.bbox
supply_rail_spacing = self.supply_rail_pitch - self.supply_rail_width supply_rail_spacing = self.supply_rail_pitch - self.supply_rail_width
height = (ur.y - ll.y) + 3 * self.supply_rail_pitch - supply_rail_spacing 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 each pin, remove the blockage and add the pin
for pin_name in self.pins: for pin_name in self.pins:
pin = self.get_pin(pin_name) pins = self.get_pins(pin_name)
inflated_pin = pin.inflated_pin(multiple=1) for pin in pins:
another_iteration_needed = True inflated_pin = pin.inflated_pin(multiple=1)
while another_iteration_needed: another_iteration_needed = True
another_iteration_needed = False while another_iteration_needed:
old_blockages = list(self.blockages[pin.layer]) another_iteration_needed = False
for blockage in old_blockages: old_blockages = list(self.blockages[pin.layer])
if blockage.overlaps(inflated_pin): for blockage in old_blockages:
intersection_shape = blockage.intersection(inflated_pin) if blockage.overlaps(inflated_pin):
# If it is zero area, don't add the pin intersection_shape = blockage.intersection(inflated_pin)
if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]: # If it is zero area, don't add the pin
continue if intersection_shape[0][0]==intersection_shape[1][0] or intersection_shape[0][1]==intersection_shape[1][1]:
another_iteration_needed = True continue
# Remove the old blockage and add the new ones another_iteration_needed = True
self.blockages[pin.layer].remove(blockage) # Remove the old blockage and add the new ones
intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer) self.blockages[pin.layer].remove(blockage)
new_blockages = blockage.cut(intersection_pin) intersection_pin = pin_layout("", intersection_shape, inflated_pin.layer)
self.blockages[pin.layer].extend(new_blockages) new_blockages = blockage.cut(intersection_pin)
self.blockages[pin.layer].extend(new_blockages)
def lef_write_header(self): def lef_write_header(self):
""" Header of LEF file """ """ Header of LEF file """

View File

@ -6,6 +6,7 @@
# All rights reserved. # All rights reserved.
# #
import math import math
from tech import spice
class verilog: class verilog:
@ -28,10 +29,19 @@ class verilog:
else: else:
self.vf.write("\n") 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("module {0}(\n".format(self.name))
self.vf.write("`ifdef USE_POWER_PINS\n") self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" vdd,\n") self.vf.write(" {},\n".format(self.vdd_name))
self.vf.write(" gnd,\n") self.vf.write(" {},\n".format(self.gnd_name))
self.vf.write("`endif\n") self.vf.write("`endif\n")
for port in self.all_ports: for port in self.all_ports:
@ -71,8 +81,8 @@ class verilog:
self.vf.write("\n") self.vf.write("\n")
self.vf.write("`ifdef USE_POWER_PINS\n") self.vf.write("`ifdef USE_POWER_PINS\n")
self.vf.write(" inout vdd;\n") self.vf.write(" inout {};\n".format(self.vdd_name))
self.vf.write(" inout gnd;\n") self.vf.write(" inout {};\n".format(self.gnd_name))
self.vf.write("`endif\n") self.vf.write("`endif\n")
for port in self.all_ports: for port in self.all_ports:

View File

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

View File

@ -22,7 +22,7 @@ from globals import OPTS
class stimuli(): class stimuli():
""" Class for providing stimuli functions """ """ Class for providing stimuli functions """
def __init__(self, stim_file, corner): def __init__(self, stim_file, corner):
self.vdd_name = "vdd" self.vdd_name = "vdd"
self.gnd_name = "gnd" self.gnd_name = "gnd"
self.pmos_name = tech.spice["pmos"] 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) human_byte_size = "{:.0f}kbytes".format((word_size * num_words)/1024/8)
# Allow byte writes # Allow byte writes
write_size = 8 # Bits #write_size = 8 # Bits
# Dual port # Dual port
num_rw_ports = 0 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 wordlines have issues with met3 power routing for now
#local_array_size = 16 #local_array_size = 16
#route_supplies = False #route_supplies = "ring"
route_supplies = "left"
check_lvsdrc = True check_lvsdrc = True
#perimeter_pins = False #perimeter_pins = False
#netlist_only = True #netlist_only = True

View File

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

View File

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

View File

@ -75,6 +75,9 @@ class router(router_tech):
self.margin = margin self.margin = margin
self.init_bbox(bbox, 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): def init_bbox(self, bbox=None, margin=0):
""" """
Initialize the ll,ur values with the paramter or using the layout boundary. 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. Adds a supply pin to the perimeter and resizes the bounding box.
""" """
pg = pin_group(name, [], self) pg = pin_group(name, [], self)
if name == "vdd": if name == "gnd":
offset = width offset = width + 1
else: 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, pg.grids = set(self.rg.get_perimeter_list(side=side,
width=width, width=width,
margin=self.margin, margin=self.margin,
offset=offset, offset=offset,
layers=[1])) layers=layers))
pg.enclosures = pg.compute_enclosures() pg.enclosures = pg.compute_enclosures()
pg.pins = set(pg.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.cell.pin_map[name].update(pg.pins)
self.pin_groups[name].append(pg) 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"): 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. 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 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). 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, # The pin escape router already made the bounding box big enough,
# so we can use the regular bbox here. # 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, router.__init__(self,
layers, layers,
design, design,
@ -65,10 +68,13 @@ class supply_tree_router(router):
print_time("Finding pins and blockages", datetime.now(), start_time, 3) print_time("Finding pins and blockages", datetime.now(), start_time, 3)
# Add side pins if enabled # Add side pins if enabled
if self.side_pin: if self.pin_type in ["left", "right", "top", "bottom"]:
self.add_side_supply_pin(self.vdd_name) self.add_side_supply_pin(self.vdd_name, side=self.pin_type)
self.add_side_supply_pin(self.gnd_name) 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 the supply pins to the supply rails
# Route vdd first since we want it to be shorter # Route vdd first since we want it to be shorter
start_time = datetime.now() start_time = datetime.now()

View File

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

View File

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

View File

@ -15,6 +15,7 @@ from design import design
from verilog import verilog from verilog import verilog
from lef import lef from lef import lef
from sram_factory import factory from sram_factory import factory
from tech import spice, layer
class sram_base(design, verilog, lef): 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): for bit in range(self.word_size + self.num_spare_cols):
self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT") self.add_pin("dout{0}[{1}]".format(port, bit), "OUTPUT")
self.add_pin("vdd", "POWER") # Standard supply and ground names
self.add_pin("gnd", "GROUND") 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): 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. # This will either be used to route or left unconnected.
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
for inst in self.insts: 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: try:
from tech import power_grid from tech import power_grid
@ -234,42 +247,21 @@ class sram_base(design, verilog, lef):
# Route a M3/M4 grid # Route a M3/M4 grid
grid_stack = self.m3_stack 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: if not OPTS.route_supplies:
# Do not route the power supply (leave as must-connect pins) # Do not route the power supply (leave as must-connect pins)
return return
elif OPTS.route_supplies == "grid": elif OPTS.route_supplies == "grid":
from supply_grid_router import supply_grid_router as router from supply_grid_router import supply_grid_router as router
rtr=router(grid_stack, self)
else: else:
from supply_tree_router import supply_tree_router as router 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() 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 # Find the lowest leftest pin for vdd and gnd
for pin_name in ["vdd", "gnd"]: for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles # Copy the pin shape(s) to rectangles
@ -282,13 +274,14 @@ class sram_base(design, verilog, lef):
# Remove the pin shape(s) # Remove the pin shape(s)
self.remove_layout_pin(pin_name) self.remove_layout_pin(pin_name)
# Get the lowest, leftest pin # Get new pins
pin = rtr.get_ll_pin(pin_name) pins = rtr.get_new_pins(pin_name)
self.add_layout_pin(pin_name, for pin in pins:
pin.layer, self.add_layout_pin(self.ext_supply[pin_name],
pin.ll(), pin.layer,
pin.width(), pin.ll(),
pin.height()) pin.width(),
pin.height())
elif OPTS.route_supplies: elif OPTS.route_supplies:
# Update these as we may have routed outside the region (perimeter pins) # Update these as we may have routed outside the region (perimeter pins)
@ -319,7 +312,7 @@ class sram_base(design, verilog, lef):
route_width, route_width,
pin.height()) pin.height())
self.add_layout_pin(pin_name, self.add_layout_pin(self.ext_supply[pin_name],
pin.layer, pin.layer,
pin_offset, pin_offset,
pin_width, pin_width,
@ -571,7 +564,7 @@ class sram_base(design, verilog, lef):
temp.append("bank_spare_wen{0}[{1}]".format(port, bit)) temp.append("bank_spare_wen{0}[{1}]".format(port, bit))
for port in self.all_ports: for port in self.all_ports:
temp.append("wl_en{0}".format(port)) temp.append("wl_en{0}".format(port))
temp.extend(["vdd", "gnd"]) temp.extend(self.ext_supplies)
self.connect_inst(temp) self.connect_inst(temp)
return self.bank_insts[-1] 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)) inputs.append("addr{}[{}]".format(port, bit + self.col_addr_size))
outputs.append("a{}[{}]".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 return insts
@ -638,7 +631,7 @@ class sram_base(design, verilog, lef):
inputs.append("addr{}[{}]".format(port, bit)) inputs.append("addr{}[{}]".format(port, bit))
outputs.append("a{}[{}]".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 return insts
@ -660,7 +653,7 @@ class sram_base(design, verilog, lef):
inputs.append("din{}[{}]".format(port, bit)) inputs.append("din{}[{}]".format(port, bit))
outputs.append("bank_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 return insts
@ -682,7 +675,7 @@ class sram_base(design, verilog, lef):
inputs.append("wmask{}[{}]".format(port, bit)) inputs.append("wmask{}[{}]".format(port, bit))
outputs.append("bank_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 return insts
@ -704,7 +697,7 @@ class sram_base(design, verilog, lef):
inputs.append("spare_wen{}[{}]".format(port, bit)) inputs.append("spare_wen{}[{}]".format(port, bit))
outputs.append("bank_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 return insts
@ -735,7 +728,7 @@ class sram_base(design, verilog, lef):
if port in self.write_ports: if port in self.write_ports:
temp.append("w_en{}".format(port)) temp.append("w_en{}".format(port))
temp.append("p_en_bar{}".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) self.connect_inst(temp)
return insts return insts