DRC and LVS fixes for pinv_dec

This commit is contained in:
mrg 2020-06-12 15:23:51 -07:00
parent 443b8fbe23
commit 33a32101c9
5 changed files with 60 additions and 27 deletions

View File

@ -27,7 +27,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
# If we have a separate lvs directory, then all the lvs files
# should be in there (all or nothing!)
lvs_dir = OPTS.openram_tech + "lvs_lib/"
if os.path.exists(lvs_dir):
# Calibre will do the scaling in s8
if os.path.exists(lvs_dir): # and OPTS.lvs_exe[0]!="calibre":
self.lvs_file = lvs_dir + name + ".sp"
else:
self.lvs_file = self.sp_file

View File

@ -133,7 +133,7 @@ class dff_buf(design.design):
q_pin = self.dff_inst.get_pin("Q")
a1_pin = self.inv1_inst.get_pin("A")
mid1 = vector(a1_pin.cx(), q_pin.cy())
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()])
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()], width=q_pin.height())
self.add_via_stack_center(from_layer=a1_pin.layer,
to_layer=q_pin.layer,
offset=a1_pin.center())
@ -177,8 +177,8 @@ class dff_buf(design.design):
height=din_pin.height())
dout_pin = self.inv2_inst.get_pin("Z")
mid_pos = dout_pin.center() + vector(self.m1_nonpref_pitch, 0)
q_pos = mid_pos - vector(0, self.m2_pitch)
mid_pos = dout_pin.center() + vector(self.m2_nonpref_pitch, 0)
q_pos = mid_pos - vector(0, 2 * self.m2_nonpref_pitch)
self.add_layout_pin_rect_center(text="Q",
layer="m2",
offset=q_pos)
@ -187,7 +187,7 @@ class dff_buf(design.design):
to_layer="m2",
offset=q_pos)
qb_pos = self.mid_qb_pos + vector(0, self.m2_pitch)
qb_pos = self.mid_qb_pos + vector(0, 2 * self.m2_nonpref_pitch)
self.add_layout_pin_rect_center(text="Qb",
layer="m2",
offset=qb_pos)

View File

@ -109,15 +109,15 @@ class pinv_dec(pinv.pinv):
self.add_rect(layer="pwell",
offset=ll,
width=ur.x - ll.x,
height=self.height - ll.y)
height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active)
if "nwell" in layer:
ll = self.pmos_inst.ll() - self.pmos_inst.mod.active_offset
ur = self.pmos_inst.ur() + self.pmos_inst.mod.active_offset
self.add_rect(layer="nwell",
offset=ll - vector(self.nwell_enclose_active, 0),
width=ur.x - ll.x + self.nwell_enclose_active,
height=self.height - ll.y + 2 * self.nwell_enclose_active)
offset=ll,
width=ur.x - ll.x,
height=self.height - ll.y + 0.5 * self.nwell_contact.height + self.well_enclose_active)
def place_ptx(self):
"""
@ -125,15 +125,14 @@ class pinv_dec(pinv.pinv):
# offset so that the input contact is over from the left edge by poly spacing
x_offset = self.nmos.active_offset.y + contact.poly_contact.width + self.poly_space
# center the transistor in the y-dimension
# bottom of the transistor in the y-dimension
y_offset = self.nmos.width + self.active_space
self.nmos_pos = vector(x_offset, y_offset)
self.nmos_inst.place(self.nmos_pos)
self.nmos_inst.place(self.nmos_pos,
rotate=270)
# place PMOS so it is half a poly spacing down from the top
xoffset = self.nmos_inst.height + 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
self.pmos_pos = self.nmos_pos + vector(xoffset, 0)
xoffset = self.nmos_inst.rx() + 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
self.pmos_pos = vector(xoffset, y_offset)
self.pmos_inst.place(self.pmos_pos,
rotate=270)
@ -142,6 +141,31 @@ class pinv_dec(pinv.pinv):
nmos_drain_pos = self.nmos_inst.get_pin("D").center()
self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y)
if OPTS.tech_name == "s8":
self.add_implants()
def add_implants(self):
"""
Add top-to-bottom implants for adjacency issues in s8.
"""
# Route to the bottom
ll = (self.nmos_inst.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0)
# Don't route to the top
ur = self.nmos_inst.ur() + vector(self.implant_enclose_active, 0)
self.add_rect("nimplant",
ll,
ur.x - ll.x,
ur.y - ll.y)
# Route to the bottom
ll = (self.pmos_inst.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0)
# Don't route to the top
ur = self.pmos_inst.ur() + vector(self.implant_enclose_active, 0)
self.add_rect("pimplant",
ll,
ur.x - ll.x,
ur.y - ll.y)
def route_outputs(self):
"""
Route the output (drains) together.

View File

@ -16,6 +16,7 @@ import os
from globals import OPTS
from pgate import pgate
class ptx(design.design):
"""
This module generates gds and spice of a parametrically NMOS or
@ -24,6 +25,10 @@ class ptx(design.design):
given width. Total width is therefore mults*width. Options allow
you to connect the fingered gates and active for parallel devices.
The add_*_contact option tells which layer to bring source/drain up to.
ll, ur, width and height refer to the active area.
Wells and poly may extend beyond this.
"""
def __init__(self,
name="",
@ -221,15 +226,13 @@ class ptx(design.design):
well_width_rule)
self.well_height = max(self.active_height + 2 * self.well_enclose_active,
well_width_rule)
# We are going to shift the 0,0, so include that in the width and height
self.height = self.well_height - self.active_offset.y
self.width = self.well_width - self.active_offset.x
else:
# The well is not included in the height and width
self.height = self.poly_height
self.width = self.active_width
self.well_height = self.height
self.well_width = self.width
# We are going to shift the 0,0, so include that in the width and height
self.height = self.active_height
self.width = self.active_width
# This is the center of the first active contact offset (centered vertically)
self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width,
@ -353,18 +356,18 @@ class ptx(design.design):
"""
Adding the diffusion (active region = diffusion region)
"""
self.add_rect(layer="active",
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
self.active = self.add_rect(layer="active",
offset=self.active_offset,
width=self.active_width,
height=self.active_height)
# If the implant must enclose the active, shift offset
# and increase width/height
enclose_width = self.implant_enclose_active
enclose_offset = [enclose_width] * 2
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset,
width=self.active_width + 2 * enclose_width,
height=self.active_height + 2 * enclose_width)
self.implant = self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset,
width=self.active_width + 2 * enclose_width,
height=self.active_height + 2 * enclose_width)
def add_well_implant(self):
"""

View File

@ -21,6 +21,11 @@ class pinv_dec_1x_test(openram_test):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
OPTS.num_rw_ports = 1
OPTS.num_r_ports = 1
OPTS.num_w_ports = 0
globals.setup_bitcell()
debug.info(2, "Checking 1x size decoder inverter")
tx = factory.create(module_type="pinv_dec", size=1)
self.local_check(tx)