From 0ae194f17c78ea754ea775baf76cf086c37f48e4 Mon Sep 17 00:00:00 2001 From: FriedrichWu Date: Tue, 20 Aug 2024 09:28:48 +0200 Subject: [PATCH] Simple version fix --- compiler/base/channel_route_new.py | 427 ++++++++++++++++++ compiler/modules/sram_new.py | 37 +- compiler/router/signal_escape_router.py | 18 +- .../router/signal_escape_router_change.py | 311 +++++++++++++ compiler/sram_new_test.py | 65 ++- 5 files changed, 827 insertions(+), 31 deletions(-) create mode 100644 compiler/base/channel_route_new.py create mode 100644 compiler/router/signal_escape_router_change.py diff --git a/compiler/base/channel_route_new.py b/compiler/base/channel_route_new.py new file mode 100644 index 00000000..a1178bd1 --- /dev/null +++ b/compiler/base/channel_route_new.py @@ -0,0 +1,427 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2024 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +# This version aims to keep the track out/vertical to the dff pins +# Now only consider the channel at the south +import collections +from openram import debug +from openram.tech import drc +from .vector import vector +from .design import design + + +class channel_net(): + def __init__(self, net_name, pins, vertical): + self.name = net_name + self.pins = pins + self.vertical = vertical + + # Keep track of the internval + if vertical: + self.min_value = min(i.by() for i in pins) + self.max_value = max(i.uy() for i in pins) + else: + self.min_value = min(i.lx() for i in pins) + self.max_value = max(i.rx() for i in pins) + + # Keep track of the conflicts + self.conflicts = [] + + def __str__(self): + return self.name + + def __repr__(self): + return self.name + + def __lt__(self, other): + return self.min_value < other.min_value + + def pin_overlap(self, pin1, pin2, pitch): + """ Check for vertical or horizontal overlap of the two pins """ + + # FIXME: If the pins are not in a row, this may break. + # However, a top pin shouldn't overlap another top pin, + # for example, so the extra comparison *shouldn't* matter. + + # Pin 1 must be in the "BOTTOM" set + x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x - pin2.center().x) < pitch + + # Pin 1 must be in the "LEFT" set + y_overlap = pin1.lx() < pin2.lx() and abs(pin1.center().y - pin2.center().y) < pitch + overlaps = (not self.vertical and x_overlap) or (self.vertical and y_overlap) + return overlaps + + def pins_overlap(self, other, pitch): + """ + Check all the pin pairs on two nets and return a pin + overlap if any pin overlaps. + """ + + for pin1 in self.pins: + for pin2 in other.pins: + if self.pin_overlap(pin1, pin2, pitch): + return True + + return False + + def segment_overlap(self, other): + """ + Check if the horizontal span of the two nets overlaps eachother. + """ + min_overlap = self.min_value >= other.min_value and self.min_value <= other.max_value + max_overlap = self.max_value >= other.min_value and self.max_value <= other.max_value + return min_overlap or max_overlap + + +class channel_route(design): + + unique_id = 0 + + def __init__(self, + netlist, + offset, + layer_stack, + directions=None, + vertical=False, + parent=None): + """ + The net list is a list of the nets with each net being a list of pins + to be connected. The offset is the lower-left of where the + routing channel will start. This does NOT try to minimize the + number of tracks -- instead, it picks an order to avoid the + vertical conflicts between pins. The track size must be the number of + nets times the *nonpreferred* routing of the non-track layer pitch. + + """ + name = "cr_{0}".format(channel_route.unique_id) + channel_route.unique_id += 1 + super().__init__(name) + + self.netlist = netlist + self.offset = offset + self.layer_stack = layer_stack + self.directions = directions + self.vertical = vertical + # For debugging... + self.parent = parent + + if not directions or directions == "pref": + # Use the preferred layer directions + if self.get_preferred_direction(layer_stack[0]) == "V": + self.vertical_layer = layer_stack[0] + self.horizontal_layer = layer_stack[2] + else: + self.vertical_layer = layer_stack[2] + self.horizontal_layer = layer_stack[0] + elif directions == "nonpref": + # Use the preferred layer directions + if self.get_preferred_direction(layer_stack[0]) == "V": + self.vertical_layer = layer_stack[2] + self.horizontal_layer = layer_stack[0] + else: + self.vertical_layer = layer_stack[0] + self.horizontal_layer = layer_stack[2] + else: + # Use the layer directions specified to the router rather than + # the preferred directions + debug.check(directions[0] != directions[1], "Must have unique layer directions.") + if directions[0] == "V": + self.vertical_layer = layer_stack[0] + self.horizontal_layer = layer_stack[2] + else: + self.horizontal_layer = layer_stack[0] + self.vertical_layer = layer_stack[2] + + layer_stuff = self.get_layer_pitch(self.vertical_layer) + (self.vertical_nonpref_pitch, self.vertical_pitch, self.vertical_width, self.vertical_space) = layer_stuff + + layer_stuff = self.get_layer_pitch(self.horizontal_layer) + (self.horizontal_nonpref_pitch, self.horizontal_pitch, self.horizontal_width, self.horizontal_space) = layer_stuff + # For debug + + debug.warning("layer horizontal: {0}".format(self.horizontal_layer)) + debug.warning("horizontal_nonpref_pitch: {0}".format(self.horizontal_nonpref_pitch)) + debug.warning("horizontal_pitch: {0}".format(self.horizontal_pitch)) + debug.warning("horizontal_space: {0}".format(self.horizontal_space)) + debug.warning("layer vertical: {0}".format(self.vertical_layer)) + debug.warning("vertiacl_nonpref_pitch: {0}".format(self.vertical_pitch)) + debug.warning("vertical_pitch: {0}".format(self.vertical_pitch)) + debug.warning("vertical_space: {0}".format(self.vertical_space)) + + self.route() + + def remove_net_from_graph(self, pin, g): + """ + Remove the pin from the graph and all conflicts + """ + g.pop(pin, None) + + # Remove the pin from all conflicts + # FIXME: This is O(n^2), so maybe optimize it. + for other_pin, conflicts in g.items(): + if pin in conflicts: + g[other_pin].remove(pin) + return g + + def route(self): + # Create names for the nets for the graphs + nets = [] + index = 0 + # print(self.netlist) + for pin_list in self.netlist: + nets.append(channel_net("n{}".format(index), pin_list, self.vertical)) + index += 1 + + # Create the (undirected) horizontal constraint graph + hcg = collections.OrderedDict() + for net1 in nets: + for net2 in nets: + if net1.name == net2.name: + continue + if net1.segment_overlap(net2): + try: + hcg[net1.name].add(net2.name) + except KeyError: + hcg[net1.name] = set([net2.name]) + try: + hcg[net2.name].add(net1.name) + except KeyError: + hcg[net2.name] = set([net1.name]) + + + # Initialize the vertical conflict graph (vcg) + # and make a list of all pins + vcg = collections.OrderedDict() + + # print("Nets:") + # for net_name in nets: + # print(net_name, [x.name for x in nets[net_name]]) + + # Find the vertical pin conflicts + # FIXME: O(n^2) but who cares for now + if self.vertical: + pitch = self.horizontal_nonpref_pitch + else: + pitch = self.vertical_nonpref_pitch + + for net in nets: + vcg[net.name] = set() + + for net1 in nets: + for net2 in nets: + # Skip yourself + if net1.name == net2.name: + continue + + if net1.pins_overlap(net2, pitch): + vcg[net2.name].add(net1.name) + + # Check if there are any cycles net1 <---> net2 in the VCG + + + # Some of the pins may be to the left/below the channel offset, + # so adjust if this is the case + self.min_value = min([n.min_value for n in nets]) + self.max_value = min([n.max_value for n in nets]) + if self.vertical: + real_channel_offset = vector(self.offset.x, min(self.min_value, self.offset.y)) + else: + real_channel_offset = vector(min(self.min_value, self.offset.x), self.offset.y) + current_offset = real_channel_offset + current_offset = vector(real_channel_offset.x, current_offset.y + 5) # make route out of dffs area + + if self.layer_stack == self.m2_stack: + self.vertical_nonpref_pitch = self.horizontal_pitch + + if self.layer_stack == self.m1_stack: + current_offset = vector(real_channel_offset.x, current_offset.y + 14) # make sure no overlap between col_dffs & data_dffs + if real_channel_offset.y > 0: # which means this is channnel router for coldff at the top + current_offset = real_channel_offset # no offset to avoid overlap problem at the top + # Sort nets by left edge value + nets.sort() + while len(nets) > 0: + + current_offset_value = current_offset.y if self.vertical else current_offset.x + + # from pprint import pformat + # print("VCG:\n", pformat(vcg)) + # for name,net in vcg.items(): + # print(name, net.min_value, net.max_value, net.conflicts) + # print(current_offset) + # get a route from conflict graph with empty fanout set + for net in nets: + # If it has no conflicts and the interval is to the right of the current offset in the track + if net.min_value >= current_offset_value and len(vcg[net.name]) == 0: + # print("Routing {}".format(net.name)) + # Add the trunk routes from the bottom up for + # horizontal or the left to right for vertical + if self.vertical: + self.add_vertical_trunk_route(net.pins, + current_offset, + self.horizontal_pitch) + current_offset = vector(current_offset.x, net.max_value + self.horizontal_nonpref_pitch) + else: + self.add_horizontal_trunk_route(net.pins, + current_offset, + self.vertical_pitch) + current_offset = vector(net.max_value + self.vertical_nonpref_pitch, current_offset.y) + + # Remove the net from other constriants in the VCG + vcg = self.remove_net_from_graph(net.name, vcg) + nets.remove(net) + + break + else: + # If we made a full pass and the offset didn't change... + current_offset_value = current_offset.y if self.vertical else current_offset.x + initial_offset_value = real_channel_offset.y if self.vertical else real_channel_offset.x + if current_offset_value == initial_offset_value: + debug.info(0, "Channel offset: {}".format(real_channel_offset)) + debug.info(0, "Current offset: {}".format(current_offset)) + debug.info(0, "VCG {}".format(str(vcg))) + debug.info(0, "HCG {}".format(str(hcg))) + for net in nets: + debug.info(0, "{0} pin: {1}".format(net.name, str(net.pins))) + if self.parent: + debug.info(0, "Saving vcg.gds") + self.parent.gds_write("vcg.gds") + debug.error("Cyclic VCG in channel router.", -1) + + # Increment the track and reset the offset to the start (like a typewriter) + if self.vertical: + current_offset = vector(current_offset.x + self.horizontal_nonpref_pitch, real_channel_offset.y) + else: + current_offset = vector(real_channel_offset.x, current_offset.y + self.vertical_nonpref_pitch) + + # Return the size of the channel + if self.vertical: + self.width = current_offset.x + self.horizontal_nonpref_pitch - self.offset.x + self.height = self.max_value + self.vertical_nonpref_pitch - self.offset.y + else: + self.width = self.max_value + self.horizontal_nonpref_pitch - self.offset.x + self.height = current_offset.y + self.vertical_nonpref_pitch - self.offset.y + + def get_layer_pitch(self, layer): + """ Return the track pitch on a given layer """ + try: + # FIXME: Using non-pref pitch here due to overlap bug in VCG constraints. + # It should just result in inefficient channel width but will work. + pitch = getattr(self, "{}_pitch".format(layer)) + nonpref_pitch = getattr(self, "{}_nonpref_pitch".format(layer)) + space = getattr(self, "{}_space".format(layer)) + except AttributeError: + debug.error("Cannot find layer pitch.", -1) + return (nonpref_pitch, pitch, pitch - space, space) + + def add_horizontal_trunk_route(self, + pins, + trunk_offset, + pitch): + """ + Create a trunk route for all pins with + the trunk located at the given y offset. + """ + max_x = max([pin.center().x for pin in pins]) + min_x = min([pin.center().x for pin in pins]) + + # if we are less than a pitch, just create a non-preferred layer jog + non_preferred_route = max_x - min_x <= pitch + + if non_preferred_route: + half_layer_width = 0.5 * drc["minwidth_{0}".format(self.vertical_layer)] + # Add the horizontal trunk on the vertical layer! + self.add_path(self.vertical_layer, + [vector(min_x - half_layer_width, trunk_offset.y), + vector(max_x + half_layer_width, trunk_offset.y)]) + + # Route each pin to the trunk + for pin in pins: + if pin.cy() < trunk_offset.y: + pin_pos = pin.uc() + else: + pin_pos = pin.bc() + + # No bend needed here + mid = vector(pin_pos.x, trunk_offset.y) + self.add_path(self.vertical_layer, [pin_pos, mid]) + else: + # Add the horizontal trunk + self.add_path(self.horizontal_layer, + [vector(min_x, trunk_offset.y), + vector(max_x, trunk_offset.y)]) + + # Route each pin to the trunk + for pin in pins: + # Find the correct side of the pin + if pin.cy() < trunk_offset.y: + pin_pos = pin.uc() + else: + pin_pos = pin.bc() + mid = vector(pin_pos.x, trunk_offset.y) + self.add_path(self.vertical_layer, [pin_pos, mid]) + if not non_preferred_route: + self.add_via_center(layers=self.layer_stack, + offset=mid, + directions=self.directions) + self.add_via_stack_center(from_layer=pin.layer, + to_layer=self.vertical_layer, + offset=pin_pos) + + def add_vertical_trunk_route(self, + pins, + trunk_offset, + pitch): + """ + Create a trunk route for all pins with the + trunk located at the given x offset. + """ + max_y = max([pin.center().y for pin in pins]) + min_y = min([pin.center().y for pin in pins]) + + # if we are less than a pitch, just create a non-preferred layer jog + non_preferred_route = max_y - min_y <= pitch + + if non_preferred_route: + half_layer_width = 0.5 * drc["minwidth_{0}".format(self.horizontal_layer)] + # Add the vertical trunk on the horizontal layer! + self.add_path(self.horizontal_layer, + [vector(trunk_offset.x, min_y - half_layer_width), + vector(trunk_offset.x, max_y + half_layer_width)]) + + # Route each pin to the trunk + for pin in pins: + # Find the correct side of the pin + if pin.cx() < trunk_offset.x: + pin_pos = pin.rc() + else: + pin_pos = pin.lc() + # No bend needed here + mid = vector(trunk_offset.x, pin_pos.y) + self.add_path(self.horizontal_layer, [pin_pos, mid]) + else: + # Add the vertical trunk + self.add_path(self.vertical_layer, + [vector(trunk_offset.x, min_y), + vector(trunk_offset.x, max_y)]) + + # Route each pin to the trunk + for pin in pins: + # Find the correct side of the pin + if pin.cx() < trunk_offset.x: + pin_pos = pin.rc() + else: + pin_pos = pin.lc() + mid = vector(trunk_offset.x, pin_pos.y) + self.add_path(self.horizontal_layer, [pin_pos, mid]) + if not non_preferred_route: + self.add_via_center(layers=self.layer_stack, + offset=mid, + directions=self.directions) + self.add_via_stack_center(from_layer=pin.layer, + to_layer=self.horizontal_layer, + offset=pin_pos) + diff --git a/compiler/modules/sram_new.py b/compiler/modules/sram_new.py index d16bd7ec..2454dcb6 100644 --- a/compiler/modules/sram_new.py +++ b/compiler/modules/sram_new.py @@ -11,7 +11,8 @@ from math import ceil from importlib import import_module, reload from openram import debug from openram.base import vector -from openram.base import channel_route +#from openram.base import channel_route +from openram.base.channel_route_new import channel_route as channel_route from openram.base import design from openram.base import verilog from openram.base import lef @@ -207,7 +208,7 @@ class sram_1bank(design, verilog, lef): if not OPTS.is_unit_test: print_time("Submodules", datetime.datetime.now(), start_time) - def create_layout_recrusive(self, position_add=0): + def create_layout_recrusive(self, position_add=0, mod=0): """ Layout creation """ start_time = datetime.datetime.now() self.place_instances_changeable(position_add=position_add) @@ -215,7 +216,12 @@ class sram_1bank(design, verilog, lef): print_time("Placement", datetime.datetime.now(), start_time) start_time = datetime.datetime.now() - self.route_layout() + + if position_add == 0: + change = False + else: + change = True + self.route_layout(change=change, mod=mod) if not OPTS.is_unit_test: print_time("Routing", datetime.datetime.now(), start_time) @@ -352,7 +358,7 @@ class sram_1bank(design, verilog, lef): # Grid is left with many top level pins pass - def route_escape_pins(self, bbox=None): + def route_escape_pins(self, bbox=None, change=False, mod=0): """ Add the top-level pins for a single bank SRAM with control. """ @@ -394,11 +400,18 @@ class sram_1bank(design, verilog, lef): else: for bit in range(self.num_spare_cols): pins_to_route.append("spare_wen{0}[{1}]".format(port, bit)) - - from openram.router import signal_escape_router as router - rtr = router(layers=self.m3_stack, - bbox=bbox, - design=self) + + if change == False: + from openram.router import signal_escape_router as router + rtr = router(layers=self.m3_stack, + bbox=bbox, + design=self) + else: + from openram.router.signal_escape_router_change import signal_escape_router_change as router + rtr = router(layers=self.m3_stack, + bbox=bbox, + design=self, + mod=mod) rtr.route(pins_to_route) def compute_bus_sizes(self): @@ -1157,7 +1170,7 @@ class sram_1bank(design, verilog, lef): "spare_wen{0}[{1}]".format(port, bit), start_layer=pin_layer) - def route_layout(self): + def route_layout(self, change=False, mod=0): """ Route a single bank SRAM """ self.route_clk() @@ -1181,9 +1194,9 @@ class sram_1bank(design, verilog, lef): if OPTS.perimeter_pins: # We now route the escape routes far enough out so that they will # reach past the power ring or stripes on the sides - self.route_escape_pins(init_bbox) + self.route_escape_pins(bbox=init_bbox, change=change, mod=mod) if OPTS.route_supplies: - self.route_supplies(init_bbox) + self.route_supplies(init_bbox) def route_dffs(self, add_routes=True): diff --git a/compiler/router/signal_escape_router.py b/compiler/router/signal_escape_router.py index c0b6749a..96de12d1 100644 --- a/compiler/router/signal_escape_router.py +++ b/compiler/router/signal_escape_router.py @@ -24,9 +24,6 @@ class signal_escape_router(router): # New pins are the side supply pins self.new_pins = {} - - # Use for add distance of dout pins at the perimeter - self.distance = 0 def route(self, pin_names): @@ -205,20 +202,7 @@ class signal_escape_router(router): fake_center = vector(ur.x + self.track_wire * 2, c.y) if edge == "top": fake_center = vector(c.x, ur.y + self.track_wire * 2) - #fake_center = vector(ll.x - self.track_wire * 2, c.y) # test if here we could change the pin position at the layout - - # relocate the pin position - pattern = r'^dout' - if re.match(pattern, pin.name): - if edge == "bottom":# change to the east - vertical = True - fake_center = vector(ur.x + self.track_wire * 2, ll.y + 30 + self.distance) - self.distance += 1 - else: - if edge == "top":# change to the west - vertical = True - fake_center = vector(ll.x - self.track_wire * 2, ur.y - 30 - self.distance) - self.distance += 1 + #fake_center = vector(ll.x - self.track_wire * 2, c.y) # test if here we could change the pin position at the layout """ pattern = r'^addr0_1' if re.match(pattern, pin.name): diff --git a/compiler/router/signal_escape_router_change.py b/compiler/router/signal_escape_router_change.py new file mode 100644 index 00000000..89eab572 --- /dev/null +++ b/compiler/router/signal_escape_router_change.py @@ -0,0 +1,311 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2024 Regents of the University of California, Santa Cruz +# All rights reserved. +# +from openram import debug +from openram.base.vector import vector +from openram.base.vector3d import vector3d +from openram import OPTS +from .graph import graph +from .graph_shape import graph_shape +from .router import router +import re + +class signal_escape_router_change(router): + """ + This is the signal escape router that uses the Hanan grid graph method. + """ + + def __init__(self, layers, design, bbox=None, mod=0): + + # `router` is the base router class + router.__init__(self, layers, design, bbox) + + # New pins are the side supply pins + self.new_pins = {} + + # Use for add distance of dout pins at the perimeter + self.distance_right = 0 + + self.distance_left = 0 + + # Use for control which edge/position the pins(dout) will be placed + # 0 -> default + # 1 -> all top/bottom + # 2 -> all left/right + self.state_mod = mod + + + def route(self, pin_names): + """ Route the given pins to the perimeter. """ + debug.info(1, "Running signal escape router...") + + # Prepare gdsMill to find pins and blockages + self.prepare_gds_reader() + + # Find pins to be routed + for name in pin_names: + self.find_pins(name) + + # Find blockages and vias + self.find_blockages() + self.find_vias() + + # Convert blockages and vias if they overlap a pin + self.convert_vias() + self.convert_blockages() + + # Add fake pins on the perimeter to do the escape routing on + self.add_perimeter_fake_pins() + + # Add vdd and gnd pins as blockages as well + # NOTE: This is done to make vdd and gnd pins DRC-safe + for pin in self.all_pins: + self.blockages.append(self.inflate_shape(pin)) + + # Route vdd and gnd + routed_count = 0 + routed_max = len(pin_names) + for source, target, _ in self.get_route_pairs(pin_names): + # Change fake pin's name so the graph will treat it as routable + target.name = source.name + # Create the graph + g = graph(self) + g.create_graph(source, target) + # Find the shortest path from source to target + path = g.find_shortest_path() + # If no path is found, throw an error + if path is None: + self.write_debug_gds(gds_name="{}error.gds".format(OPTS.openram_temp), g=g, source=source, target=target) + debug.error("Couldn't route from {} to {}.".format(source, target), -1) + # Create the path shapes on layout + new_wires, new_vias = self.add_path(path) + self.new_pins[source.name] = new_wires[-1] + # Find the recently added shapes + self.find_blockages(name, new_wires) + self.find_vias(new_vias) + routed_count += 1 + debug.info(2, "Routed {} of {} signal pins".format(routed_count, routed_max)) + print("route pins:") + print(source) + self.replace_layout_pins() + + + def get_closest_edge(self, point): + """ Return a point's the closest edge and the edge's axis direction. """ + + ll, ur = self.bbox + + # Snap the pin to the perimeter and break the iteration + ll_diff_x = abs(point.x - ll.x) + ll_diff_y = abs(point.y - ll.y) + ur_diff_x = abs(point.x - ur.x) + ur_diff_y = abs(point.y - ur.y) + min_diff = min(ll_diff_x, ll_diff_y, ur_diff_x, ur_diff_y) + + if min_diff == ll_diff_x: + return "left", True + if min_diff == ll_diff_y: + return "bottom", False + if min_diff == ur_diff_x: + return "right", True + return "top", False + + + def prepare_path(self, path): + """ + Override the `prepare_path` method from the `router` class to prevent + overflows from the SRAM layout area. + """ + + ll, ur = self.bbox + nodes = super().prepare_path(path) + new_nodes = [] + for i in range(len(nodes)): + node = nodes[i] + c = node.center + # Haven't overflown yet + if ll.x < c.x and c.x < ur.x and ll.y < c.y and c.y < ur.y: + new_nodes.append(node) + continue + # Snap the pin to the perimeter and break the iteration + edge, _ = self.get_closest_edge(c) + if edge == "left": + fake_center = vector3d(ll.x + self.half_wire, c.y, c.z) + if edge == "bottom": + fake_center = vector3d(c.x, ll.y + self.half_wire, c.z) + if edge == "right": + fake_center = vector3d(ur.x - self.half_wire, c.y, c.z) + if edge == "top": + fake_center = vector3d(c.x, ur.y - self.half_wire, c.z) + node.center = fake_center + new_nodes.append(node) + break + return new_nodes + + + def add_perimeter_fake_pins(self): + """ + Add the fake pins on the perimeter to where the signals will be routed. + These perimeter fake pins are only used to replace layout pins at the + end of routing. + """ + + ll, ur = self.bbox + wide = self.track_wire + + for side in ["top", "bottom", "left", "right"]: + vertical = side in ["left", "right"] + + # Calculate the lower left coordinate + if side == "top": + offset = vector(ll.x, ur.y - wide) + elif side == "bottom": + offset = vector(ll.x, ll.y) + elif side == "left": + offset = vector(ll.x, ll.y) + elif side == "right": + offset = vector(ur.x - wide, ll.y) + + # Calculate width and height + shape = ur - ll + if vertical: + shape_width = wide + shape_height = shape.y + else: + shape_width = shape.x + shape_height = wide + + # Add this new pin + # They must lie on the non-preferred direction since the side supply + # pins will lie on the preferred direction + layer = self.get_layer(int(not vertical)) + nll = vector(offset.x, offset.y) + nur = vector(offset.x + shape_width, offset.y + shape_height) + rect = [nll, nur] + pin = graph_shape(name="fake", + rect=rect, + layer_name_pp=layer) + self.fake_pins.append(pin) + print("this is add_per") + print(pin.name) + print(pin.center) + + def create_fake_pin(self, pin): + """ Create a fake pin on the perimeter orthogonal to the given pin. """ + + ll, ur = self.bbox + c = pin.center() + print("inside pin name") + print("----------------------------------------------------------") + print(pin.name) + # Find the closest edge + edge, vertical = self.get_closest_edge(c) + + # Keep the fake pin out of the SRAM layout are so that they won't be + # blocked by previous signals if they're on the same orthogonal line + if edge == "left": + fake_center = vector(ll.x - self.track_wire * 2, c.y) + if edge == "bottom": + fake_center = vector(c.x, ll.y - self.track_wire * 2) + if edge == "right": + fake_center = vector(ur.x + self.track_wire * 2, c.y) + if edge == "top": + fake_center = vector(c.x, ur.y + self.track_wire * 2) + #fake_center = vector(ll.x - self.track_wire * 2, c.y) # test if here we could change the pin position at the layout + + # relocate the pin position + pattern = r'^dout' + if re.match(pattern, pin.name): + + if self.state_mod == 0: + pass# do not change, default + + elif self.state_mod == 1: # all top/bottom + if edge == "right": + vertical = False + fake_center = vector(c.x, ll.y - self.track_wire * 2) + self.distance_right += 1 + else: + if edge == "left": + vertical = False + fake_center = vector(c.x, ll.y + self.track_wire * 2) + self.distance_left += 1 + + elif self.state_mod == 2: # all left/right + if (edge == "bottom") or (edge == "right"):# change to the east + vertical = True + fake_center = vector(ur.x + self.track_wire * 2, ll.y + 30 + self.distance_right) + self.distance_right += 1 + else: + if (edge == "top") or (edge == "left"):# change to the west + vertical = True + fake_center = vector(ll.x - self.track_wire * 2, ur.y - 30 - self.distance_left) + self.distance_left += 1 + else: + debug.error("wrong state mod!", -1) + ''' # old version + if edge == "bottom":# change to the east + vertical = True + fake_center = vector(ur.x + self.track_wire * 2, ll.y + 30 + self.distance_right) + self.distance_right += 1 + else: + if edge == "top":# change to the west + vertical = True + fake_center = vector(ll.x - self.track_wire * 2, ur.y - 30 - self.distance_left) + self.distance_left += 1 + ''' + """ + pattern = r'^addr0_1' + if re.match(pattern, pin.name): + vertical = True + fake_center = vector(ll.x - self.track_wire * 2, c.y + self.track_wire * 4)# fix still do not know how to control the distance between every fake pin + #do not know why after this, all fake out pins are put at the same position -> because the originl inside pin has same y? + """ + # Create the fake pin shape + layer = self.get_layer(int(not vertical)) + half_wire_vector = vector([self.half_wire] * 2) + nll = fake_center - half_wire_vector + nur = fake_center + half_wire_vector + #not test jet + #half_wire_vector = vector([self.half_wire] * 2)# out *2 means vector([self.half_wire, self.half_wire]) + #nll = fake_center - half_wire_vector - half_wire_vector + #nur = fake_center + half_wire_vector + half_wire_vector + rect = [nll, nur] + pin = graph_shape(name="fake", + rect=rect, + layer_name_pp=layer) + print("this create_fake_pin") + print(pin.name) + print(pin.center) + return pin + + + def get_route_pairs(self, pin_names): + """ Return the pairs to be routed. """ + + to_route = [] + for name in pin_names: + print("==============the pin names===================") + print(name) + pin = next(iter(self.pins[name])) + fake = self.create_fake_pin(pin) + to_route.append((pin, fake, pin.distance(fake))) + return sorted(to_route, key=lambda x: x[2]) + + + def replace_layout_pins(self): + """ Replace the old layout pins with new ones around the perimeter. """ + + for name, pin in self.new_pins.items(): + print("name:{0}".format(name)) + print("replace_pin->{0}".format(pin)) + pin = graph_shape(pin.name, pin.boundary, pin.lpp) + # Find the intersection of this pin on the perimeter + for fake in self.fake_pins: + edge = pin.intersection(fake) + if edge: + break + self.design.replace_layout_pin(name, edge) + print("pass!!!!!!!") diff --git a/compiler/sram_new_test.py b/compiler/sram_new_test.py index ec2b1a4e..cbce8582 100644 --- a/compiler/sram_new_test.py +++ b/compiler/sram_new_test.py @@ -51,7 +51,67 @@ class sram(): self.name = name from openram.modules.sram_new import sram_1bank as sram - + + num_ports = OPTS.num_rw_ports + OPTS.num_r_ports + OPTS.num_w_ports + self.s = sram(name, sram_config) + self.s.create_netlist()# not placed & routed jet + cur_state = "IDLE" + if not OPTS.netlist_only: + i = 0 + while i < (OPTS.word_size + 100): + + print("current iteration: i = {0}".format(i)) + debug.warning("current state: state = {0}".format(cur_state)) + + if cur_state == "IDLE":# default, fisrt try + try: + self.s.create_layout_recrusive(position_add=i) + except AssertionError as e: + cur_state = "ALL_TOP_BOTTOM" + del self.s + self.s = sram(name, sram_config) + self.s.create_netlist() + if num_ports > 1: + i = 16 + else: + i = 0 + continue + cur_state = "FINISH" + break + + elif cur_state == "ALL_TOP_BOTTOM": + try: + self.s.create_layout_recrusive(position_add=i, mod=1) + except AssertionError as e: + cur_state = "ALL_LEFT_RIGHT" + i = OPTS.word_size + 24 + del self.s + self.s = sram(name, sram_config) + self.s.create_netlist() + continue + cur_state = "FINISH" + break + + elif cur_state == "ALL_LEFT_RIGHT": + try: + self.s.create_layout_recrusive(position_add=i, mod=2) + except AssertionError as e: + cur_state = "ALL_LEFT_RIGHT" + i = i + 1 + if i == (99 + OPTS.word_size):# failed in rounting + debug.error("Failed in rounting", -1) + break + del self.s + self.s = sram(name, sram_config) + self.s.create_netlist() + continue + cur_state = "FINISH" + break + else: + cur_state = "FINISH" + break + + ''' # 2nd version self.s = sram(name, sram_config) self.s.create_netlist()# not placed & routed jet if not OPTS.netlist_only: @@ -78,7 +138,8 @@ class sram(): i = i + 1 supply_route_not_found = False else:# successfully routed - break + break + ''' '''#old version self.s = sram(name, sram_config) self.s.create_netlist()# not placed & routed jet