diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 532b0f7d..4fd42635 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -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: diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 867b3cdb..5d2dd09a 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -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} diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index ae5d8550..f25a71c5 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -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) + diff --git a/compiler/router/router.py b/compiler/router/router.py index a6df4f0b..e1fa72ab 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -865,7 +865,7 @@ class router(router_tech): debug.check(index=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) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 55ea7527..a7bc9c9e 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -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 diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 9fbdec64..76acbf0b 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -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 """ diff --git a/compiler/tests/21_model_delay_test.py b/compiler/tests/21_model_delay_test.py index e711c7ca..af1dfa12 100755 --- a/compiler/tests/21_model_delay_test.py +++ b/compiler/tests/21_model_delay_test.py @@ -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)) diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index d19ae02e..0682ef6e 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -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 diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 9d2ace8c..b3d2d99b 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -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))