diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index 72d903d9..ae3e6a56 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -116,8 +116,19 @@ class layout: self.objs.append(geometry.rectangle(layerNumber, offset, width, height)) return self.objs[-1] return None - - + + def add_center_rect(self, layer, start, end): + """ Add a min-width rectangle from centered on the start and end points""" + minwidth_layer = drc["minwidth_{}".format(layer)] + if start.x!=end.x and start.y!=end.y: + debug.error("Nonrectilinear center rect!",-1) + elif start.x!=end.x: + offset = vector(0,0.5*minwidth_layer) + else: + offset = vector(0.5*minwidth_layer,0) + return self.add_rect(layer,start-offset,end.x-start.x,minwidth_layer) + + def get_pin(self, text): """ Return the pin or list of pins """ try: @@ -170,7 +181,7 @@ class layout: width = max(minwidth_layer,width) - self.add_layout_pin(text, layer, ll_offset, width, height) + return self.add_layout_pin(text, layer, ll_offset, width, height) def remove_layout_pin(self, text): """Delete a labeled pin (or all pins of the same name)""" @@ -192,11 +203,13 @@ class layout: pin_list = self.pin_map[text] for pin in pin_list: if pin == new_pin: - return + return pin self.pin_map[text].append(new_pin) except KeyError: self.pin_map[text] = [new_pin] + return new_pin + def add_label_pin(self, text, layer, offset, width=None, height=None): """Create a labeled pin WITHOUT the pin data structure. This is not an actual pin but a named net so that we can add a correspondence point diff --git a/compiler/nand_2.py b/compiler/nand_2.py index 7b8d3a0e..3863afd2 100644 --- a/compiler/nand_2.py +++ b/compiler/nand_2.py @@ -36,6 +36,7 @@ class nand_2(design.design): self.add_pins() self.create_layout() + print self.pin_map self.DRC_LVS() def add_pins(self): diff --git a/compiler/pin_layout.py b/compiler/pin_layout.py index 978dcb02..8241ad94 100644 --- a/compiler/pin_layout.py +++ b/compiler/pin_layout.py @@ -16,6 +16,8 @@ class pin_layout: self.rect = rect else: self.rect = [vector(rect[0]),vector(rect[1])] + # snap the rect to the grid + self.rect = [x.snap_to_grid() for x in self.rect] # if it's a layer number look up the layer name. this assumes a unique layer number. if type(layer_name_num)==int: self.layer = layer.keys()[layer.values().index(layer_name_num)] diff --git a/compiler/ptx.py b/compiler/ptx.py index 317e6ebd..2eb55b81 100644 --- a/compiler/ptx.py +++ b/compiler/ptx.py @@ -156,8 +156,6 @@ class ptx(design.design): self.poly_connect_index = len(self.objs) - 1 - # change the name so it is unique and specifies drain/srouce (p) routed - self.name = self.name + "_p" def pairwise(self, iterable): @@ -239,11 +237,18 @@ class ptx(design.design): self.poly_positions = [] # following poly(s) for i in range(0, self.mults): - self.add_layout_pin(text="G", - layer="poly", - offset=[poly_xoffset, poly_yoffset], - width=self.poly_width, - height=self.poly_height) + if self.connect_poly: + self.add_layout_pin(text="G", + layer="poly", + offset=[poly_xoffset, poly_yoffset], + width=self.poly_width, + height=self.poly_height) + else: + # Add the rectangle in case we remove the pin when joining fingers + self.add_rect(layer="poly", + offset=[poly_xoffset, poly_yoffset], + width=self.poly_width, + height=self.poly_height) self.poly_positions.append(vector(poly_xoffset, poly_yoffset)) poly_xoffset += self.mults_poly_to_poly + drc["minwidth_poly"] @@ -319,11 +324,18 @@ class ptx(design.design): offset=offset, size=(1, self.num_contacts)) # source are even - self.add_layout_pin(text="S", - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) + if self.connect_active: + self.add_layout_pin(text="S", + layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) + else: + # Add this in case the pins get removed when fingers joined + self.add_rect(layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) self.active_contact_positions.append(offset) # middle contact columns @@ -337,12 +349,19 @@ class ptx(design.design): offset=offset, size=(1, self.num_contacts)) # source are even, drain are odd - name = "S" if i%2==1 else "D" - self.add_layout_pin(text=name, - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) + if self.connect_active: + name = "S" if i%2==1 else "D" + self.add_layout_pin(text=name, + layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) + else: + # Add this in case the pins get removed when fingers joined + self.add_rect(layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) self.active_contact_positions.append(offset) @@ -355,12 +374,19 @@ class ptx(design.design): offset=offset, size=(1, self.num_contacts)) # source are even, drain are odd - name = "D" if self.mults%2==1 else "S" - self.add_layout_pin(text=name, - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) + if self.connect_active: + name = "D" if self.mults%2==1 else "S" + self.add_layout_pin(text=name, + layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) + else: + self.add_rect(layer="metal1", + offset=offset+contact.second_layer_position, + width=contact.second_layer_width, + height=contact.second_layer_height) + # Add this in case the pins get removed when fingers joined self.active_contact_positions.append(offset) diff --git a/compiler/tests/04_wordline_driver_test.py b/compiler/tests/04_wordline_driver_test.py index 5f761d4a..e14814dc 100644 --- a/compiler/tests/04_wordline_driver_test.py +++ b/compiler/tests/04_wordline_driver_test.py @@ -51,5 +51,6 @@ class wordline_driver_test(unittest.TestCase): # instantiate a copy of the class to actually run the test if __name__ == "__main__": (OPTS, args) = globals.parse_args() + del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main() diff --git a/compiler/wire.py b/compiler/wire.py index b76a6216..879baf9b 100644 --- a/compiler/wire.py +++ b/compiler/wire.py @@ -25,7 +25,7 @@ class wire(path): def create_layout(self): self.setup_layers() - self.create_rectilinear_route() + self.create_rectilinear() self.create_vias() self.create_rectangles() # wires and paths should not be offset to (0,0) diff --git a/compiler/wordline_driver.py b/compiler/wordline_driver.py index b28ce8c6..935595dc 100644 --- a/compiler/wordline_driver.py +++ b/compiler/wordline_driver.py @@ -59,11 +59,11 @@ class wordline_driver(design.design): def create_layout(self): # Wordline enable connection - self.add_layout_pin(text="en", - layer="metal2", - offset=[drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"],0], - width=drc["minwidth_metal2"], - height=self.height) + en_pin=self.add_layout_pin(text="en", + layer="metal2", + offset=[drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"],0], + width=drc["minwidth_metal2"], + height=self.height) self.add_layout_pin(text="gnd", layer="metal1", @@ -113,85 +113,82 @@ class wordline_driver(design.design): # add inv1 based on the info above - self.add_inst(name=name_inv1, - mod=self.inv, - offset=name_inv1_offset, - mirror=inst_mirror ) + inv1_inst=self.add_inst(name=name_inv1, + mod=self.inv, + offset=name_inv1_offset, + mirror=inst_mirror ) self.connect_inst(["en", "en_bar[{0}]".format(row), "vdd", "gnd"]) # add nand 2 - self.add_inst(name=name_nand, - mod=self.nand2, - offset=nand2_offset, - mirror=inst_mirror) + nand_inst=self.add_inst(name=name_nand, + mod=self.nand2, + offset=nand2_offset, + mirror=inst_mirror) self.connect_inst(["in[{0}]".format(row), "en_bar[{0}]".format(row), "net[{0}]".format(row), "vdd", "gnd"]) # add inv2 - self.add_inst(name=name_inv2, - mod=self.inv, - offset=inv2_offset, - mirror=inst_mirror) + inv2_inst=self.add_inst(name=name_inv2, + mod=self.inv, + offset=inv2_offset, + mirror=inst_mirror) self.connect_inst(["net[{0}]".format(row), "wl[{0}]".format(row), "vdd", "gnd"]) - # clk connection - clk_offset= vector(drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"], - y_offset + cell_dir.y * self.inv.get_pin("A").by()) - self.add_rect(layer="metal1", - offset=clk_offset, - width=self.x_offset0 - 2*drc["metal1_to_metal1"], - height=cell_dir.y *drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=clk_offset) + # en connection + a_pin = inv1_inst.get_pin("A") + a_pos = a_pin.lc() + clk_offset = vector(en_pin.bc().x,a_pos.y) + self.add_center_rect(layer="metal1", + start=clk_offset, + end=a_pos) + self.add_center_via(layers=("metal1", "via1", "metal2"), + offset=clk_offset) # first inv to nand2 B - inv_to_nand2B_offset = [self.x_offset1 - drc["minwidth_metal1"], - y_offset + cell_dir.y * self.nand2.get_pin("B").by()] - self.add_rect(layer="metal1", - offset=inv_to_nand2B_offset, - width=drc["minwidth_metal1"], - height=cell_dir.y*inv_nand2B_connection_height) + zl_pos = inv1_inst.get_pin("Z").lc() + zr_pos = inv1_inst.get_pin("Z").rc() + bl_pos = nand_inst.get_pin("B").lc() + br_pos = nand_inst.get_pin("B").rc() + self.add_path("metal1", [zl_pos, zr_pos, bl_pos, br_pos]) + # Nand2 out to 2nd inv - nand2_to_2ndinv_offset =[self.x_offset2, - y_offset + cell_dir.y * self.nand2.get_pin("Z").by()] - self.add_rect(layer="metal1", - offset=nand2_to_2ndinv_offset, - width=drc["minwidth_metal1"], - height=cell_dir.y * drc["minwidth_metal1"]) + zl_pos = nand_inst.get_pin("Z").lc() + zr_pos = nand_inst.get_pin("Z").rc() + bl_pos = inv2_inst.get_pin("A").lc() + br_pos = inv2_inst.get_pin("A").rc() + self.add_path("metal1", [zl_pos, zr_pos, bl_pos, br_pos]) # connect the decoder input pin to nand2 A - input_offset=vector(0, y_offset + cell_dir.y*self.nand2.get_pin("A").by()) - mid_via_offset = vector(clk_offset.x,input_offset.y) + vector(drc["minwidth_metal2"]+drc["metal2_to_metal2"],0) + a_pin = nand_inst.get_pin("A") + a_pos = a_pin.lc() + input_offset = vector(0,a_pos.y) + mid_via_offset = vector(clk_offset.x,a_pos.y) + vector(drc["minwidth_metal2"]+drc["metal2_to_metal2"],0) # must under the clk line in M1 - self.add_layout_pin(text="in[{0}]".format(row), - layer="metal1", - offset=input_offset, - width=mid_via_offset.x+drc["minwidth_metal1"], - height=cell_dir.y*drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=mid_via_offset, - mirror=inst_mirror) + self.add_center_layout_pin(text="in[{0}]".format(row), + layer="metal1", + start=input_offset, + end=mid_via_offset) + m1m2_via=self.add_center_via(layers=("metal1", "via1", "metal2"), + offset=mid_via_offset) + # now connect to the nand2 A - self.add_rect(layer="metal2", - offset=mid_via_offset, - width=self.x_offset1-mid_via_offset.x, - height=cell_dir.y*drc["minwidth_metal2"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.x_offset1, - y_offset + cell_dir.y * self.nand2.get_pin("A").by()], - rotate=m1tm2_rotate, - mirror=m1tm2_mirror) + self.add_center_rect(layer="metal2", + start=mid_via_offset, + end=a_pos) + self.add_center_via(layers=("metal1", "via1", "metal2"), + offset=a_pos + vector(0.5*m1m2_via.height,0), + rotate=90) + # output each WL on the right - wl_offset = base_offset + self.inv.get_pin("Z").ll().scale(cell_dir) - self.add_layout_pin(text="wl[{0}]".format(row), - layer="metal1", - offset=wl_offset, - width=drc["minwidth_metal1"]*cell_dir.y, - height=drc["minwidth_metal1"]*cell_dir.y) + wl_offset = inv2_inst.get_pin("Z").rc() + self.add_center_layout_pin(text="wl[{0}]".format(row), + layer="metal1", + start=wl_offset, + end=wl_offset-vector(drc["minwidth_metal1"],0)) def delay(self, slew, load=0):