From 98fb34c44c2c447043d639bcfde26c16b429fb30 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 29 Apr 2021 13:55:36 -0700 Subject: [PATCH 01/15] Add conditional power pins to Verilog model. --- compiler/base/verilog.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index 0405649d..ded22e61 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -29,6 +29,11 @@ class verilog: self.vf.write("\n") 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("`endif\n") + for port in self.all_ports: if port in self.readwrite_ports: self.vf.write("// Port {0}: RW\n".format(port)) @@ -65,6 +70,12 @@ class verilog: self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n") self.vf.write("\n") + self.vf.write("module {0}(\n".format(self.name)) + self.vf.write("`ifdef USE_POWER_PINS\n") + self.vf.write(" inout vdd;\n") + self.vf.write(" inout gnd;\n") + self.vf.write("`endif\n") + for port in self.all_ports: self.add_inputs_outputs(port) From a0e263b14a2e8279bf922d40b950d921d371b0e8 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 3 May 2021 15:14:15 -0700 Subject: [PATCH 02/15] Add vdd/gnd pins to the side. --- .../example_config_scn4m_subm.py | 2 +- compiler/router/router.py | 19 ++++- compiler/sram/sram_base.py | 80 ++++++++++++++----- 3 files changed, 77 insertions(+), 24 deletions(-) diff --git a/compiler/example_configs/example_config_scn4m_subm.py b/compiler/example_configs/example_config_scn4m_subm.py index d331c1fc..8fc92169 100644 --- a/compiler/example_configs/example_config_scn4m_subm.py +++ b/compiler/example_configs/example_config_scn4m_subm.py @@ -11,7 +11,7 @@ process_corners = ["TT"] supply_voltages = [5.0] temperatures = [25] -route_supplies = True +route_supplies = "side" check_lvsdrc = True output_name = "sram_{0}rw{1}r{2}w_{3}_{4}_{5}".format(num_rw_ports, diff --git a/compiler/router/router.py b/compiler/router/router.py index 5213af4a..8fe18765 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -1214,7 +1214,7 @@ class router(router_tech): return self.convert_track_to_pin(v) return None - + def get_ll_pin(self, pin_name): """ Return the lowest, leftest pin group """ @@ -1228,6 +1228,23 @@ class router(router_tech): keep_pin = pin return keep_pin + + def get_left_pins(self, pin_name): + """ Return the leftest pin(s) group """ + + keep_pins = [] + for index, pg in enumerate(self.pin_groups[pin_name]): + for pin in pg.enclosures: + if not keep_pins: + keep_pins = [pin] + else: + # Only need to check first since they are all the same left value + if pin.lx() == keep_pins[0].lx(): + keep_pins.append(pin) + elif pin.lx() < keep_pins[0].lx(): + keep_pins = [pin] + + return keep_pins def check_all_routed(self, pin_name): """ diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 7621f67b..ce3f983c 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -229,6 +229,10 @@ class sram_base(design, verilog, lef): 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 + else: + from supply_tree_router import supply_tree_router as router try: from tech import power_grid @@ -237,17 +241,15 @@ class sram_base(design, verilog, lef): # if no power_grid is specified by tech we use sensible defaults # Route a M3/M4 grid grid_stack = self.m3_stack - - 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() + lowest_coord = self.find_lowest_coords() + highest_coord = self.find_highest_coords() + # Find the lowest leftest pin for vdd and gnd - for pin_name in ["vdd", "gnd"]: + for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]: # Copy the pin shape(s) to rectangles for pin in self.get_pins(pin_name): self.add_rect(pin.layer, @@ -258,23 +260,57 @@ 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) + # Either add two long rails or a simple pin + if OPTS.route_supplies == "side": + # Get the leftest pins + pins = rtr.get_left_pins(pin_name) + + pin_width = 2 * getattr(self, "{}_width".format(pins[0].layer)) + pin_space = 2 * getattr(self, "{}_space".format(pins[0].layer)) + 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_pin = self.add_layout_pin(text=pin_name, + layer="m4", + offset=lowest_coord + vector(pin_index * supply_pitch, 0), + width=pin_width, + height=supply_height) - # Add it as an IO pin to the perimeter - lowest_coord = self.find_lowest_coords() - route_width = pin.rx() - lowest_coord.x - pin_width = 2 * getattr(self, "{}_width".format(pin.layer)) - pin_offset = vector(lowest_coord.x, pin.by()) - self.add_layout_pin(pin_name, - pin.layer, - pin_offset, - pin_width, - pin.height()) - self.add_rect(pin.layer, - pin_offset, - route_width, - pin.height()) + route_width = pins[0].rx() - lowest_coord.x + for pin in pins: + pin_offset = vector(lowest_coord.x, pin.by()) + self.add_rect(pin.layer, + pin_offset, + route_width, + pin.height()) + center_offset = vector(supply_pin.cx(), + pin.cy()) + self.add_via_center(layers=self.m3_stack, + offset=center_offset) + else: + # Get the lowest, leftest pin + pin = rtr.get_ll_pins(pin_name) + + pin_width = 2 * getattr(self, "{}_width".format(pin.layer)) + pin_space = 2 * getattr(self, "{}_space".format(pin.layer)) + + # Add it as an IO pin to the perimeter + route_width = pin.rx() - lowest_coord.x + pin_offset = vector(lowest_coord.x, pin.by()) + self.add_rect(pin.layer, + pin_offset, + route_width, + pin.height()) + + self.add_layout_pin(pin_name, + pin.layer, + pin_offset, + pin_width, + pin.height()) def route_escape_pins(self): """ From 19ea33d43ddb03e470a5cc3afc9e719eb8bb2cc7 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 4 May 2021 16:42:42 -0700 Subject: [PATCH 03/15] Move delay line module down. --- compiler/modules/control_logic.py | 29 ++++++++++++++++++++--------- compiler/modules/delay_chain.py | 30 ++++++++++++++---------------- compiler/sram/sram_1bank.py | 6 +++--- 3 files changed, 37 insertions(+), 28 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index eb9a21ed..92b0bcb8 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -346,9 +346,12 @@ class control_logic(design.design): row += 1 self.place_wlen_row(row) row += 1 - self.place_delay(row) + + control_center_y = self.wl_en_inst.uy() + self.m3_pitch + + # Delay chain always gets placed at row 4 + self.place_delay(4) height = self.delay_inst.uy() - control_center_y = self.delay_inst.by() # This offset is used for placement of the control logic in the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), control_center_y) @@ -387,19 +390,22 @@ class control_logic(design.design): def place_delay(self, row): """ Place the replica bitline """ - y_off = row * self.and2.height + 2 * self.m1_pitch + debug.check(row % 2 == 0, "Must place delay chain at even row for supply alignment.") + + # It is flipped on X axis + y_off = (row + self.delay_chain.rows) * self.and2.height # Add the RBL above the rows # Add to the right of the control rows and routing channel - offset = vector(self.delay_chain.width, y_off) - self.delay_inst.place(offset, mirror="MY") + offset = vector(0, y_off) + self.delay_inst.place(offset, mirror="MX") def route_delay(self): - out_pos = self.delay_inst.get_pin("out").bc() + out_pos = self.delay_inst.get_pin("out").center() # Connect to the rail level with the vdd rail - # Use pen since it is in every type of control logic - vdd_ypos = self.p_en_bar_nand_inst.get_pin("vdd").by() + # Use gated clock since it is in every type of control logic + vdd_ypos = self.gated_clk_buf_inst.get_pin("vdd").cy() + self.m1_pitch in_pos = vector(self.input_bus["rbl_bl_delay"].cx(), vdd_ypos) mid1 = vector(out_pos.x, in_pos.y) self.add_wire(self.m1_stack, [out_pos, mid1, in_pos]) @@ -676,7 +682,7 @@ class control_logic(design.design): # Connect the clock rail to the other clock rail # by routing in the supply rail track to avoid channel conflicts in_pos = self.ctrl_dff_inst.get_pin("clk").uc() - mid_pos = in_pos + vector(0, self.and2.height) + mid_pos = vector(in_pos.x, self.gated_clk_buf_inst.get_pin("vdd").cy() - self.m1_pitch) rail_pos = vector(self.input_bus["clk_buf"].cx(), mid_pos.y) self.add_wire(self.m1_stack, [in_pos, mid_pos, rail_pos]) self.add_via_center(layers=self.m1_stack, @@ -794,3 +800,8 @@ class control_logic(design.design): to_layer="m2", offset=out_pos) + def get_left_pins(self, name): + """ + Return the left side supply pins to connect to a vertical stripe. + """ + return(self.cntrl_dff_inst.get_pins(name) + self.delay_inst.get_pins(name)) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index d7e9c2d0..4d112343 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -31,6 +31,7 @@ class delay_chain(design.design): # number of inverters including any fanout loads. self.fanout_list = fanout_list + self.rows = len(self.fanout_list) self.create_netlist() if not OPTS.netlist_only: @@ -43,7 +44,7 @@ class delay_chain(design.design): def create_layout(self): # Each stage is a a row - self.height = len(self.fanout_list) * self.inv.height + self.height = self.rows * self.inv.height # The width is determined by the largest fanout plus the driver self.width = (max(self.fanout_list) + 1) * self.inv.width @@ -69,7 +70,7 @@ class delay_chain(design.design): """ Create the inverters and connect them based on the stage list """ self.driver_inst_list = [] self.load_inst_map = {} - for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list): + for stage_num, fanout_size in zip(range(self.rows), self.fanout_list): # Add the inverter cur_driver=self.add_inst(name="dinv{}".format(stage_num), mod=self.inv) @@ -77,7 +78,7 @@ class delay_chain(design.design): self.driver_inst_list.append(cur_driver) # Hook up the driver - if stage_num + 1 == len(self.fanout_list): + if stage_num + 1 == self.rows: stageout_name = "out" else: stageout_name = "dout_{}".format(stage_num + 1) @@ -101,7 +102,7 @@ class delay_chain(design.design): def place_inverters(self): """ Place the inverters and connect them based on the stage list """ - for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list): + for stage_num, fanout_size in zip(range(self.rows), self.fanout_list): if stage_num % 2: inv_mirror = "MX" inv_offset = vector(0, (stage_num + 1) * self.inv.height) @@ -189,20 +190,17 @@ class delay_chain(design.design): self.add_via_stack_center(from_layer=a_pin.layer, to_layer="m2", offset=a_pin.center()) - self.add_layout_pin(text="in", - layer="m2", - offset=a_pin.ll().scale(1, 0), - height=a_pin.cy()) + self.add_layout_pin_rect_center(text="in", + layer="m2", + offset=a_pin.center()) - # output is A pin of last load inverter + # output is A pin of last load/fanout inverter last_driver_inst = self.driver_inst_list[-1] a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A") self.add_via_stack_center(from_layer=a_pin.layer, - to_layer="m2", + to_layer="m1", offset=a_pin.center()) - mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy()) - self.add_path("m2", [a_pin.center(), mid_point, mid_point.scale(1, 0)]) - self.add_layout_pin_segment_center(text="out", - layer="m2", - start=mid_point, - end=mid_point.scale(1, 0)) + self.add_layout_pin_rect_center(text="out", + layer="m1", + offset=a_pin.center()) + diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 6bc2cd43..176ce49b 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -527,13 +527,13 @@ class sram_1bank(sram_base): # Only input (besides pins) is the replica bitline src_pin = self.control_logic_insts[port].get_pin("rbl_bl") dest_pin = self.bank_inst.get_pin("rbl_bl_{0}_{0}".format(port)) - self.add_wire(self.m2_stack[::-1], + self.add_wire(self.m3_stack, [src_pin.center(), vector(src_pin.cx(), dest_pin.cy()), dest_pin.rc()]) self.add_via_stack_center(from_layer=src_pin.layer, - to_layer="m2", + to_layer="m4", offset=src_pin.center()) self.add_via_stack_center(from_layer=dest_pin.layer, - to_layer="m2", + to_layer="m3", offset=dest_pin.center()) def route_row_addr_dff(self): From 22437615007097d2c198b0d61c64c404bfe35631 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 13:44:06 -0700 Subject: [PATCH 04/15] Must transitively cut blockages until no more. --- compiler/base/lef.py | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/compiler/base/lef.py b/compiler/base/lef.py index f0d6dda0..9db18ab1 100644 --- a/compiler/base/lef.py +++ b/compiler/base/lef.py @@ -112,18 +112,22 @@ class lef: for pin_name in self.pins: pin = self.get_pin(pin_name) inflated_pin = pin.inflated_pin(multiple=1) - for blockage in self.blockages[pin.layer]: - 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 - # 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) - + 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 """ From d3f4810d1b87a0040f54c799676ceab0cddce100 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 13:44:31 -0700 Subject: [PATCH 05/15] Add error with zero length labels on GDS write. --- compiler/gdsMill/gdsMill/vlsiLayout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/gdsMill/gdsMill/vlsiLayout.py b/compiler/gdsMill/gdsMill/vlsiLayout.py index bd9968dc..71e5498c 100644 --- a/compiler/gdsMill/gdsMill/vlsiLayout.py +++ b/compiler/gdsMill/gdsMill/vlsiLayout.py @@ -422,7 +422,8 @@ class VlsiLayout: self.structures[self.rootStructureName].texts.append(textToAdd) def padText(self, text): - if(len(text)%2 == 1): + debug.check(len(text) > 0, "Cannot have zero length text string.") + if(len(text) % 2 == 1): return text + '\x00' else: return text @@ -696,7 +697,6 @@ class VlsiLayout: return max_pins - def getAllPinShapes(self, pin_name): """ Search for a pin label and return ALL the enclosing rectangles on the same layer From f48b0b8f41bd48e0e7f9d2b1aead603e46f0c13a Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 13:45:12 -0700 Subject: [PATCH 06/15] Add left stripe power routes to tree router as option. --- compiler/router/grid.py | 48 +++++---- compiler/router/pin_group.py | 4 + compiler/router/router.py | 78 ++++++++------ compiler/router/router_tech.py | 2 +- compiler/router/signal_escape_router.py | 3 +- compiler/router/signal_router.py | 4 +- compiler/router/supply_grid_router.py | 13 +-- compiler/router/supply_tree_router.py | 28 +++-- compiler/sram/sram_base.py | 134 +++++++++++++----------- 9 files changed, 185 insertions(+), 129 deletions(-) diff --git a/compiler/router/grid.py b/compiler/router/grid.py index 793e5e89..ea59c80f 100644 --- a/compiler/router/grid.py +++ b/compiler/router/grid.py @@ -122,35 +122,45 @@ class grid: self.set_target(n) # self.set_blocked(n, False) - def add_perimeter_target(self, side="all"): - debug.info(3, "Adding perimeter target") - + def get_perimeter_list(self, side="left", layers=[0, 1], width=1, margin=0, offset=0): + """ + Side specifies which side. + Layer specifies horizontal (0) or vertical (1) + Width specifies how wide the perimter "stripe" should be. + """ perimeter_list = [] # Add the left/right columns if side=="all" or side=="left": - x = self.ll.x - for y in range(self.ll.y, self.ur.y, 1): - perimeter_list.append(vector3d(x, y, 0)) - perimeter_list.append(vector3d(x, y, 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 layer in layers: + perimeter_list.append(vector3d(x, y, layer)) if side=="all" or side=="right": - x = self.ur.x - for y in range(self.ll.y, self.ur.y, 1): - perimeter_list.append(vector3d(x, y, 0)) - perimeter_list.append(vector3d(x, y, 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 layer in layers: + perimeter_list.append(vector3d(x, y, layer)) if side=="all" or side=="bottom": - y = self.ll.y - for x in range(self.ll.x, self.ur.x, 1): - perimeter_list.append(vector3d(x, y, 0)) - perimeter_list.append(vector3d(x, y, 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 layer in layers: + perimeter_list.append(vector3d(x, y, layer)) if side=="all" or side=="top": - y = self.ur.y - for x in range(self.ll.x, self.ur.x, 1): - perimeter_list.append(vector3d(x, y, 0)) - perimeter_list.append(vector3d(x, y, 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 layer in layers: + perimeter_list.append(vector3d(x, y, layer)) + return perimeter_list + + def add_perimeter_target(self, side="all", layers=[0, 1]): + debug.info(3, "Adding perimeter target") + + perimeter_list = self.get_perimeter_list(side, layers) + self.set_target(perimeter_list) def is_target(self, point): diff --git a/compiler/router/pin_group.py b/compiler/router/pin_group.py index 7a5d8817..5e6d6f89 100644 --- a/compiler/router/pin_group.py +++ b/compiler/router/pin_group.py @@ -155,6 +155,10 @@ class pin_group: # Now simplify the enclosure list new_pin_list = self.remove_redundant_shapes(pin_list) + # Now add the right name + for pin in new_pin_list: + pin.name = self.name + debug.check(len(new_pin_list) > 0, "Did not find any enclosures.") diff --git a/compiler/router/router.py b/compiler/router/router.py index 8fe18765..ca077572 100644 --- a/compiler/router/router.py +++ b/compiler/router/router.py @@ -28,7 +28,7 @@ class router(router_tech): route on a given layer. This is limited to two layer routes. It populates blockages on a grid class. """ - def __init__(self, layers, design, gds_filename=None, bbox=None, margin=0, route_track_width=1): + def __init__(self, layers, design, bbox=None, margin=0, route_track_width=1): """ This will instantiate a copy of the gds file or the module at (0,0) and route on top of this. The blockages from the gds/module will be @@ -39,19 +39,7 @@ class router(router_tech): self.cell = design - # If didn't specify a gds blockage file, write it out to read the gds - # This isn't efficient, but easy for now - # start_time = datetime.now() - if not gds_filename: - gds_filename = OPTS.openram_temp+"temp.gds" - self.cell.gds_write(gds_filename) - - # Load the gds file and read in all the shapes - self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) - self.reader = gdsMill.Gds2reader(self.layout) - self.reader.loadFromFile(gds_filename) - self.top_name = self.layout.rootStructureName - # print_time("GDS read",datetime.now(), start_time) + self.gds_filename = OPTS.openram_temp + "temp.gds" # The pin data structures # A map of pin names to a set of pin_layout structures @@ -91,6 +79,16 @@ class router(router_tech): """ Initialize the ll,ur values with the paramter or using the layout boundary. """ + + # If didn't specify a gds blockage file, write it out to read the gds + # This isn't efficient, but easy for now + # Load the gds file and read in all the shapes + self.cell.gds_write(self.gds_filename) + self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) + self.reader = gdsMill.Gds2reader(self.layout) + self.reader.loadFromFile(self.gds_filename) + self.top_name = self.layout.rootStructureName + if not bbox: # The boundary will determine the limits to the size # of the routing grid @@ -178,6 +176,17 @@ class router(router_tech): """ Find the pins and blockages in the design """ + + # If didn't specify a gds blockage file, write it out to read the gds + # This isn't efficient, but easy for now + # Load the gds file and read in all the shapes + self.cell.gds_write(self.gds_filename) + self.layout = gdsMill.VlsiLayout(units=GDS["unit"]) + self.reader = gdsMill.Gds2reader(self.layout) + self.reader.loadFromFile(self.gds_filename) + self.top_name = self.layout.rootStructureName + # print_time("GDS read",datetime.now(), start_time) + # This finds the pin shapes and sorts them into "groups" that # are connected. This must come before the blockages, so we # can not count the pins themselves @@ -881,12 +890,32 @@ class router(router_tech): # Clearing the blockage of this pin requires the inflated pins self.clear_blockages(pin_name) + def add_side_supply_pin(self, name, side="left", width=2): + """ + Adds a supply pin to the perimeter and resizes the bounding box. + """ + pg = pin_group(name, [], self) + if name == "vdd": + offset = width + else: + offset = 0 + + pg.grids = set(self.rg.get_perimeter_list(side=side, + width=width, + margin=self.margin, + offset=offset, + layers=[1])) + pg.enclosures = pg.compute_enclosures() + pg.pins = set(pg.enclosures) + self.cell.pin_map[name].update(pg.pins) + self.pin_groups[name].append(pg) + def add_perimeter_target(self, side="all"): """ This will mark all the cells on the perimeter of the original layout as a target. """ self.rg.add_perimeter_target(side=side) - + def num_pin_components(self, pin_name): """ This returns how many disconnected pin components there are. @@ -1219,7 +1248,7 @@ class router(router_tech): """ Return the lowest, leftest pin group """ keep_pin = None - for index,pg in enumerate(self.pin_groups[pin_name]): + for index, pg in enumerate(self.pin_groups[pin_name]): for pin in pg.enclosures: if not keep_pin: keep_pin = pin @@ -1229,23 +1258,6 @@ class router(router_tech): return keep_pin - def get_left_pins(self, pin_name): - """ Return the leftest pin(s) group """ - - keep_pins = [] - for index, pg in enumerate(self.pin_groups[pin_name]): - for pin in pg.enclosures: - if not keep_pins: - keep_pins = [pin] - else: - # Only need to check first since they are all the same left value - if pin.lx() == keep_pins[0].lx(): - keep_pins.append(pin) - elif pin.lx() < keep_pins[0].lx(): - keep_pins = [pin] - - return keep_pins - def check_all_routed(self, pin_name): """ Check that all pin groups are routed. diff --git a/compiler/router/router_tech.py b/compiler/router/router_tech.py index b3e26f79..6cbbd422 100644 --- a/compiler/router/router_tech.py +++ b/compiler/router/router_tech.py @@ -123,7 +123,7 @@ class router_tech: min_wire_width = drc("minwidth_{0}".format(layer_name), 0, math.inf) - min_width = drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf) + min_width = self.route_track_width * drc("minwidth_{0}".format(layer_name), self.route_track_width * min_wire_width, math.inf) min_spacing = drc(str(layer_name)+"_to_"+str(layer_name), self.route_track_width * min_wire_width, math.inf) return (min_width, min_spacing) diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index a9531290..7cc41d97 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -17,7 +17,7 @@ class signal_escape_router(router): A router that routes signals to perimeter and makes pins. """ - def __init__(self, layers, design, bbox=None, margin=0, gds_filename=None): + def __init__(self, layers, design, bbox=None, margin=0): """ 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). @@ -25,7 +25,6 @@ class signal_escape_router(router): router.__init__(self, layers=layers, design=design, - gds_filename=gds_filename, bbox=bbox, margin=margin) diff --git a/compiler/router/signal_router.py b/compiler/router/signal_router.py index 89edcb01..9fbf871f 100644 --- a/compiler/router/signal_router.py +++ b/compiler/router/signal_router.py @@ -15,12 +15,12 @@ class signal_router(router): route on a given layer. This is limited to two layer routes. """ - def __init__(self, layers, design, gds_filename=None, bbox=None): + def __init__(self, layers, design, bbox=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). """ - router.__init__(self, layers, design, gds_filename, bbox) + router.__init__(self, layers, design, bbox) def route(self, src, dest, detour_scale=5): """ diff --git a/compiler/router/supply_grid_router.py b/compiler/router/supply_grid_router.py index 8a201474..f24498ab 100644 --- a/compiler/router/supply_grid_router.py +++ b/compiler/router/supply_grid_router.py @@ -21,7 +21,7 @@ class supply_grid_router(router): routes a grid to connect the supply on the two layers. """ - def __init__(self, layers, design, gds_filename=None, bbox=None): + def __init__(self, layers, design, margin=0, bbox=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). @@ -29,9 +29,9 @@ class supply_grid_router(router): start_time = datetime.now() # Power rail width in minimum wire widths - self.route_track_width = 2 + self.route_track_width = 1 - router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width) + router.__init__(self, layers, design, bbox=bbox, margin=margin, route_track_width=self.route_track_width) # The list of supply rails (grid sets) that may be routed self.supply_rails = {} @@ -357,8 +357,9 @@ class supply_grid_router(router): # This is inefficient since it is non-incremental, but it was # easier to debug. - self.prepare_blockages(pin_name) - + self.prepare_blockages() + self.clear_blockages(self.vdd_name) + # 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) @@ -369,7 +370,7 @@ class supply_grid_router(router): # Actually run the A* router if not self.run_router(detour_scale=5): - self.write_debug_gds("debug_route.gds", False) + self.write_debug_gds("debug_route.gds") # if index==3 and pin_name=="vdd": # self.write_debug_gds("route.gds",False) diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index ba54ee39..a9f947ad 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -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, gds_filename=None, bbox=None): + def __init__(self, layers, design, bbox=None, side_pin=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). @@ -31,11 +31,19 @@ class supply_tree_router(router): # for prettier routes. self.route_track_width = 1 - router.__init__(self, layers, design, gds_filename, bbox, self.route_track_width) + # The pin escape router already made the bounding box big enough, + # so we can use the regular bbox here. + self.side_pin = side_pin + router.__init__(self, + layers, + design, + bbox=bbox, + route_track_width=self.route_track_width) def route(self, vdd_name="vdd", gnd_name="gnd"): """ - Route the two nets in a single layer) + Route the two nets in a single layer. + Setting pin stripe will make a power rail on the left side. """ debug.info(1, "Running supply router on {0} and {1}...".format(vdd_name, gnd_name)) self.vdd_name = vdd_name @@ -50,11 +58,17 @@ class supply_tree_router(router): # but this is simplest for now. self.create_routing_grid(signal_grid) - # Get the pin shapes start_time = datetime.now() + + # Get the pin shapes self.find_pins_and_blockages([self.vdd_name, self.gnd_name]) 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) + # Route the supply pins to the supply rails # Route vdd first since we want it to be shorter start_time = datetime.now() @@ -87,15 +101,15 @@ class supply_tree_router(router): pin_size = len(self.pin_groups[pin_name]) adj_matrix = [[0] * pin_size for i in range(pin_size)] - for index1,pg1 in enumerate(self.pin_groups[pin_name]): - for index2,pg2 in enumerate(self.pin_groups[pin_name]): + 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 - debug.info(2, "Finding MinimumSpanning Tree") + debug.info(2, "Finding Minimum Spanning Tree") X = csr_matrix(adj_matrix) Tcsr = minimum_spanning_tree(X) mst = Tcsr.toarray().astype(int) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index ce3f983c..1ea9d96b 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -225,6 +225,38 @@ class sram_base(design, verilog, lef): for pin_name in ["vdd", "gnd"]: for inst in self.insts: self.copy_power_pins(inst, pin_name) + + try: + from tech import power_grid + grid_stack = power_grid + except ImportError: + # if no power_grid is specified by tech we use sensible defaults + # 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) @@ -233,71 +265,52 @@ class sram_base(design, verilog, lef): from supply_grid_router import supply_grid_router as router else: from supply_tree_router import supply_tree_router as router - - try: - from tech import power_grid - grid_stack = power_grid - except ImportError: - # if no power_grid is specified by tech we use sensible defaults - # Route a M3/M4 grid - grid_stack = self.m3_stack - rtr=router(grid_stack, self) + rtr=router(grid_stack, self, side_pin=(OPTS.route_supplies == "side")) rtr.route() - lowest_coord = self.find_lowest_coords() - highest_coord = self.find_highest_coords() - - # Find the lowest leftest pin for vdd and gnd - for (pin_name, pin_index) in [("vdd", 0), ("gnd", 1)]: - # Copy the pin shape(s) to rectangles - for pin in self.get_pins(pin_name): - self.add_rect(pin.layer, - pin.ll(), - pin.width(), - pin.height()) - - # Remove the pin shape(s) - self.remove_layout_pin(pin_name) - - # Either add two long rails or a simple pin - if OPTS.route_supplies == "side": - # Get the leftest pins - pins = rtr.get_left_pins(pin_name) - - pin_width = 2 * getattr(self, "{}_width".format(pins[0].layer)) - pin_space = 2 * getattr(self, "{}_space".format(pins[0].layer)) - 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_pin = self.add_layout_pin(text=pin_name, - layer="m4", - offset=lowest_coord + vector(pin_index * supply_pitch, 0), - width=pin_width, - height=supply_height) - - route_width = pins[0].rx() - lowest_coord.x - for pin in pins: - pin_offset = vector(lowest_coord.x, pin.by()) + if OPTS.route_supplies == "side": + # Find the lowest leftest pin for vdd and gnd + for pin_name in ["vdd", "gnd"]: + # Copy the pin shape(s) to rectangles + for pin in self.get_pins(pin_name): self.add_rect(pin.layer, - pin_offset, - route_width, + pin.ll(), + pin.width(), pin.height()) - center_offset = vector(supply_pin.cx(), - pin.cy()) - self.add_via_center(layers=self.m3_stack, - offset=center_offset) - else: + + # Remove the pin shape(s) + self.remove_layout_pin(pin_name) + # Get the lowest, leftest pin - pin = rtr.get_ll_pins(pin_name) - - pin_width = 2 * getattr(self, "{}_width".format(pin.layer)) - pin_space = 2 * getattr(self, "{}_space".format(pin.layer)) + pin = rtr.get_ll_pin(pin_name) + self.add_layout_pin(pin_name, + pin.layer, + pin.ll(), + pin.width(), + pin.height()) + elif OPTS.route_supplies == "tree": + # Update these as we may have routed outside the region (perimeter pins) + lowest_coord = self.find_lowest_coords() + + # Find the lowest leftest pin for vdd and gnd + for pin_name in ["vdd", "gnd"]: + # Copy the pin shape(s) to rectangles + for pin in self.get_pins(pin_name): + self.add_rect(pin.layer, + pin.ll(), + pin.width(), + pin.height()) + + # Remove the pin shape(s) + self.remove_layout_pin(pin_name) + + # Get the lowest, leftest pin + pin = rtr.get_ll_pin(pin_name) + + pin_width = 2 * getattr(self, "{}_width".format(pin.layer)) + # Add it as an IO pin to the perimeter route_width = pin.rx() - lowest_coord.x pin_offset = vector(lowest_coord.x, pin.by()) @@ -311,6 +324,9 @@ class sram_base(design, verilog, lef): pin_offset, pin_width, pin.height()) + else: + # Grid is left with many top level pins + pass def route_escape_pins(self): """ @@ -355,7 +371,7 @@ class sram_base(design, verilog, lef): from signal_escape_router import signal_escape_router as router rtr=router(layers=self.m3_stack, design=self, - margin=4 * self.m3_pitch) + margin=8 * self.m3_pitch) rtr.escape_route(pins_to_route) def compute_bus_sizes(self): From b3948121df8393f6e0b692b2e0fec59046374845 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 14:04:24 -0700 Subject: [PATCH 07/15] Default supply routing is tree. --- compiler/sram/sram_base.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 1ea9d96b..8b6d6a31 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -265,7 +265,7 @@ class sram_base(design, verilog, lef): from supply_grid_router import supply_grid_router as router else: from supply_tree_router import supply_tree_router as router - + rtr=router(grid_stack, self, side_pin=(OPTS.route_supplies == "side")) rtr.route() @@ -290,7 +290,7 @@ class sram_base(design, verilog, lef): pin.width(), pin.height()) - elif OPTS.route_supplies == "tree": + elif OPTS.route_supplies: # Update these as we may have routed outside the region (perimeter pins) lowest_coord = self.find_lowest_coords() @@ -324,9 +324,9 @@ class sram_base(design, verilog, lef): pin_offset, pin_width, pin.height()) - else: - # Grid is left with many top level pins - pass + else: + # Grid is left with many top level pins + pass def route_escape_pins(self): """ From 120c4de5ade02c26875b1d571ca38b47e697fc85 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 14:21:53 -0700 Subject: [PATCH 08/15] Fix placement of delay chain to align with control logic rows. --- compiler/modules/control_logic.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 92b0bcb8..52c1dd87 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -391,9 +391,9 @@ class control_logic(design.design): def place_delay(self, row): """ Place the replica bitline """ debug.check(row % 2 == 0, "Must place delay chain at even row for supply alignment.") - + # It is flipped on X axis - y_off = (row + self.delay_chain.rows) * self.and2.height + y_off = row * self.and2.height + self.delay_chain.height # Add the RBL above the rows # Add to the right of the control rows and routing channel From f677c8a88df6c5142d3e9156cf1b59f71a3313ca Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 14:44:05 -0700 Subject: [PATCH 09/15] Fix predecoder offset after relocating bank offset --- compiler/modules/bank.py | 6 +++++- compiler/sram/sram_1bank.py | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 9c2b2add..a76d0d80 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -75,6 +75,11 @@ class bank(design.design): self.bank_array_ll = self.offset_all_coordinates().scale(-1, -1) self.bank_array_ur = self.bitcell_array_inst.ur() self.bank_array_ul = self.bitcell_array_inst.ul() + + # These are used for other placements (e.g. address flops) + self.predecoder_top = self.port_address[0].predecoder_height + self.port_address_inst[0].by() + self.predecoder_bottom = self.port_address_inst[0].by() + self.DRC_LVS() def add_pins(self): @@ -227,7 +232,6 @@ class bank(design.design): x_offset = self.m2_gap + self.port_address[port].width self.port_address_offsets[port] = vector(-x_offset, self.main_bitcell_array_bottom) - self.predecoder_height = self.port_address[port].predecoder_height + self.port_address_offsets[port].y # LOWER LEFT QUADRANT # Place the col decoder left aligned with wordline driver diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 176ce49b..5ddbaade 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -120,8 +120,9 @@ class sram_1bank(sram_base): port = 0 # The row address bits are placed above the control logic aligned on the right. x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width - # It is above the control logic but below the top of the bitcell array - y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_height) + # It is above the control logic and the predecoder array + y_offset = max(self.control_logic_insts[port].uy(), self.bank.predecoder_top) + self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(self.row_addr_pos[port]) @@ -130,7 +131,7 @@ class sram_1bank(sram_base): # The row address bits are placed above the control logic aligned on the left. x_offset = self.control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width # If it can be placed above the predecoder and below the control logic, do it - y_offset = self.bank.bank_array_ll.y + y_offset = self.bank.predecoder_bottom self.row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(self.row_addr_pos[port], mirror="XY") From 789a8a1cf06999de81a927dd3ee25c903147ec2b Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 15:37:27 -0700 Subject: [PATCH 10/15] Update golden verilog results --- compiler/tests/golden/sram_2_16_1_freepdk45.v | 9 +++++++++ compiler/tests/golden/sram_2_16_1_scn4m_subm.v | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.v b/compiler/tests/golden/sram_2_16_1_freepdk45.v index 46f89fa5..a35d3da7 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.v +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.v @@ -3,6 +3,10 @@ // Word size: 2 module sram_2_16_1_freepdk45( +`ifdef USE_POWER_PINS + vdd, + gnd, +`endif // Port 0: RW clk0,csb0,web0,addr0,din0,dout0 ); @@ -15,6 +19,11 @@ module sram_2_16_1_freepdk45( parameter VERBOSE = 1 ; //Set to 0 to only display warnings parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary +module sram_2_16_1_freepdk45( +`ifdef USE_POWER_PINS + inout vdd; + inout gnd; +`endif input clk0; // clock input csb0; // active low chip select input web0; // active low write control diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v index cb95036b..e53abcbe 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v @@ -3,6 +3,10 @@ // Word size: 2 module sram_2_16_1_scn4m_subm( +`ifdef USE_POWER_PINS + vdd, + gnd, +`endif // Port 0: RW clk0,csb0,web0,addr0,din0,dout0 ); @@ -15,6 +19,11 @@ module sram_2_16_1_scn4m_subm( parameter VERBOSE = 1 ; //Set to 0 to only display warnings parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary +module sram_2_16_1_scn4m_subm( +`ifdef USE_POWER_PINS + inout vdd; + inout gnd; +`endif input clk0; // clock input csb0; // active low chip select input web0; // active low write control From c0574909236cd85cb6f8a7185d26a83fa2fce450 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 5 May 2021 15:45:28 -0700 Subject: [PATCH 11/15] Delay chain should have same height cells as control logic to align supplies. --- compiler/modules/delay_chain.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 4d112343..e85f000a 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -47,7 +47,7 @@ class delay_chain(design.design): self.height = self.rows * self.inv.height # The width is determined by the largest fanout plus the driver self.width = (max(self.fanout_list) + 1) * self.inv.width - + self.place_inverters() self.route_inverters() self.route_supplies() @@ -63,7 +63,12 @@ class delay_chain(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): - self.inv = factory.create(module_type="pinv") + + self.dff = factory.create(module_type="dff_buf") + dff_height = self.dff.height + + self.inv = factory.create(module_type="pinv", + height=dff_height) self.add_mod(self.inv) def create_inverters(self): From e995e61ea4f3374abbebb49e45c110ddced8237d Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 May 2021 14:32:47 -0700 Subject: [PATCH 12/15] Fix Verilog module typo. Adjust RBL route. --- compiler/base/verilog.py | 1 - compiler/modules/delay_chain.py | 11 ++++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/compiler/base/verilog.py b/compiler/base/verilog.py index ded22e61..7886615f 100644 --- a/compiler/base/verilog.py +++ b/compiler/base/verilog.py @@ -70,7 +70,6 @@ class verilog: self.vf.write(" parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary\n") self.vf.write("\n") - self.vf.write("module {0}(\n".format(self.name)) self.vf.write("`ifdef USE_POWER_PINS\n") self.vf.write(" inout vdd;\n") self.vf.write(" inout gnd;\n") diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index e85f000a..7e4830c9 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -191,13 +191,18 @@ class delay_chain(design.design): def add_layout_pins(self): # input is A pin of first inverter + # It gets routed to the left a bit to prevent pin access errors + # due to the output pin when going up to M3 a_pin = self.driver_inst_list[0].get_pin("A") + mid_loc = vector(a_pin.cx() - self.m3_pitch, a_pin.cy()) self.add_via_stack_center(from_layer=a_pin.layer, - to_layer="m2", - offset=a_pin.center()) + to_layer="m2", + offset=mid_loc) + self.add_path(a_pin.layer, [a_pin.center(), mid_loc]) + self.add_layout_pin_rect_center(text="in", layer="m2", - offset=a_pin.center()) + offset=mid_loc) # output is A pin of last load/fanout inverter last_driver_inst = self.driver_inst_list[-1] From 453f260ca265263f840aa0d9a5e81bec31edc589 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 May 2021 17:14:27 -0700 Subject: [PATCH 13/15] Add commented save npz file for intern --- compiler/router/supply_tree_router.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/compiler/router/supply_tree_router.py b/compiler/router/supply_tree_router.py index a9f947ad..97ba87d5 100644 --- a/compiler/router/supply_tree_router.py +++ b/compiler/router/supply_tree_router.py @@ -111,6 +111,11 @@ class supply_tree_router(router): # Find MST debug.info(2, "Finding Minimum Spanning Tree") X = csr_matrix(adj_matrix) + from scipy.sparse import save_npz + #print("Saving {}.npz".format(self.cell.name)) + #save_npz("{}.npz".format(self.cell.name), X) + #exit(1) + Tcsr = minimum_spanning_tree(X) mst = Tcsr.toarray().astype(int) connections = [] From 57c58ce4a51b021c7c54ec470951c957727b3f17 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 May 2021 17:14:39 -0700 Subject: [PATCH 14/15] Always route data dff on m3 stack. --- compiler/sram/sram_1bank.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 5ddbaade..f9ea1d43 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -420,11 +420,11 @@ class sram_1bank(sram_base): if len(route_map) > 0: # The write masks will have blockages on M1 - if self.num_wmasks > 0 and port in self.write_ports: - layer_stack = self.m3_stack - else: - layer_stack = self.m1_stack - + # if self.num_wmasks > 0 and port in self.write_ports: + # layer_stack = self.m3_stack + # else: + # layer_stack = self.m1_stack + layer_stack = self.m3_stack if port == 0: offset = vector(self.control_logic_insts[port].rx() + self.dff.width, - self.data_bus_size[port] + 2 * self.m3_pitch) From d43edd95e460b59d3f7bb976563eccfaea65d610 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 6 May 2021 19:56:22 -0700 Subject: [PATCH 15/15] Update golden tests for verilog --- compiler/tests/golden/sram_2_16_1_freepdk45.v | 1 - compiler/tests/golden/sram_2_16_1_scn4m_subm.v | 1 - 2 files changed, 2 deletions(-) diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45.v b/compiler/tests/golden/sram_2_16_1_freepdk45.v index a35d3da7..4441b717 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45.v +++ b/compiler/tests/golden/sram_2_16_1_freepdk45.v @@ -19,7 +19,6 @@ module sram_2_16_1_freepdk45( parameter VERBOSE = 1 ; //Set to 0 to only display warnings parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary -module sram_2_16_1_freepdk45( `ifdef USE_POWER_PINS inout vdd; inout gnd; diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v index e53abcbe..fd77a66e 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm.v +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm.v @@ -19,7 +19,6 @@ module sram_2_16_1_scn4m_subm( parameter VERBOSE = 1 ; //Set to 0 to only display warnings parameter T_HOLD = 1 ; //Delay to hold dout value after posedge. Value is arbitrary -module sram_2_16_1_scn4m_subm( `ifdef USE_POWER_PINS inout vdd; inout gnd;