Merge remote-tracking branch 'private/dev' into dev

This commit is contained in:
mrg 2020-12-18 13:05:11 -08:00
commit e3bc5454f9
11 changed files with 140 additions and 109 deletions

View File

@ -236,7 +236,7 @@ class layout():
# This is commented out for runtime reasons
# debug.info(4, "instance list: " + ",".join(x.name for x in self.insts))
return self.insts[-1]
def get_inst(self, name):
""" Retrieve an instance by name """
for inst in self.insts:
@ -244,6 +244,19 @@ class layout():
return inst
return None
def add_flat_inst(self, name, mod, offset=[0, 0]):
""" Copies all of the items in instance into this module """
for item in mod.objs:
item.offset += offset
self.objs.append(item)
for item in mod.insts:
item.offset += offset
self.insts.append(item)
debug.check(len(item.mod.pins) == 0, "Cannot add flat instance with subinstances.")
self.connect_inst([])
debug.info(3, "adding flat instance {}".format(name))
return None
def add_rect(self, layer, offset, width=None, height=None):
"""
Adds a rectangle on a given layer,offset with width and height
@ -1078,18 +1091,24 @@ class layout():
"""
import channel_route
cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=True, parent=self)
self.add_inst(cr.name, cr)
self.connect_inst([])
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices.
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
def create_horizontal_channel_route(self, netlist, offset, layer_stack, directions=None):
"""
Wrapper to create a horizontal channel route
"""
import channel_route
cr = channel_route.channel_route(netlist, offset, layer_stack, directions, vertical=False, parent=self)
self.add_inst(cr.name, cr)
self.connect_inst([])
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices.
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
def add_boundary(self, ll=vector(0, 0), ur=None):
""" Add boundary for debugging dimensions """
if OPTS.netlist_only:

View File

@ -1362,8 +1362,9 @@ class delay(simulation):
else:
debug.error("Measurement name not recognized: {}".format(mname), 1)
# Estimate the period as double the delay with margin
period_margin = 0.1
# Margin for error in period. Calculated by averaging required margin for a small and large
# memory. FIXME: margin is quite large, should be looked into.
period_margin = 1.85
sram_data = {"min_period": (max_delay / 1e3) * 2 * period_margin,
"leakage_power": power.leakage}

View File

