diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 6b1ca3fd..35aa73b1 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -316,7 +316,7 @@ class layout(): You can optionally rename the pin to a new name. """ for pin_name in self.pin_map.keys(): - self.copy_layout_pin(instance, pin_name, prefix+pin_name) + self.copy_layout_pin(instance, pin_name, prefix + pin_name) def add_layout_pin_segment_center(self, text, layer, start, end): """ diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index efc9c4a3..d5b0e799 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -12,6 +12,7 @@ from vector import vector from sram_factory import factory from globals import OPTS + class precharge_array(design.design): """ Dynamically generated precharge array of all bitlines. Cols is number @@ -68,11 +69,8 @@ class precharge_array(design.design): size=self.size, bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) - - self.add_mod(self.pc_cell) - def add_layout_pins(self): self.add_layout_pin(text="en_bar", @@ -86,20 +84,9 @@ class precharge_array(design.design): for i in range(len(self.local_insts)): inst = self.local_insts[i] - bl_pin = inst.get_pin("bl") - self.add_layout_pin(text="bl_{0}".format(i), - layer="m2", - offset=bl_pin.ll(), - width=drc("minwidth_m2"), - height=bl_pin.height()) - br_pin = inst.get_pin("br") - self.add_layout_pin(text="br_{0}".format(i), - layer="m2", - offset=br_pin.ll(), - width=drc("minwidth_m2"), - height=bl_pin.height()) + self.copy_layout_pin(inst, "bl", "bl_{0}".format(i)) + self.copy_layout_pin(inst, "br", "br_{0}".format(i)) - def create_insts(self): """Creates a precharge array by horizontally tiling the precharge cell""" self.local_insts = [] @@ -112,7 +99,6 @@ class precharge_array(design.design): self.local_insts.append(inst) self.connect_inst(["bl_{0}".format(i), "br_{0}".format(i), "en_bar", "vdd"]) - def place_insts(self): """ Places precharge array by horizontally tiling the precharge cell""" from tech import cell_properties @@ -130,8 +116,11 @@ class precharge_array(design.design): xoffset = xoffset + self.pc_cell.width def get_en_cin(self): - """Get the relative capacitance of all the clk connections in the precharge array""" - #Assume single port + """ + Get the relative capacitance of all the clk connections + in the precharge array + """ + # Assume single port precharge_en_cin = self.pc_cell.get_en_cin() - return precharge_en_cin*self.columns + return precharge_en_cin * self.columns diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 4a494763..3f0560f5 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -14,6 +14,7 @@ from globals import OPTS from sram_factory import factory from tech import drc + class precharge(design.design): """ Creates a single precharge cell @@ -32,8 +33,14 @@ class precharge(design.design): self.bitcell_br = bitcell_br self.bitcell_bl_pin =self.bitcell.get_pin(self.bitcell_bl) self.bitcell_br_pin =self.bitcell.get_pin(self.bitcell_br) - print(self.bitcell_bl_pin) - print(self.bitcell_br_pin) + + if self.bitcell_bl_pin.layer == "m1": + self.bitline_layer = "m1" + self.en_layer = "m2" + else: + self.bitline_layer = "m2" + self.en_layer = "m1" + # Creates the netlist and layout # Since it has variable height, it is not a pgate. self.create_netlist() @@ -82,18 +89,24 @@ class precharge(design.design): # Adds the rail across the width of the cell vdd_position = vector(0.5 * self.width, self.height) - self.add_rect_center(layer="m1", + layer_width = drc("minwidth_" + self.en_layer) + self.add_rect_center(layer=self.en_layer, offset=vdd_position, width=self.width, - height=self.m1_width) + height=layer_width) pmos_pin = self.upper_pmos2_inst.get_pin("S") # center of vdd rail pmos_vdd_pos = vector(pmos_pin.cx(), vdd_position.y) self.add_path("m1", [pmos_pin.uc(), pmos_vdd_pos]) + if self.en_layer != "m1": + self.add_via_center(layers=self.m1_stack, + offset=pmos_vdd_pos) + + # Add vdd pin above the transistor - self.add_power_pin("vdd", pmos_pin.center(), vertical=True) + self.add_power_pin("vdd", self.well_contact_pos, vertical=True) def create_ptx(self): """ @@ -117,6 +130,8 @@ class precharge(design.design): Place both the upper_pmos and lower_pmos to the module """ + # reserve some offset to jog the bitlines + self.initial_yoffset = self.pmos.active_offset.y + self.m2_pitch # Compute the other pmos2 location, # but determining offset to overlap the source and drain pins overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll() @@ -127,11 +142,11 @@ class precharge(design.design): bl_xoffset = self.bitcell_bl_pin.lx() self.lower_pmos_position = vector(max(bl_xoffset - contact_xdiff, self.nwell_enclose_active), - self.pmos.active_offset.y) + self.initial_yoffset) self.lower_pmos_inst.place(self.lower_pmos_position) - # adds the upper pmos(s) to layout - ydiff = self.pmos.height + 4 * self.m2_space + # adds the upper pmos(s) to layout with 2 M2 tracks + ydiff = self.pmos.height + self.m2_pitch self.upper_pmos1_pos = self.lower_pmos_position + vector(0, ydiff) self.upper_pmos1_inst.place(self.upper_pmos1_pos) @@ -167,24 +182,20 @@ class precharge(design.design): Adds the en input rail, en contact/vias, and connects to the pmos """ - if self.bitcell_bl_pin.layer == "m1": - layer = "m2" - else: - layer = "m1" - - # adds the en contact to connect the gates to the en rail on metal1 + # adds the en contact to connect the gates to the en rail + # midway in the 4 M2 tracks offset = self.lower_pmos_inst.get_pin("G").ul() \ - + vector(0, self.m2_pitch) + + vector(0, 0.5 * self.m2_pitch) self.add_via_center(layers=self.poly_stack, offset=offset) - if layer == "m2": + if self.en_layer == "m2": self.add_via_center(layers=self.m1_stack, offset=offset) # adds the en rail on metal1 self.add_layout_pin_segment_center(text="en_bar", - layer=layer, + layer=self.en_layer, start=offset.scale(0, 1), end=offset.scale(0, 1) + vector(self.width, 0)) @@ -194,16 +205,15 @@ class precharge(design.design): """ # adds the contact from active to metal1 - well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) \ - + vector(0, self.upper_pmos1_inst.uy() + contact.active_contact.height / 2 \ - + self.nwell_extend_active) + self.well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) \ + + vector(0, self.upper_pmos1_inst.uy() + contact.active_contact.height / 2 \ + + self.nwell_extend_active) self.add_via_center(layers=self.active_stack, - offset=well_contact_pos, + offset=self.well_contact_pos, implant_type="n", well_type="n") - # leave an extra pitch for the height - self.height = well_contact_pos.y + contact.active_contact.height + self.m1_pitch + self.height = self.well_contact_pos.y + contact.active_contact.height + self.m1_space # nwell should span the whole design since it is pmos only self.add_rect(layer="nwell", @@ -215,44 +225,59 @@ class precharge(design.design): """ Adds both bit-line and bit-line-bar to the module """ - layer_width = drc("minwidth_" + self.bitcell_br_pin.layer) - layer_space = drc("{0}_to_{0}".format(self.bitcell_br_pin.layer)) - layer = self.bitcell_bl_pin.layer + layer_width = drc("minwidth_" + self.bitline_layer) + layer_space = drc("{0}_to_{0}".format(self.bitline_layer)) - # adds the BL on metal 2 - offset = vector(layer_space - 0.5 * layer_width, 0) - self.bl_pin = self.add_layout_pin(text="bl", - layer=layer, - offset=offset, - height=self.height) - - # adds the BR on metal 2 - offset = vector(self.width - layer_space - 0.5 * layer_width, 0) - self.br_pin = self.add_layout_pin(text="br", - layer=layer, - offset=offset, - height=self.height) + yoffset = self.initial_yoffset - 0.5 * self.m2_pitch + # adds the BL + self.bl_xoffset = layer_space + 0.5 * layer_width + top_pos = vector(self.bl_xoffset, self.height) + mid1_pos = vector(self.bl_xoffset, yoffset) + mid2_pos = vector(self.bitcell_bl_pin.cx(), yoffset) + pin_pos = vector(self.bitcell_bl_pin.cx(), 0) + self.add_path(self.bitline_layer, + [top_pos, mid1_pos, mid2_pos, pin_pos]) + self.bl_pin = self.add_layout_pin_segment_center(text="bl", + layer=self.bitline_layer, + start=pin_pos, + end=mid2_pos) + + # adds the BR + self.br_xoffset = self.width - layer_space - 0.5 * layer_width + top_pos = vector(self.br_xoffset, self.height) + mid1_pos = vector(self.br_xoffset, yoffset) + mid2_pos = vector(self.bitcell_br_pin.cx(), yoffset) + pin_pos = vector(self.bitcell_br_pin.cx(), 0) + self.add_path(self.bitline_layer, + [top_pos, mid1_pos, mid2_pos, pin_pos]) + self.br_pin = self.add_layout_pin_segment_center(text="br", + layer=self.bitline_layer, + start=pin_pos, + end=mid2_pos) def connect_to_bitlines(self): """ Connect the bitlines to the devices """ self.add_bitline_contacts() - self.connect_pmos_m2(self.lower_pmos_inst.get_pin("S"), - self.get_pin("bl")) - self.connect_pmos_m2(self.lower_pmos_inst.get_pin("D"), - self.get_pin("br")) + self.connect_pmos(self.lower_pmos_inst.get_pin("S"), + self.bl_xoffset) + self.connect_pmos(self.lower_pmos_inst.get_pin("D"), + self.br_xoffset) - self.connect_pmos_m2(self.upper_pmos1_inst.get_pin("S"), - self.get_pin("bl")) - self.connect_pmos_m2(self.upper_pmos2_inst.get_pin("D"), - self.get_pin("br")) + self.connect_pmos(self.upper_pmos1_inst.get_pin("S"), + self.bl_xoffset) + self.connect_pmos(self.upper_pmos2_inst.get_pin("D"), + self.br_xoffset) def add_bitline_contacts(self): """ Adds contacts/via from metal1 to metal2 for bit-lines """ + # No contacts needed if M1 + if self.bitline_layer == "m1": + return # BL lower_pin = self.lower_pmos_inst.get_pin("S") @@ -276,15 +301,17 @@ class precharge(design.design): offset=upper_pin.center(), directions=("V", "V")) - def connect_pmos_m2(self, pmos_pin, bit_pin): + def connect_pmos(self, pmos_pin, bit_xoffset): """ Connect a pmos pin to bitline pin """ - left_pos = vector(min(pmos_pin.cx(), bit_pin.cx()), pmos_pin.cy()) - right_pos = vector(max(pmos_pin.cx(), bit_pin.cx()), pmos_pin.cy()) + left_pos = vector(min(pmos_pin.cx(), bit_xoffset), pmos_pin.cy()) + right_pos = vector(max(pmos_pin.cx(), bit_xoffset), pmos_pin.cy()) - self.add_path("m2", [left_pos, right_pos]) + self.add_path(self.bitline_layer, + [left_pos, right_pos], + width=pmos_pin.height()) def get_en_cin(self): """Get the relative capacitance of the enable in the precharge cell"""