mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
b2043bef11
commit
a9797d12ab
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue