Skip to content

Commit 33a3210

Browse files
committed
DRC and LVS fixes for pinv_dec
1 parent 443b8fb commit 33a3210

File tree

5 files changed

+60
-27
lines changed

5 files changed

+60
-27
lines changed

compiler/base/hierarchy_design.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ def __init__(self, name):
2727
# If we have a separate lvs directory, then all the lvs files
2828
# should be in there (all or nothing!)
2929
lvs_dir = OPTS.openram_tech + "lvs_lib/"
30-
if os.path.exists(lvs_dir):
30+
# Calibre will do the scaling in s8
31+
if os.path.exists(lvs_dir): # and OPTS.lvs_exe[0]!="calibre":
3132
self.lvs_file = lvs_dir + name + ".sp"
3233
else:
3334
self.lvs_file = self.sp_file

compiler/modules/dff_buf.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def route_wires(self):
133133
q_pin = self.dff_inst.get_pin("Q")
134134
a1_pin = self.inv1_inst.get_pin("A")
135135
mid1 = vector(a1_pin.cx(), q_pin.cy())
136-
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()])
136+
self.add_path(q_pin.layer, [q_pin.center(), mid1, a1_pin.center()], width=q_pin.height())
137137
self.add_via_stack_center(from_layer=a1_pin.layer,
138138
to_layer=q_pin.layer,
139139
offset=a1_pin.center())
@@ -177,8 +177,8 @@ def add_layout_pins(self):
177177
height=din_pin.height())
178178

179179
dout_pin = self.inv2_inst.get_pin("Z")
180-
mid_pos = dout_pin.center() + vector(self.m1_nonpref_pitch, 0)
181-
q_pos = mid_pos - vector(0, self.m2_pitch)
180+
mid_pos = dout_pin.center() + vector(self.m2_nonpref_pitch, 0)
181+
q_pos = mid_pos - vector(0, 2 * self.m2_nonpref_pitch)
182182
self.add_layout_pin_rect_center(text="Q",
183183
layer="m2",
184184
offset=q_pos)
@@ -187,7 +187,7 @@ def add_layout_pins(self):
187187
to_layer="m2",
188188
offset=q_pos)
189189

190-
qb_pos = self.mid_qb_pos + vector(0, self.m2_pitch)
190+
qb_pos = self.mid_qb_pos + vector(0, 2 * self.m2_nonpref_pitch)
191191
self.add_layout_pin_rect_center(text="Qb",
192192
layer="m2",
193193
offset=qb_pos)

compiler/pgates/pinv_dec.py

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -109,31 +109,30 @@ def extend_wells(self):
109109
self.add_rect(layer="pwell",
110110
offset=ll,
111111
width=ur.x - ll.x,
112-
height=self.height - ll.y)
112+
height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active)
113113

114114
if "nwell" in layer:
115115
ll = self.pmos_inst.ll() - self.pmos_inst.mod.active_offset
116116
ur = self.pmos_inst.ur() + self.pmos_inst.mod.active_offset
117117
self.add_rect(layer="nwell",
118-
offset=ll - vector(self.nwell_enclose_active, 0),
119-
width=ur.x - ll.x + self.nwell_enclose_active,
120-
height=self.height - ll.y + 2 * self.nwell_enclose_active)
118+
offset=ll,
119+
width=ur.x - ll.x,
120+
height=self.height - ll.y + 0.5 * self.nwell_contact.height + self.well_enclose_active)
121121

122122
def place_ptx(self):
123123
"""
124124
"""
125125

126126
# offset so that the input contact is over from the left edge by poly spacing
127127
x_offset = self.nmos.active_offset.y + contact.poly_contact.width + self.poly_space
128-
# center the transistor in the y-dimension
128+
# bottom of the transistor in the y-dimension
129129
y_offset = self.nmos.width + self.active_space
130130
self.nmos_pos = vector(x_offset, y_offset)
131-
self.nmos_inst.place(self.nmos_pos)
132131
self.nmos_inst.place(self.nmos_pos,
133132
rotate=270)
134133
# place PMOS so it is half a poly spacing down from the top
135-
xoffset = self.nmos_inst.height + 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
136-
self.pmos_pos = self.nmos_pos + vector(xoffset, 0)
134+
xoffset = self.nmos_inst.rx() + 2 * self.poly_extend_active + 2 * self.well_extend_active + drc("pwell_to_nwell")
135+
self.pmos_pos = vector(xoffset, y_offset)
137136
self.pmos_inst.place(self.pmos_pos,
138137
rotate=270)
139138

