From a9797d12ab1289955057db755a2b442956905402 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 5 Oct 2017 17:35:05 -0700 Subject: [PATCH] Added pins to the ptx class. Modified pin class to do lazy write of GDS shapes to allow removal of pins. --- compiler/hierarchy_layout.py | 15 ++--- compiler/path.py | 28 ++++---- compiler/pin_layout.py | 20 ++++++ compiler/ptx.py | 75 +++++++++++++++++----- compiler/tests/03_ptx_3finger_nmos_test.py | 4 +- compiler/tests/03_ptx_3finger_pmos_test.py | 4 +- 6 files changed, 108 insertions(+), 38 deletions(-) diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index a398a2cd..72d903d9 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -172,6 +172,9 @@ class layout: 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)""" + self.pin_map[text]=[] def add_layout_pin(self, text, layer, offset, width=None, height=None): """Create a labeled pin """ @@ -179,14 +182,7 @@ class layout: width=drc["minwidth_{0}".format(layer)] if height==None: height=drc["minwidth_{0}".format(layer)] - self.add_rect(layer=layer, - offset=offset, - width=width, - height=height) - self.add_label(text=text, - layer=layer, - offset=offset) - + new_pin = pin_layout(text, [offset,offset+vector(width,height)], layer) try: @@ -384,6 +380,9 @@ class layout: i.gds_write_file(newLayout) for i in self.objs: i.gds_write_file(newLayout) + for pin_name in self.pin_map.keys(): + for pin in self.pin_map[pin_name]: + pin.gds_write_file(newLayout) self.visited = True def gds_write(self, gds_name): diff --git a/compiler/path.py b/compiler/path.py index 0428a09e..2ce313fb 100644 --- a/compiler/path.py +++ b/compiler/path.py @@ -4,6 +4,20 @@ import debug from vector import vector from utils import snap_to_grid +def create_rectilinear_route(my_list): + """ Add intermediate nodes if it isn't rectilinear. Also skip + repeated nodes. Also, convert to vector if the aren't.""" + pl = [snap_to_grid(x) for x in my_list] + + my_list = [] + for index in range(len(pl) - 1): + if pl[index] != pl[index + 1]: + my_list.append(vector(pl[index])) + if (pl[index][0] != pl[index + 1][0]) and (pl[index][1] != pl[index + 1][1]): + my_list.append(vector(pl[index][0], pl[index + 1][1])) + my_list.append(vector(pl[-1])) + return my_list + class path(): """ Object metal path; given the layer type @@ -27,23 +41,15 @@ class path(): def create_layout(self): - self.create_rectilinear_route() + self.create_rectilinear() self.connect_corner() self.create_rectangles() # wires and paths should not be offset to (0,0) - def create_rectilinear_route(self): + def create_rectilinear(self): """ Add intermediate nodes if it isn't rectilinear. Also skip repeated nodes. Also, convert to vector if the aren't.""" - pl = [snap_to_grid(x) for x in self.position_list] - - self.position_list = [] - for index in range(len(pl) - 1): - if pl[index] != pl[index + 1]: - self.position_list.append(vector(pl[index])) - if (pl[index][0] != pl[index + 1][0]) and (pl[index][1] != pl[index + 1][1]): - self.position_list.append(vector(pl[index][0], pl[index + 1][1])) - self.position_list.append(vector(pl[-1])) + self.position_list = create_rectilinear_route(self.position_list) def connect_corner(self): """ Add a corner square at every corner of the path.""" diff --git a/compiler/pin_layout.py b/compiler/pin_layout.py index 0c7dc391..978dcb02 100644 --- a/compiler/pin_layout.py +++ b/compiler/pin_layout.py @@ -1,3 +1,5 @@ +import debug +from tech import GDS from vector import vector from tech import layer @@ -142,3 +144,21 @@ class pin_layout: """ Bottom center point """ return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[0].y) + + def gds_write_file(self, newLayout): + """Writes the pin shape and label to GDS""" + debug.info(4, "writing pin (" + str(self.layer) + "):" + + str(self.width()) + "x" + str(self.height()) + " @ " + str(self.ll())) + newLayout.addBox(layerNumber=layer[self.layer], + purposeNumber=0, + offsetInMicrons=self.ll(), + width=self.width(), + height=self.height(), + center=False) + newLayout.addText(text=self.name, + layerNumber=layer[self.layer], + purposeNumber=0, + offsetInMicrons=self.ll(), + magnification=GDS["zoom"], + rotate=None) + diff --git a/compiler/ptx.py b/compiler/ptx.py index 06cfd648..317e6ebd 100644 --- a/compiler/ptx.py +++ b/compiler/ptx.py @@ -3,6 +3,7 @@ import debug from tech import drc, info, spice from vector import vector from contact import contact +import path import re class ptx(design.design): @@ -146,10 +147,13 @@ class ptx(design.design): - self.poly_positions[0].x poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width) if len(self.poly_positions) > 1: - self.add_rect(layer="poly", - offset=poly_connect_position, - width=poly_connect_length, - height=drc["minwidth_poly"]) + self.remove_layout_pin("G") # only keep the main pin + self.add_layout_pin(text="G", + layer="poly", + offset=poly_connect_position, + width=poly_connect_length, + height=drc["minwidth_poly"]) + self.poly_connect_index = len(self.objs) - 1 # change the name so it is unique and specifies drain/srouce (p) routed @@ -204,11 +208,27 @@ class ptx(design.design): # allows one to connect the source and drains self.source_connect_index = None if self.source_positions: + self.remove_layout_pin("S") # remove the individual connections + self.source_positions = path.create_rectilinear_route(self.source_positions) self.add_path(("metal1"), self.source_positions) + # The source positions are odd since the second one is always redundant + # so we must use the THIRD one + self.add_center_layout_pin(text="S", + layer="metal1", + start=self.source_positions[2]-vector(0.5*drc["minwidth_metal1"],0), + end=self.source_positions[-2]+vector(0.5*drc["minwidth_metal1"],0)) self.source_connect_index = len(self.insts) - 1 self.drain_connect_index = None if self.drain_positions: + self.remove_layout_pin("D") # remove the individual connections + self.drain_positions = path.create_rectilinear_route(self.drain_positions) self.add_path(("metal1"), self.drain_positions) + # The source positions are odd since the second one is always redundant + # so we must use the THIRD one + self.add_center_layout_pin(text="D", + layer="metal1", + start=self.drain_positions[2]-vector(0.5*drc["minwidth_metal1"],0), + end=self.drain_positions[-2]+vector(0.5*drc["minwidth_metal1"],0)) self.drain_connect_index = len(self.insts) - 1 def add_poly(self): @@ -219,10 +239,11 @@ class ptx(design.design): self.poly_positions = [] # following poly(s) for i in range(0, self.mults): - self.add_rect(layer="poly", - offset=[poly_xoffset, poly_yoffset], - width=self.poly_width, - height=self.poly_height) + self.add_layout_pin(text="G", + 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"] @@ -294,9 +315,15 @@ class ptx(design.design): contact_xoffset = 0 contact_yoffset = (self.active_height - self.active_contact.height) / 2 offset = vector(contact_xoffset, contact_yoffset) - self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) + contact=self.add_contact(layers=("active", "contact", "metal1"), + 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) self.active_contact_positions.append(offset) # middle contact columns @@ -306,9 +333,16 @@ class ptx(design.design): - (drc["minwidth_contact"] / 2) - \ self.active_contact.via_layer_position.x offset = vector(contact_xoffset, contact_yoffset) - self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) + contact=self.add_contact(layers=("active", "contact", "metal1"), + 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) self.active_contact_positions.append(offset) @@ -317,9 +351,16 @@ class ptx(design.design): + self.poly_width + drc["contact_to_poly"] - \ self.active_contact.via_layer_position.x offset = vector(contact_xoffset, contact_yoffset) - self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) + contact=self.add_contact(layers=("active", "contact", "metal1"), + 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) self.active_contact_positions.append(offset) diff --git a/compiler/tests/03_ptx_3finger_nmos_test.py b/compiler/tests/03_ptx_3finger_nmos_test.py index 0fa64a8c..915e0196 100644 --- a/compiler/tests/03_ptx_3finger_nmos_test.py +++ b/compiler/tests/03_ptx_3finger_nmos_test.py @@ -27,7 +27,9 @@ class ptx_test(unittest.TestCase): debug.info(2, "Checking three fingers NMOS") fet = ptx.ptx(width=tech.drc["minwidth_tx"], mults=3, - tx_type="nmos") + tx_type="nmos", + connect_active=True, + connect_poly=True) self.local_check(fet) OPTS.check_lvsdrc = True diff --git a/compiler/tests/03_ptx_3finger_pmos_test.py b/compiler/tests/03_ptx_3finger_pmos_test.py index 96e5ac00..c5c56c6e 100644 --- a/compiler/tests/03_ptx_3finger_pmos_test.py +++ b/compiler/tests/03_ptx_3finger_pmos_test.py @@ -27,7 +27,9 @@ class ptx_test(unittest.TestCase): debug.info(2, "Checking three fingers PMOS") fet = ptx.ptx(width=tech.drc["minwidth_tx"], mults=3, - tx_type="pmos") + tx_type="pmos", + connect_active=True, + connect_poly=True) self.local_check(fet) OPTS.check_lvsdrc = True