diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index df7095df..0da2c4b0 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -42,14 +42,14 @@ class layout(): self.visited = [] # List of modules we have already visited self.is_library_cell = False # Flag for library cells self.gds_read() - + try: from tech import power_grid self.pwr_grid_layer = power_grid[0] except ImportError: self.pwr_grid_layer = "m3" - + ############################################################ # GDS layout @@ -465,7 +465,7 @@ class layout(): mid2 = vector(mid1, end.y) else: debug.error("Invalid direction for jog -- must be H or V.") - + if layer in layer_stacks: self.add_wire(layer, [start, mid1, mid2, end]) elif layer in techlayer: @@ -480,7 +480,7 @@ class layout(): mid1 = vector(0.5 * start.x + 0.5 * end.x, start.y) mid2 = vector(mid1, end.y) self.add_path(layer, [start, mid1, mid2, end]) - + def add_wire(self, layers, coordinates, widen_short_wires=True): """Connects a routing path on given layer,coordinates,width. The layers are the (horizontal, via, vertical). """ @@ -620,7 +620,7 @@ class layout(): last_via=via, size=size) return via - + def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): """Adds a ptx module to the design.""" import ptx @@ -973,7 +973,7 @@ class layout(): self.add_via_stack_center(from_layer=vlayer, to_layer=dest_pin.layer, offset=out_pos) - + def get_layer_pitch(self, layer): """ Return the track pitch on a given layer """ try: @@ -985,7 +985,7 @@ class layout(): 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, @@ -998,8 +998,13 @@ class layout(): max_x = max([pin.center().x for pin in pins]) min_x = min([pin.center().x for pin in pins]) + # max_x_lc & min_x_rc are for routing to/from the edge of the pins + # to increase spacing between contacts of different nets + max_x_lc = max([pin.lc().x for pin in pins]) + min_x_rc = min([pin.rc().x for pin in pins]) + # if we are less than a pitch, just create a non-preferred layer jog - if max_x - min_x <= pitch: + if max_x_lc - min_x_rc <= pitch: half_layer_width = 0.5 * drc["minwidth_{0}".format(self.vertical_layer)] # Add the horizontal trunk on the vertical layer! @@ -1020,7 +1025,15 @@ class layout(): # Route each pin to the trunk for pin in pins: - mid = vector(pin.center().x, trunk_offset.y) + # If there is sufficient space, Route from the edge of the pins + # Otherwise, route from the center of the pins + if max_x_lc - min_x_rc > pitch: + if pin.center().x == max_x: + mid = vector(pin.lc().x, trunk_offset.y) + else: + mid = vector(pin.rc().x, trunk_offset.y) + else: + mid = vector(pin.center().x, trunk_offset.y) self.add_path(self.vertical_layer, [pin.center(), mid]) self.add_via_center(layers=layer_stack, offset=mid) @@ -1037,8 +1050,13 @@ class layout(): max_y = max([pin.center().y for pin in pins]) min_y = min([pin.center().y for pin in pins]) + # max_y_bc & min_y_uc are for routing to/from the edge of the pins + # to reduce spacing between contacts of different nets + max_y_bc = max([pin.bc().y for pin in pins]) + min_y_uc = min([pin.uc().y for pin in pins]) + # if we are less than a pitch, just create a non-preferred layer jog - if max_y - min_y <= pitch: + if max_y_bc - min_y_uc <= pitch: half_layer_width = 0.5 * drc["minwidth_{0}".format(self.horizontal_layer)] @@ -1060,7 +1078,15 @@ class layout(): # Route each pin to the trunk for pin in pins: - mid = vector(trunk_offset.x, pin.center().y) + # If there is sufficient space, Route from the edge of the pins + # Otherwise, route from the center of the pins + if max_y_bc - min_y_uc > pitch: + if pin.center().y == max_y: + mid = vector(trunk_offset.x, pin.bc().y) + else: + mid = vector(trunk_offset.x, pin.uc().y) + else: + mid = vector(trunk_offset.x, pin.center().y) self.add_path(self.horizontal_layer, [pin.center(), mid]) self.add_via_center(layers=layer_stack, offset=mid) @@ -1103,7 +1129,7 @@ class layout(): pitch = self.horizontal_nonpref_pitch else: pitch = self.vertical_nonpref_pitch - + for pin1 in net1: for pin2 in net2: if vcg_pin_overlap(pin1, pin2, vertical, pitch): @@ -1113,7 +1139,7 @@ class layout(): def vcg_pin_overlap(pin1, pin2, vertical, 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. @@ -1147,7 +1173,7 @@ class layout(): 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 @@ -1172,7 +1198,7 @@ class layout(): # 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 for net_name1 in nets: diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 91e20a45..1f482f7d 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -19,7 +19,7 @@ class port_data(design.design): """ def __init__(self, sram_config, port, name=""): - + sram_config.set_local_config(self) self.port = port if self.write_size is not None: @@ -444,7 +444,7 @@ class port_data(design.design): def route_sense_amp_out(self, port): """ Add pins for the sense amp output """ - + for bit in range(self.word_size): data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit)) self.add_layout_pin_rect_center(text="dout_{0}".format(bit), @@ -521,10 +521,10 @@ class port_data(design.design): insn2_start_bit = 1 if self.port == 0 else 0 - self.connect_bitlines(inst1=inst1, - inst2=inst2, - num_bits=self.num_cols, - inst2_start_bit=insn2_start_bit) + self.channel_route_bitlines(inst1=inst1, + inst2=inst2, + num_bits=self.num_cols, + inst2_start_bit=insn2_start_bit) def route_sense_amp_to_column_mux_or_precharge_array(self, port): """ Routing of BL and BR between sense_amp and column mux or precharge array """ @@ -703,7 +703,7 @@ class port_data(design.design): bitline_dirs = ("H", "V") elif bottom_names[0].layer == "m1": bitline_dirs = ("V", "H") - + route_map = list(zip(bottom_names, top_names)) self.create_horizontal_channel_route(route_map, offset, self.m1_stack, bitline_dirs) @@ -717,7 +717,7 @@ class port_data(design.design): This assumes that they have sufficient space to create a jog in the middle between the two modules (if needed). """ - + bot_inst_group, top_inst_group = self._group_bitline_instances( inst1, inst2, num_bits, inst1_bls_template, inst1_start_bit, @@ -738,9 +738,8 @@ class port_data(design.design): vector(bot_br.x, yoffset), vector(top_br.x, yoffset), top_br]) - + def graph_exclude_precharge(self): """Precharge adds a loop between bitlines, can be excluded to reduce complexity""" if self.precharge_array_inst: self.graph_inst_exclude.add(self.precharge_array_inst) - diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index e1d19534..bdd03e55 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -11,7 +11,7 @@ from tech import drc, layer from vector import vector from sram_factory import factory import logical_effort - +from utils import round_to_grid class single_level_column_mux(pgate.pgate): """ @@ -75,6 +75,17 @@ class single_level_column_mux(pgate.pgate): bl_pos = vector(bl_pin.lx(), 0) br_pos = vector(br_pin.lx(), 0) + # The bitline input/output pins must be a least as wide as the metal pitch + # so that there is enough space to route to/from the pins. + # FIXME: bitline_metal_pitch should be greater than the horizontal metal pitch used in port_data + bitline_metal_pitch = self.width / 2 + bitline_width = br_pos.x - bl_pos.x + if bitline_width < bitline_metal_pitch: + bitline_width_increase_bl = round_to_grid((bitline_metal_pitch - bitline_width) / 2) + bitline_width_increase_br = round_to_grid((bitline_metal_pitch - bitline_width) - bitline_width_increase_bl) + bl_pos = bl_pos + vector(-bitline_width_increase_bl, 0) + br_pos = br_pos + vector( bitline_width_increase_br, 0) + # bl and br self.add_layout_pin(text="bl", layer=bl_pin.layer, @@ -133,7 +144,7 @@ class single_level_column_mux(pgate.pgate): def connect_bitlines(self): """ Connect the bitlines to the mux transistors """ - + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 if "li" in layer: self.col_mux_stack = self.li_stack