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)
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):

View File

@ -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."""

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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