Added pins to the ptx class. Modified pin class to do lazy write of GDS shapes to allow removal of pins.

This commit is contained in:
Matt Guthaus 2017-10-05 17:35:05 -07:00
parent b2043bef11
commit a9797d12ab
6 changed files with 108 additions and 38 deletions

View File

@ -172,6 +172,9 @@ class layout:
self.add_layout_pin(text, layer, ll_offset, width, height) 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): def add_layout_pin(self, text, layer, offset, width=None, height=None):
"""Create a labeled pin """ """Create a labeled pin """
@ -179,13 +182,6 @@ class layout:
width=drc["minwidth_{0}".format(layer)] width=drc["minwidth_{0}".format(layer)]
if height==None: if height==None:
height=drc["minwidth_{0}".format(layer)] 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) new_pin = pin_layout(text, [offset,offset+vector(width,height)], layer)
@ -384,6 +380,9 @@ class layout:
i.gds_write_file(newLayout) i.gds_write_file(newLayout)
for i in self.objs: for i in self.objs:
i.gds_write_file(newLayout) 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 self.visited = True
def gds_write(self, gds_name): def gds_write(self, gds_name):

View File

@ -4,6 +4,20 @@ import debug
from vector import vector from vector import vector
from utils import snap_to_grid 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(): class path():
""" """
Object metal path; given the layer type Object metal path; given the layer type
@ -27,23 +41,15 @@ class path():
def create_layout(self): def create_layout(self):
self.create_rectilinear_route() self.create_rectilinear()
self.connect_corner() self.connect_corner()
self.create_rectangles() self.create_rectangles()
# wires and paths should not be offset to (0,0) # 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 """ Add intermediate nodes if it isn't rectilinear. Also skip
repeated nodes. Also, convert to vector if the aren't.""" repeated nodes. Also, convert to vector if the aren't."""
pl = [snap_to_grid(x) for x in self.position_list] self.position_list = create_rectilinear_route(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]))
def connect_corner(self): def connect_corner(self):
""" Add a corner square at every corner of the path.""" """ Add a corner square at every corner of the path."""

View File

@ -1,3 +1,5 @@
import debug
from tech import GDS
from vector import vector from vector import vector
from tech import layer from tech import layer
@ -142,3 +144,21 @@ class pin_layout:
""" Bottom center point """ """ Bottom center point """
return vector(0.5*(self.rect[0].x+self.rect[1].x),self.rect[0].y) 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)

View File

@ -3,6 +3,7 @@ import debug
from tech import drc, info, spice from tech import drc, info, spice
from vector import vector from vector import vector
from contact import contact from contact import contact
import path
import re import re
class ptx(design.design): class ptx(design.design):
@ -146,10 +147,13 @@ class ptx(design.design):
- self.poly_positions[0].x - self.poly_positions[0].x
poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width) poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width)
if len(self.poly_positions) > 1: if len(self.poly_positions) > 1:
self.add_rect(layer="poly", self.remove_layout_pin("G") # only keep the main pin
offset=poly_connect_position, self.add_layout_pin(text="G",
width=poly_connect_length, layer="poly",
height=drc["minwidth_poly"]) offset=poly_connect_position,
width=poly_connect_length,
height=drc["minwidth_poly"])
self.poly_connect_index = len(self.objs) - 1 self.poly_connect_index = len(self.objs) - 1
# change the name so it is unique and specifies drain/srouce (p) routed # 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 # allows one to connect the source and drains
self.source_connect_index = None self.source_connect_index = None
if self.source_positions: 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) 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.source_connect_index = len(self.insts) - 1
self.drain_connect_index = None self.drain_connect_index = None
if self.drain_positions: 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) 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 self.drain_connect_index = len(self.insts) - 1
def add_poly(self): def add_poly(self):
@ -219,10 +239,11 @@ class ptx(design.design):
self.poly_positions = [] self.poly_positions = []
# following poly(s) # following poly(s)
for i in range(0, self.mults): for i in range(0, self.mults):
self.add_rect(layer="poly", self.add_layout_pin(text="G",
offset=[poly_xoffset, poly_yoffset], layer="poly",
width=self.poly_width, offset=[poly_xoffset, poly_yoffset],
height=self.poly_height) width=self.poly_width,
height=self.poly_height)
self.poly_positions.append(vector(poly_xoffset, poly_yoffset)) self.poly_positions.append(vector(poly_xoffset, poly_yoffset))
poly_xoffset += self.mults_poly_to_poly + drc["minwidth_poly"] poly_xoffset += self.mults_poly_to_poly + drc["minwidth_poly"]
@ -294,9 +315,15 @@ class ptx(design.design):
contact_xoffset = 0 contact_xoffset = 0
contact_yoffset = (self.active_height - self.active_contact.height) / 2 contact_yoffset = (self.active_height - self.active_contact.height) / 2
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), contact=self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_contacts)) 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) self.active_contact_positions.append(offset)
# middle contact columns # middle contact columns
@ -306,9 +333,16 @@ class ptx(design.design):
- (drc["minwidth_contact"] / 2) - \ - (drc["minwidth_contact"] / 2) - \
self.active_contact.via_layer_position.x self.active_contact.via_layer_position.x
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), contact=self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_contacts)) 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) self.active_contact_positions.append(offset)
@ -317,9 +351,16 @@ class ptx(design.design):
+ self.poly_width + drc["contact_to_poly"] - \ + self.poly_width + drc["contact_to_poly"] - \
self.active_contact.via_layer_position.x self.active_contact.via_layer_position.x
offset = vector(contact_xoffset, contact_yoffset) offset = vector(contact_xoffset, contact_yoffset)
self.add_contact(layers=("active", "contact", "metal1"), contact=self.add_contact(layers=("active", "contact", "metal1"),
offset=offset, offset=offset,
size=(1, self.num_contacts)) 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) self.active_contact_positions.append(offset)

View File

@ -27,7 +27,9 @@ class ptx_test(unittest.TestCase):
debug.info(2, "Checking three fingers NMOS") debug.info(2, "Checking three fingers NMOS")
fet = ptx.ptx(width=tech.drc["minwidth_tx"], fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=3, mults=3,
tx_type="nmos") tx_type="nmos",
connect_active=True,
connect_poly=True)
self.local_check(fet) self.local_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True

View File

@ -27,7 +27,9 @@ class ptx_test(unittest.TestCase):
debug.info(2, "Checking three fingers PMOS") debug.info(2, "Checking three fingers PMOS")
fet = ptx.ptx(width=tech.drc["minwidth_tx"], fet = ptx.ptx(width=tech.drc["minwidth_tx"],
mults=3, mults=3,
tx_type="pmos") tx_type="pmos",
connect_active=True,
connect_poly=True)
self.local_check(fet) self.local_check(fet)
OPTS.check_lvsdrc = True OPTS.check_lvsdrc = True