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)
|
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,14 +182,7 @@ 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)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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."""
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue