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