@ -11,7 +11,7 @@ import math
from sram_factory import factory
from vector import vector
from globals import OPTS
from tech import layer
class write_mask_and_array(design.design):
"""
@ -95,9 +95,9 @@ class write_mask_and_array(design.design):
if not self.offsets:
self.offsets = []
for i in range(self.columns):
self.offsets.append(i * self.driver_spacing)
self.offsets.append((i + self.write_size - 1) * self.driver_spacing)
self.width = self.offsets[-1] + self.driver_spacing
self.width = self.offsets[-1] + self.bitcell.width
self.height = self.and2.height
write_bits = self.columns / self.num_wmasks
@ -138,12 +138,13 @@ class write_mask_and_array(design.design):
self.add_via_stack_center(from_layer=en_pin.layer,
to_layer="m3",
offset=en_pos)
for supply in ["gnd", "vdd"]:
supply_pin=self.and2_insts[i].get_pin(supply)
self.add_power_pin(supply, supply_pin.center(), start_layer=supply_pin.layer)
for supply in ["gnd", "vdd"]:
supply_pin_left = self.and2_insts[0].get_pin(supply)
supply_pin_right = self.and2_insts[self.num_wmasks - 1].get_pin(supply)
self.add_path(supply_pin_left.layer, [supply_pin_left.lc(), supply_pin_right.rc()])
supply_pin = self.and2_insts[0].get_pin(supply)
supply_pin_yoffset = supply_pin.cy()
left_loc = vector(0, supply_pin_yoffset)
right_loc = vector(self.width, supply_pin_yoffset)
self.add_path(supply_pin.layer, [left_loc, right_loc])
self.add_power_pin(supply, left_loc, start_layer=supply_pin.layer)
self.add_power_pin(supply, right_loc, start_layer=supply_pin.layer)

View File

@ -865,7 +865,7 @@ class router(router_tech):
debug.check(index<self.num_pin_components(pin_name),"Pin component index too large.")
pin_in_tracks = self.pin_groups[pin_name][index].grids
debug.info(2, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
debug.info(3, "Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.add_target(pin_in_tracks)
def add_pin_component_target_except(self, pin_name, index):
@ -1000,8 +1000,7 @@ class router(router_tech):
# Double check source and taget are not same node, if so, we are done!
for k, v in self.rg.map.items():
if v.source and v.target:
debug.error("Grid cell is source and target! {}".format(k))
return False
return True
# returns the path in tracks
(path, cost) = self.rg.route(detour_scale)
@ -1013,12 +1012,9 @@ class router(router_tech):
path_set = grid_utils.flatten_set(path)
self.path_blockages.append(path_set)
return True
else:
self.write_debug_gds("failed_route.gds")
# clean up so we can try a reroute
self.rg.reinit()
return False
return True
def annotate_pin_and_tracks(self, pin, tracks):
""""
@ -1156,7 +1152,20 @@ class router(router_tech):
width=pin.width(),
height=pin.height())
def get_pin(self, pin_name):
""" Return the lowest, leftest pin group """
keep_pin = None
for index,pg in enumerate(self.pin_groups[pin_name]):
for pin in pg.enclosures:
if not keep_pin:
keep_pin = pin
else:
if pin.lx() <= keep_pin.lx() and pin.by() <= keep_pin.by():
keep_pin = pin
return keep_pin
# FIXME: This should be replaced with vector.snap_to_grid at some point
def snap_to_grid(offset):
"""

View File

@ -125,7 +125,6 @@ class signal_grid(grid):
#else:
# print("Cost bounded")
debug.warning("Unable to route path. Expand the detour_scale to allow detours.")
return (None,None)
def expand_dirs(self,curpath):

View File

@ -5,20 +5,14 @@
#(acting for and on behalf of Oklahoma State University)
#All rights reserved.
#
import gdsMill
import tech
import math
import debug
from globals import OPTS,print_time
from contact import contact
from pin_group import pin_group
from pin_layout import pin_layout
from vector3d import vector3d
from globals import print_time
from router import router
from direction import direction
from datetime import datetime
import grid
import grid_utils
from scipy.sparse import csr_matrix
from scipy.sparse.csgraph import minimum_spanning_tree
class supply_tree_router(router):
"""
@ -36,7 +30,6 @@ class supply_tree_router(router):
router.__init__(self, layers, design, gds_filename, self.rail_track_width)
def create_routing_grid(self):
"""
Create a sprase routing grid with A* expansion functions.
@ -133,7 +126,6 @@ class supply_tree_router(router):
self.set_blockages(blockage_grids,False)
def route_pins(self, pin_name):
"""
This will route each of the remaining pin components to the other pins.
@ -141,15 +133,46 @@ class supply_tree_router(router):
"""
remaining_components = sum(not x.is_routed() for x in self.pin_groups[pin_name])
debug.info(1,"Maze routing {0} with {1} pin components to connect.".format(pin_name,
remaining_components))
debug.info(1,"Routing {0} with {1} pin components to connect.".format(pin_name,
remaining_components))
for index,pg in enumerate(self.pin_groups[pin_name]):
if pg.is_routed():
continue
# Create full graph
pin_size = len(self.pin_groups[pin_name])
adj_matrix = [[0] * pin_size for i in range(pin_size)]
debug.info(1,"Routing component {0} {1}".format(pin_name, index))
for index1,pg1 in enumerate(self.pin_groups[pin_name]):
for index2,pg2 in enumerate(self.pin_groups[pin_name]):
if index1>=index2:
continue
dist = int(grid_utils.distance_set(list(pg1.grids)[0], pg2.grids))
adj_matrix[index1][index2] = dist
# Find MST
X = csr_matrix(adj_matrix)
Tcsr = minimum_spanning_tree(X)
mst = Tcsr.toarray().astype(int)
connections = []
for x in range(pin_size):
for y in range(pin_size):
if x >= y:
continue
if mst[x][y]>0:
connections.append((x, y))
debug.info(1,"MST has {0} segments.".format(len(connections)))
# Route MST components
for (src, dest) in connections:
self.route_signal(pin_name, src, dest)
#self.write_debug_gds("final.gds", True)
#return
def route_signal(self, pin_name, src_idx, dest_idx):
for detour_scale in [5 * pow(2, x) for x in range(5)]:
debug.info(2, "Routing {0} to {1} with scale {2}".format(src_idx, dest_idx, detour_scale))
# Clear everything in the routing grid.
self.rg.reinit()
@ -159,35 +182,16 @@ class supply_tree_router(router):
# Add the single component of the pin as the source
# which unmarks it as a blockage too
self.add_pin_component_source(pin_name,index)
self.add_pin_component_source(pin_name, src_idx)
# Marks all pin components except index as target
self.add_pin_component_target_except(pin_name,index)
# Add the prevous paths as a target too
self.add_path_target(self.paths)
print("SOURCE: ")
for k,v in self.rg.map.items():
if v.source:
print(k)
print("TARGET: ")
for k,v in self.rg.map.items():
if v.target:
print(k)
import pdb; pdb.set_trace()
if index==1:
self.write_debug_gds("debug{}.gds".format(pin_name),False)
self.add_pin_component_target(pin_name, dest_idx)
# Actually run the A* router
if not self.run_router(detour_scale=5):
self.write_debug_gds("debug_route.gds",True)
#if index==3 and pin_name=="vdd":
# self.write_debug_gds("route.gds",False)
if self.run_router(detour_scale=detour_scale):
return
self.write_debug_gds("debug_route.gds", True)

View File

@ -402,25 +402,6 @@ class sram_1bank(sram_base):
bank_pins = [self.bank_inst.get_pin(x) for x in bank_names]
route_map.extend(list(zip(bank_pins, dff_pins)))
if port == 0:
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
- self.data_bus_size[port] + 2 * self.m1_pitch)
else:
offset = vector(0,
self.bank.height + 2 * self.m1_space)
cr = channel_route.channel_route(netlist=route_map,
offset=offset,
layer_stack=self.m1_stack,
parent=self)
if add_routes:
self.add_inst(cr.name, cr)
self.connect_inst([])
else:
self.col_addr_bus_size[port] = cr.height
route_map = []
# wmask dff
if self.num_wmasks > 0 and port in self.write_ports:
dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)]
@ -464,26 +445,32 @@ class sram_1bank(sram_base):
if port == 0:
offset = vector(self.control_logic_insts[port].rx() + self.dff.width,
- self.data_bus_size[port] + 2 * self.m1_pitch)
- self.data_bus_size[port] + 2 * self.m3_pitch)
cr = channel_route.channel_route(netlist=route_map,
offset=offset,
layer_stack=layer_stack,
parent=self)
if add_routes:
self.add_inst(cr.name, cr)
self.connect_inst([])
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices.
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap
else:
offset = vector(0,
self.bank.height + 2 * self.m1_space)
self.bank.height + self.m3_pitch)
cr = channel_route.channel_route(netlist=route_map,
offset=offset,
layer_stack=layer_stack,
parent=self)
if add_routes:
self.add_inst(cr.name, cr)
self.connect_inst([])
# This causes problem in magic since it sometimes cannot extract connectivity of isntances
# with no active devices.
# self.add_inst(cr.name, cr)
# self.connect_inst([])
self.add_flat_inst(cr.name, cr)
else:
self.data_bus_size[port] = max(cr.height, self.col_addr_bus_size[port]) + self.data_bus_gap

View File

@ -221,31 +221,40 @@ class sram_base(design, verilog, lef):
# Copy the pins to the top level
# This will either be used to route or left unconnected.
for inst in self.insts:
self.copy_power_pins(inst, "vdd")
self.copy_power_pins(inst, "gnd")
for pin_name in ["vdd", "gnd"]:
for inst in self.insts:
self.copy_power_pins(inst, pin_name)
if not OPTS.route_supplies:
# Do not route the power supply (leave as must-connect pins)
return
grid_stack = set()
try:
from tech import power_grid
grid_stack = power_grid
except ImportError:
# if no power_grid is specified by tech we use sensible defaults
import tech
if "m4" in tech.layer:
# Route a M3/M4 grid
grid_stack = self.m3_stack
elif "m3" in tech.layer:
grid_stack =("m3",)
# Route a M3/M4 grid
grid_stack = self.m3_stack
from supply_grid_router import supply_grid_router as router
if OPTS.route_supplies == "grid":
from supply_grid_router import supply_grid_router as router
elif OPTS.route_supplies:
from supply_tree_router import supply_tree_router as router
rtr=router(grid_stack, self)
rtr.route()
vdd_pin = rtr.get_pin("vdd")
gnd_pin = rtr.get_pin("gnd")
for pin_name, pin in [("vdd", vdd_pin), ("gnd", gnd_pin)]:
self.remove_layout_pin(pin_name)
self.add_layout_pin(pin_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
def compute_bus_sizes(self):
""" Compute the independent bus widths shared between two and four bank SRAMs """

View File

@ -63,7 +63,9 @@ class model_delay_test(openram_test):
# Only compare the delays
spice_delays = {key:value for key, value in spice_data.items() if 'delay' in key}
spice_delays['min_period'] = spice_data['min_period']
model_delays = {key:value for key, value in model_data.items() if 'delay' in key}
model_delays['min_period'] = model_data['min_period']
debug.info(1,"Spice Delays={}".format(spice_delays))
debug.info(1,"Model Delays={}".format(model_delays))

View File

@ -12,6 +12,6 @@ num_words = 16
tech_name = OPTS.tech_name
nominal_corner_only = True
route_supplies = True
route_supplies = "tree"
check_lvsdrc = True

View File

@ -89,7 +89,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
f.write("drc off\n")
f.write("gds polygon subcell true\n")
f.write("gds warning default\n")
f.write("#gds flatten true\n")
f.write("gds flatten true\n")
f.write("gds readonly true\n")
f.write("#gds ordering true\n")
f.write("gds read {}\n".format(gds_name))