mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into automated_analytical_model
This commit is contained in:
commit
b3bcf48d2e
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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"]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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"):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue