From 33a32101c9831465ed0e98cd7251acc77ead348a Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 12 Jun 2020 15:23:51 -0700 Subject: [PATCH] DRC and LVS fixes for pinv_dec --- compiler/base/hierarchy_design.py | 3 +- compiler/modules/dff_buf.py | 8 +++--- compiler/pgates/pinv_dec.py | 40 +++++++++++++++++++++------ compiler/pgates/ptx.py | 31 +++++++++++---------- compiler/tests/04_pinv_dec_1x_test.py | 5 ++++ 5 files changed, 60 insertions(+), 27 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index bb57ae3e..87331315 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -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 diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index 81629771..a1e54a4d 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -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) diff --git a/compiler/pgates/pinv_dec.py b/compiler/pgates/pinv_dec.py index f12a620b..10c8d2fb 100644 --- a/compiler/pgates/pinv_dec.py +++ b/compiler/pgates/pinv_dec.py @@ -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. diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index fb215d78..c4c53a70 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -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): """ diff --git a/compiler/tests/04_pinv_dec_1x_test.py b/compiler/tests/04_pinv_dec_1x_test.py index 8876ab58..92772616 100755 --- a/compiler/tests/04_pinv_dec_1x_test.py +++ b/compiler/tests/04_pinv_dec_1x_test.py @@ -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)