merge local with dev

This commit is contained in:
jcirimel
2020-04-16 02:16:56 -07:00
13 changed files with 441 additions and 281 deletions
+17 -9
View File
@@ -15,6 +15,7 @@ from globals import OPTS
from utils import round_to_grid
import logical_effort
from sram_factory import factory
from errors import drc_error
class pinv(pgate.pgate):
@@ -108,11 +109,14 @@ class pinv(pgate.pgate):
# This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
self.poly_extend_active + self.poly_space)
total_height = tx_height + min_channel + 2 * self.top_bottom_space
debug.check(self.height > total_height,
"Cell height {0} too small for simple min height {1}.".format(self.height,
total_height))
total_height = tx_height + min_channel + 2 * self.top_bottom_space
# debug.check(self.height > total_height,
# "Cell height {0} too small for simple min height {1}.".format(self.height,
# total_height))
if total_height > self.height:
msg = "Cell height {0} too small for simple min height {1}.".format(self.height, total_height)
raise drc_error(msg)
# Determine the height left to the transistors to determine
# the number of fingers
@@ -144,12 +148,16 @@ class pinv(pgate.pgate):
# with LVS property mismatch errors when fingers are not a grid
# length and get rounded in the offset geometry.
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
debug.check(self.nmos_width >= drc("minwidth_tx"),
"Cannot finger NMOS transistors to fit cell height.")
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
debug.check(self.pmos_width >= drc("minwidth_tx"),
"Cannot finger PMOS transistors to fit cell height.")
# debug.check(self.nmos_width >= drc("minwidth_tx"),
# "Cannot finger NMOS transistors to fit cell height.")
if self.nmos_width < drc("minwidth_tx"):
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
#debug.check(self.pmos_width >= drc("minwidth_tx"),
# "Cannot finger PMOS transistors to fit cell height.")
if self.pmos_width < drc("minwidth_tx"):
raise drc_error("Cannot finger NMOS transistors to fit cell height.")
def add_ptx(self):
""" Create the PMOS and NMOS transistors. """
+43 -23
View File
@@ -98,7 +98,7 @@ class pnand2(pgate.pgate):
# metal spacing to allow contacts on any layer
self.input_spacing = max(self.poly_space + contact.poly_contact.first_layer_width,
self.m1_space + contact.m1_via.first_layer_width,
self.m2_space + contact.m2_via.first_layer_width,
self.m2_space + contact.m2_via.first_layer_width,
self.m3_space + contact.m2_via.second_layer_width)
@@ -173,13 +173,15 @@ class pnand2(pgate.pgate):
0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos_nd.active_height))
def add_well_contacts(self):
"""
"""
Add n/p well taps to the layout and connect to supplies
AFTER the wells are created
"""
self.add_nwell_contact(self.pmos, self.pmos2_pos)
self.add_pwell_contact(self.nmos_nd, self.nmos2_pos)
self.add_nwell_contact(self.pmos,
self.pmos2_pos + vector(self.m1_pitch, 0))
self.add_pwell_contact(self.nmos_nd,
self.nmos2_pos + vector(self.m1_pitch, 0))
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
@@ -197,7 +199,7 @@ class pnand2(pgate.pgate):
self.nmos2_inst,
inputB_yoffset,
"B",
position="right")
position="center")
# This will help with the wells and the input/output placement
self.inputA_yoffset = self.pmos2_inst.by() - self.poly_extend_active \
@@ -209,6 +211,7 @@ class pnand2(pgate.pgate):
def route_output(self):
""" Route the Z output """
# PMOS1 drain
pmos_pin = self.pmos1_inst.get_pin("D")
top_pin_offset = pmos_pin.center()
@@ -217,29 +220,46 @@ class pnand2(pgate.pgate):
bottom_pin_offset = nmos_pin.center()
# Output pin
out_offset = vector(nmos_pin.center().x + self.m1_pitch,
c_pin = self.get_pin("B")
out_offset = vector(c_pin.cx() + self.m1_pitch,
self.inputA_yoffset)
# Midpoints of the L routes go horizontal first then vertical
mid1_offset = vector(out_offset.x, top_pin_offset.y)
# This routes on M2
# # Midpoints of the L routes go horizontal first then vertical
# mid1_offset = vector(out_offset.x, top_pin_offset.y)
# mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
# # Non-preferred active contacts
# self.add_via_center(layers=self.m1_stack,
# directions=("V", "H"),
# offset=pmos_pin.center())
# # Non-preferred active contacts
# self.add_via_center(layers=self.m1_stack,
# directions=("V", "H"),
# offset=nmos_pin.center())
# self.add_via_center(layers=self.m1_stack,
# offset=out_offset)
# # PMOS1 to mid-drain to NMOS2 drain
# self.add_path("m2",
# [top_pin_offset, mid1_offset, out_offset,
# mid2_offset, bottom_pin_offset])
# This routes on M1
# Midpoints of the L routes goes vertical first then horizontal
mid1_offset = vector(top_pin_offset.x, out_offset.y)
# Midpoints of the L routes goes horizontal first then vertical
mid2_offset = vector(out_offset.x, bottom_pin_offset.y)
# Non-preferred active contacts
self.add_via_center(layers=self.m1_stack,
directions=("V", "H"),
offset=pmos_pin.center())
# Non-preferred active contacts
self.add_via_center(layers=self.m1_stack,
directions=("V", "H"),
offset=nmos_pin.center())
self.add_via_center(layers=self.m1_stack,
offset=out_offset)
self.add_path("m1",
[top_pin_offset, mid1_offset, out_offset])
# Route in two segments to have the width rule
self.add_path("m1",
[bottom_pin_offset, mid2_offset + vector(0.5 * self.m1_width, 0)],
width=nmos_pin.height())
self.add_path("m1",
[mid2_offset, out_offset])
# PMOS1 to mid-drain to NMOS2 drain
self.add_path("m2",
[top_pin_offset, mid1_offset, out_offset,
mid2_offset, bottom_pin_offset])
# This extends the output to the edge of the cell
self.add_layout_pin_rect_center(text="Z",
layer="m1",
+57 -23
View File
@@ -12,6 +12,7 @@ from tech import drc, parameter, spice
from vector import vector
import logical_effort
from sram_factory import factory
from globals import OPTS
class pnand3(pgate.pgate):
@@ -190,8 +191,10 @@ class pnand3(pgate.pgate):
def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """
self.add_nwell_contact(self.pmos, self.pmos3_pos)
self.add_pwell_contact(self.nmos_ns, self.nmos3_pos)
self.add_nwell_contact(self.pmos,
self.pmos3_pos + vector(self.m1_pitch, 0))
self.add_pwell_contact(self.nmos_ns,
self.nmos3_pos + vector(self.m1_pitch, 0))
def connect_rails(self):
""" Connect the nmos and pmos to its respective power rails """
@@ -220,18 +223,22 @@ class pnand3(pgate.pgate):
self.nmos3_inst,
self.inputC_yoffset,
"C",
position="center")
position="right")
# FIXME: constant hack
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
if OPTS.tech_name == "s8":
self.inputA_yoffset = self.inputB_yoffset + 1.15 * m1_pitch
else:
self.inputA_yoffset = self.inputB_yoffset + 1.12 * m1_pitch
self.route_input_gate(self.pmos1_inst,
self.nmos1_inst,
self.inputA_yoffset,
"A",
position="center")
position="left")
def route_output(self):
""" Route the Z output """
# PMOS1 drain
pmos1_pin = self.pmos1_inst.get_pin("D")
# PMOS3 drain
@@ -239,29 +246,56 @@ class pnand3(pgate.pgate):
# NMOS3 drain
nmos3_pin = self.nmos3_inst.get_pin("D")
# Go up to metal2 for ease on all output pins
self.add_via_center(layers=self.m1_stack,
offset=pmos1_pin.center(),
directions=("V", "V"))
self.add_via_center(layers=self.m1_stack,
offset=pmos3_pin.center(),
directions=("V", "V"))
self.add_via_center(layers=self.m1_stack,
offset=nmos3_pin.center(),
directions=("V", "V"))
# midpoint for routing
mid_offset = vector(nmos3_pin.cx() + self.m1_pitch,
self.inputA_yoffset)
# Aligned with the well taps
out_offset = vector(self.nwell_contact.cx(),
self.inputA_yoffset)
# PMOS3 and NMOS3 are drain aligned
self.add_path("m2", [pmos3_pin.center(), nmos3_pin.center()])
# Route in the A input track (top track)
mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
self.add_path("m2", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
# Go up to metal2 for ease on all output pins
# self.add_via_center(layers=self.m1_stack,
# offset=pmos1_pin.center(),
# directions=("V", "V"))
# self.add_via_center(layers=self.m1_stack,
# offset=pmos3_pin.center(),
# directions=("V", "V"))
# self.add_via_center(layers=self.m1_stack,
# offset=nmos3_pin.center(),
# directions=("V", "V"))
# # Route in the A input track (top track)
# mid_offset = vector(nmos3_pin.center().x, self.inputA_yoffset)
# self.add_path("m1", [pmos1_pin.center(), mid_offset, nmos3_pin.uc()])
# This extends the output to the edge of the cell
self.add_via_center(layers=self.m1_stack,
offset=mid_offset)
# self.add_via_center(layers=self.m1_stack,
# offset=mid_offset)
top_left_pin_offset = pmos1_pin.center()
top_right_pin_offset = pmos3_pin.center()
bottom_pin_offset = nmos3_pin.center()
# PMOS1 to output
self.add_path("m1", [top_left_pin_offset,
vector(top_left_pin_offset.x, out_offset.y),
out_offset])
# PMOS3 to output
self.add_path("m1", [top_right_pin_offset,
vector(top_right_pin_offset.x, mid_offset.y),
mid_offset])
# NMOS3 to output
mid2_offset = vector(mid_offset.x, bottom_pin_offset.y)
self.add_path("m1",
[bottom_pin_offset, mid2_offset],
width=nmos3_pin.height())
mid3_offset = vector(mid_offset.x, nmos3_pin.by())
self.add_path("m1", [mid3_offset, mid_offset])
self.add_layout_pin_rect_center(text="Z",
layer="m1",
offset=mid_offset,
offset=out_offset,
width=contact.m1_via.first_layer_width,
height=contact.m1_via.first_layer_height)
+25 -17
View File
@@ -107,10 +107,7 @@ class ptx(design.design):
# be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
if OPTS.tech_name == None:
print("here {0}".format(self.name))
if OPTS.tech_name == "s8":
# s8 technology is in microns
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
@@ -474,13 +471,13 @@ class ptx(design.design):
"""Returns an object representing the parameters for delay in tau units."""
# FIXME: Using the same definition as the pinv.py.
parasitic_delay = 1
size = self.mults*self.tx_width/drc("minwidth_tx")
return logical_effort.logical_effort(self.name,
size,
self.input_load(),
cout,
parasitic_delay)
parasitic_delay = 1
size = self.mults * self.tx_width / drc("minwidth_tx")
return logical_effort.logical_effort(self.name,
size,
self.input_load(),
cout,
parasitic_delay)
def input_load(self):
"""
@@ -488,7 +485,7 @@ class ptx(design.design):
"""
# FIXME: this will be applied for the loads of the drain/source
return self.mults*self.tx_width/drc("minwidth_tx")
return self.mults * self.tx_width / drc("minwidth_tx")
def add_diff_contact(self, label, pos):
contact=self.add_via_center(layers=self.active_stack,
@@ -499,14 +496,25 @@ class ptx(design.design):
well_type=self.well_type)
if hasattr(self, "li_stack"):
self.add_via_center(layers=self.li_stack,
offset=pos)
contact=self.add_via_center(layers=self.li_stack,
offset=pos,
directions=("V", "V"))
# contact_area = contact.mod.second_layer_width * contact.mod.second_layer_height
# min_area = drc("minarea_m1")
# width = contact.mod.second_layer_width
# if contact_area < min_area:
# height = min_area / width
# else:
# height = contact.mod.second_layer_height
width = contact.mod.second_layer_width
height = contact.mod.second_layer_height
self.add_layout_pin_rect_center(text=label,
layer="m1",
offset=pos,
width=contact.mod.second_layer_width,
height=contact.mod.second_layer_height)
width=width,
height=height)
return(contact)
def get_cin(self):