diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index b5ca9d2e..9ab12827 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -422,25 +422,36 @@ class layout(): for pin_name in self.pin_map.keys(): self.copy_layout_pin(instance, pin_name, prefix + pin_name) - def route_vertical_pins(self, name, layer=None): + def route_vertical_pins(self, name, insts=None, layer=None, side=None): """ Route together all of the pins of a given name that vertically align. + Uses local_insts if insts not specified. + Uses center of pin by default, or right or left if specified. """ bins = {} + if not insts: + insts = self.local_insts - for i in range(len(self.local_insts)): - inst = self.local_insts[i] + for inst in insts: for pin in inst.get_pins(name): + + if side == "right": + x = pin.rx() + elif side == "left": + x = pin.lx() + else: + x = pin.cx() + try: - bins[pin.cx()].append((inst,pin)) + bins[x].append((inst,pin)) except KeyError: - bins[pin.cx()] = [(inst,pin)] + bins[x] = [(inst,pin)] for x, v in bins.items(): - bot_x = min([inst.by() for (inst,pin) in v]) - top_x = max([inst.uy() for (inst,pin) in v]) + bot_y = min([inst.by() for (inst,pin) in v]) + top_y = max([inst.uy() for (inst,pin) in v]) last_via = None for inst,pin in v: @@ -450,7 +461,7 @@ class layout(): pin_layer = self.supply_stack[2] last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=pin.center(), + offset=vector(x, pin.cy()), min_area=True) if last_via: @@ -464,21 +475,31 @@ class layout(): end=vector(x, top_y), width=via_width) - def route_horizontal_pins(self, name, layer=None): + def route_horizontal_pins(self, name, insts=None, layer=None, side=None): """ Route together all of the pins of a given name that horizontally align. + Uses local_insts if insts not specified. + Uses center of pin by default, or top or botom if specified. """ bins = {} + if not insts: + insts = self.local_insts - for i in range(len(self.local_insts)): - inst = self.local_insts[i] + for inst in insts: for pin in inst.get_pins(name): + if side == "top": + y = pin.uy() + elif side == "bottom": + y = pin.by() + else: + y = pin.cy() + try: - bins[pin.cy()].append((inst,pin)) + bins[y].append((inst,pin)) except KeyError: - bins[pin.cy()] = [(inst,pin)] + bins[y] = [(inst,pin)] for y, v in bins.items(): left_x = min([inst.lx() for (inst,pin) in v]) @@ -492,7 +513,7 @@ class layout(): pin_layer = self.supply_stack[0] last_via = self.add_via_stack_center(from_layer=pin.layer, to_layer=pin_layer, - offset=pin.center(), + offset=vector(pin.cx(), y), min_area=True) if last_via: diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f7b721f2..7bddb3a3 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -28,6 +28,7 @@ class hierarchical_decoder(design.design): self.pre2x4_inst = [] self.pre3x8_inst = [] self.pre4x16_inst = [] + self.local_insts = [] b = factory.create(module_type=OPTS.bitcell) self.cell_height = b.height @@ -57,11 +58,12 @@ class hierarchical_decoder(design.design): self.route_inputs() self.route_outputs() self.route_decoder_bus() - self.route_vdd_gnd() self.offset_x_coordinates() - self.width = self.and_inst[0].rx() + 0.5 * self.m1_width + self.width = self.and_inst[0].rx() + + self.route_vdd_gnd() self.add_boundary() self.DRC_LVS() @@ -188,7 +190,7 @@ class hierarchical_decoder(design.design): self.output_layer_pitch = getattr(self, self.output_layer + "_pitch") # Two extra pitches between modules on left and right - self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + self.bus_pitch + self.internal_routing_width = self.total_number_of_predecoder_outputs * self.bus_pitch + 2 * self.bus_pitch self.row_decoder_height = self.and2.height * self.num_outputs # Extra bus space for supply contacts @@ -592,8 +594,13 @@ class hierarchical_decoder(design.design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ - if layer_props.hierarchical_decoder.vertical_supply: + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts) + self.route_vertical_pins("gnd", insts=pre_insts) + self.route_vertical_pins("vdd", insts=self.and_inst) + self.route_vertical_pins("gnd", insts=self.and_inst) + return for n in ["vdd", "gnd"]: pins = self.and_inst[0].get_pins(n) for pin in pins: @@ -612,19 +619,20 @@ class hierarchical_decoder(design.design): for i in self.pre2x4_inst + self.pre3x8_inst: self.copy_layout_pin(i, n) else: - # The vias will be placed at the right of the cells. - xoffset = max(x.rx() for x in self.and_inst) + 0.5 * self.m1_space - for row in range(0, self.num_outputs): - for pin_name in ["vdd", "gnd"]: - # The nand and inv are the same height rows... - supply_pin = self.and_inst[row].get_pin(pin_name) - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) + pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst + self.route_vertical_pins("vdd", insts=pre_insts) + self.route_vertical_pins("gnd", insts=pre_insts) + self.route_vertical_pins("vdd", insts=self.and_inst, side="right") + self.route_vertical_pins("gnd", insts=self.and_inst, side="left") + + # Widen the rails to cover any gap + for inst in self.and_inst: + for name in ["vdd", "gnd"]: + supply_pin = inst.get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) - # Copy the pins from the predecoders - for pre in self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst: - for pin_name in ["vdd", "gnd"]: - self.copy_layout_pin(pre, pin_name) def route_predecode_bus_outputs(self, rail_name, pin, row): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index a8da372a..f3dd8e7e 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -413,7 +413,9 @@ class hierarchical_predecode(design.design): end=vector(self.width, and_pin.cy())) # Add pins in two locations - for xoffset in [self.inv_inst[0].lx() - self.bus_space, - self.and_inst[0].lx() - self.bus_space]: - pin_pos = vector(xoffset, and_pin.cy()) - self.copy_power_pin(and_pin, loc=pin_pos) + if n == "vdd": + xoffset = self.and_inst[0].lx() - self.bus_space + else: + xoffset = self.inv_inst[0].lx() - self.bus_space + pin_pos = vector(xoffset, and_pin.cy()) + self.copy_power_pin(and_pin, loc=pin_pos) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 27dd7e6a..e06d6857 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -77,8 +77,8 @@ class port_address(design.design): def route_supplies(self): """ Propagate all vdd/gnd pins up to this level for all modules """ for inst in [self.wordline_driver_array_inst, self.row_decoder_inst]: - self.copy_power_pins(inst, "vdd") - self.copy_power_pins(inst, "gnd") + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") for rbl_vdd_pin in self.rbl_driver_inst.get_pins("vdd"): if layer_props.port_address.supply_offset: diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 4faf622f..4fe9cc95 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -44,9 +44,9 @@ class wordline_driver_array(design.design): self.route_layer = "m1" self.place_drivers() self.route_layout() - self.route_vdd_gnd() self.offset_x_coordinates() self.add_boundary() + self.route_vdd_gnd() self.DRC_LVS() def add_pins(self): @@ -67,35 +67,23 @@ class wordline_driver_array(design.design): def route_vdd_gnd(self): """ - Add a pin for each row of vdd/gnd which - are must-connects next level up. + Add vertical power rails. """ if layer_props.wordline_driver.vertical_supply: - for name in ["vdd", "gnd"]: - supply_pins = self.wld_inst[0].get_pins(name) - for pin in supply_pins: - self.add_layout_pin_segment_center(text=name, - layer=pin.layer, - start=pin.bc(), - end=vector(pin.cx(), self.height)) + self.route_vertical_pins("vdd", insts=self.wld_inst) + self.route_vertical_pins("gnd", insts=self.wld_inst) else: - # Find the x offsets for where the vias/pins should be placed - xoffset_list = [self.wld_inst[0].rx()] - for num in range(self.rows): - # this will result in duplicate polygons for rails, but who cares + self.route_vertical_pins("vdd", insts=self.wld_inst, side="left") + self.route_vertical_pins("gnd", insts=self.wld_inst, side="right") - # use the inverter offset even though it will be the and's too - (gate_offset, y_dir) = self.get_gate_offset(0, - self.wl_driver.height, - num) - # Route both supplies + # Widen the rails to cover any gap + for num in range(self.rows): for name in ["vdd", "gnd"]: supply_pin = self.wld_inst[num].get_pin(name) + self.add_segment_center(layer=supply_pin.layer, + start=vector(0, supply_pin.cy()), + end=vector(self.width, supply_pin.cy())) - # Add pins in two locations - for xoffset in xoffset_list: - pin_pos = vector(xoffset, supply_pin.cy()) - self.copy_power_pin(supply_pin, loc=pin_pos) def create_drivers(self): self.wld_inst = [] @@ -105,8 +93,8 @@ class wordline_driver_array(design.design): # add and2 self.wld_inst.append(self.add_inst(name=name_and, mod=self.wl_driver)) - self.connect_inst(["in_{0}".format(row), - "en", + self.connect_inst(["en", + "in_{0}".format(row), "wl_{0}".format(row), "vdd", "gnd"]) @@ -135,24 +123,25 @@ class wordline_driver_array(design.design): """ Route all of the signals """ # Wordline enable connection - en_pin = self.wld_inst[0].get_pin("B") - en_bottom_pos = vector(en_pin.lx(), 0) - en_pin = self.add_layout_pin(text="en", - layer="m2", - offset=en_bottom_pos, - height=self.height) + en_pin = self.wld_inst[0].get_pin("A") + en_bottom_pos = vector(en_pin.cx(), 0) + en_top_pos = vector(en_pin.cx(), self.height) + en_pin = self.add_layout_pin_segment_center(text="en", + layer="m2", + start=en_bottom_pos, + end=en_top_pos) for row in range(self.rows): and_inst = self.wld_inst[row] # Drop a via - b_pin = and_inst.get_pin("B") + b_pin = and_inst.get_pin("A") self.add_via_stack_center(from_layer=b_pin.layer, to_layer="m2", offset=b_pin.center()) # connect the decoder input pin to and2 A - self.copy_layout_pin(and_inst, "A", "in_{0}".format(row)) + self.copy_layout_pin(and_inst, "B", "in_{0}".format(row)) # output each WL on the right wl_offset = and_inst.get_pin("Z").rc()