@@ -142,6 +141,31 @@ def place_ptx(self):
142141
nmos_drain_pos = self.nmos_inst.get_pin("D").center()
143142
self.output_pos = vector(0.5 * (pmos_drain_pos.x + nmos_drain_pos.x), nmos_drain_pos.y)
144143

144+
if OPTS.tech_name == "s8":
145+
self.add_implants()
146+
147+
def add_implants(self):
148+
"""
149+
Add top-to-bottom implants for adjacency issues in s8.
150+
"""
151+
# Route to the bottom
152+
ll = (self.nmos_inst.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0)
153+
# Don't route to the top
154+
ur = self.nmos_inst.ur() + vector(self.implant_enclose_active, 0)
155+
self.add_rect("nimplant",
156+
ll,
157+
ur.x - ll.x,
158+
ur.y - ll.y)
159+
160+
# Route to the bottom
161+
ll = (self.pmos_inst.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0)
162+
# Don't route to the top
163+
ur = self.pmos_inst.ur() + vector(self.implant_enclose_active, 0)
164+
self.add_rect("pimplant",
165+
ll,
166+
ur.x - ll.x,
167+
ur.y - ll.y)
168+
145169
def route_outputs(self):
146170
"""
147171
Route the output (drains) together.

compiler/pgates/ptx.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
from globals import OPTS
1717
from pgate import pgate
1818

19+
1920
class ptx(design.design):
2021
"""
2122
This module generates gds and spice of a parametrically NMOS or
@@ -24,6 +25,10 @@ class ptx(design.design):
2425
given width. Total width is therefore mults*width. Options allow
2526
you to connect the fingered gates and active for parallel devices.
2627
The add_*_contact option tells which layer to bring source/drain up to.
28+
29+
ll, ur, width and height refer to the active area.
30+
Wells and poly may extend beyond this.
31+
2732
"""
2833
def __init__(self,
2934
name="",
@@ -221,15 +226,13 @@ def setup_layout_constants(self):
221226
well_width_rule)
222227
self.well_height = max(self.active_height + 2 * self.well_enclose_active,
223228
well_width_rule)
224-
# We are going to shift the 0,0, so include that in the width and height
225-
self.height = self.well_height - self.active_offset.y
226-
self.width = self.well_width - self.active_offset.x
227229
else:
228-
# The well is not included in the height and width
229-
self.height = self.poly_height
230-
self.width = self.active_width
231230
self.well_height = self.height
232231
self.well_width = self.width
232+
233+
# We are going to shift the 0,0, so include that in the width and height
234+
self.height = self.active_height
235+
self.width = self.active_width
233236

234237
# This is the center of the first active contact offset (centered vertically)
235238
self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width,
@@ -353,18 +356,18 @@ def add_active(self):
353356
"""
354357
Adding the diffusion (active region = diffusion region)
355358
"""
356-
self.add_rect(layer="active",
357-
offset=self.active_offset,
358-
width=self.active_width,
359-
height=self.active_height)
359+
self.active = self.add_rect(layer="active",
360+
offset=self.active_offset,
361+
width=self.active_width,
362+
height=self.active_height)
360363
# If the implant must enclose the active, shift offset
361364
# and increase width/height
362365
enclose_width = self.implant_enclose_active
363366
enclose_offset = [enclose_width] * 2
364-
self.add_rect(layer="{}implant".format(self.implant_type),
365-
offset=self.active_offset - enclose_offset,
366-
width=self.active_width + 2 * enclose_width,
367-
height=self.active_height + 2 * enclose_width)
367+
self.implant = self.add_rect(layer="{}implant".format(self.implant_type),
368+
offset=self.active_offset - enclose_offset,
369+
width=self.active_width + 2 * enclose_width,
370+
height=self.active_height + 2 * enclose_width)
368371

369372
def add_well_implant(self):
370373
"""

compiler/tests/04_pinv_dec_1x_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ def runTest(self):
2121
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
2222
globals.init_openram(config_file)
2323

24+
OPTS.num_rw_ports = 1
25+
OPTS.num_r_ports = 1
26+
OPTS.num_w_ports = 0
27+
globals.setup_bitcell()
28+
2429
debug.info(2, "Checking 1x size decoder inverter")
2530
tx = factory.create(module_type="pinv_dec", size=1)
2631
self.local_check(tx)

0 commit comments

Comments
 (0)