This commit is contained in:
jcirimel
2020-06-25 06:32:29 -07:00
29 changed files with 265 additions and 114 deletions
+31 -4
View File
@@ -43,6 +43,9 @@ class pgate(design.design):
self.route_layer_space = getattr(self, "{}_space".format(self.route_layer))
self.route_layer_pitch = getattr(self, "{}_pitch".format(self.route_layer))
# hack for enclosing input pin with npc
self.input_pin_vias = []
# This is the space from a S/D contact to the supply rail
contact_to_vdd_rail_space = 0.5 * self.route_layer_width + self.route_layer_space
# This is a poly-to-poly of a flipped cell
@@ -132,6 +135,8 @@ class pgate(design.design):
offset=contact_offset,
directions=directions)
self.input_pin_vias.append(via)
self.add_layout_pin_rect_center(text=name,
layer=self.route_layer,
offset=contact_offset,
@@ -146,11 +151,33 @@ class pgate(design.design):
height=contact.poly_contact.first_layer_width,
width=left_gate_offset.x - contact_offset.x)
def enclose_npc(self):
""" Enclose the poly contacts with npc layer """
ll = None
ur = None
for via in self.input_pin_vias:
# Find ll/ur
if not ll:
ll = via.ll()
else:
ll = ll.min(via.ll())
if not ur:
ur = via.ur()
else:
ur = ur.max(via.ur())
npc_enclose_poly = drc("npc_enclose_poly")
npc_enclose_offset = vector(npc_enclose_poly, npc_enclose_poly)
self.add_rect(layer="npc",
offset=ll - npc_enclose_offset,
width=(ur.x - ll.x) + 2 * npc_enclose_poly,
height=(ur.y - ll.y) + 2 * npc_enclose_poly)
def extend_wells(self):
""" Extend the n/p wells to cover whole cell """
# This should match the cells in the cell library
self.nwell_y_offset = 0.48 * self.height
self.nwell_yoffset = 0.48 * self.height
full_height = self.height + 0.5 * self.m1_width
# FIXME: float rounding problem
@@ -158,8 +185,8 @@ class pgate(design.design):
# Add a rail width to extend the well to the top of the rail
nwell_max_offset = max(self.find_highest_layer_coords("nwell").y,
full_height)
nwell_position = vector(0, self.nwell_y_offset) - vector(self.well_extend_active, 0)
nwell_height = nwell_max_offset - self.nwell_y_offset
nwell_position = vector(0, self.nwell_yoffset) - vector(self.well_extend_active, 0)
nwell_height = nwell_max_offset - self.nwell_yoffset
self.add_rect(layer="nwell",
offset=nwell_position,
width=self.width + 2 * self.well_extend_active,
@@ -175,7 +202,7 @@ class pgate(design.design):
pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y,
-0.5 * self.m1_width)
pwell_position = vector(-self.well_extend_active, pwell_min_offset)
pwell_height = self.nwell_y_offset - pwell_position.y
pwell_height = self.nwell_yoffset - pwell_position.y
self.add_rect(layer="pwell",
offset=pwell_position,
width=self.width + 2 * self.well_extend_active,
+6 -2
View File
@@ -184,7 +184,7 @@ class pnand2(pgate.pgate):
# doesn't use nmos uy because that is calculated using offset + poly height
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact,
active_to_poly_contact2)
@@ -200,7 +200,7 @@ class pnand2(pgate.pgate):
# active_contact_to_poly_contact = self.output_yoffset - self.route_layer_space - 0.5 * contact.poly_contact.second_layer_height
# active_bottom = self.pmos1_inst.by()
# active_to_poly_contact = active_bottom - self.poly_to_active - 0.5 * contact.poly_contact.first_layer_height
# active_to_poly_contact2 = active_bottom - drc("contact_to_gate") - 0.5 * self.route_layer_width
# active_to_poly_contact2 = active_bottom - self.poly_contact_to_gate - 0.5 * self.route_layer_width
# self.inputB_yoffset = min(active_contact_to_poly_contact,
# active_to_poly_contact,
# active_to_poly_contact2)
@@ -212,6 +212,10 @@ class pnand2(pgate.pgate):
"B",
position="center")
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """
+6 -4
View File
@@ -222,7 +222,7 @@ class pnand3(pgate.pgate):
# doesn't use nmos uy because that is calculated using offset + poly height
active_top = self.nmos1_inst.by() + self.nmos1_inst.mod.active_height
active_to_poly_contact = active_top + self.poly_to_active + 0.5 * contact.poly_contact.first_layer_height
active_to_poly_contact2 = active_top + drc("contact_to_gate") + 0.5 * self.route_layer_width
active_to_poly_contact2 = active_top + self.poly_contact_to_gate + 0.5 * self.route_layer_width
self.inputA_yoffset = max(active_contact_to_poly_contact,
active_to_poly_contact,
active_to_poly_contact2)
@@ -233,20 +233,22 @@ class pnand3(pgate.pgate):
"A",
position="left")
# Put B right on the well line
self.inputB_yoffset = self.inputA_yoffset + non_contact_pitch
self.inputB_yoffset = self.inputA_yoffset + self.m3_pitch
self.route_input_gate(self.pmos2_inst,
self.nmos2_inst,
self.inputB_yoffset,
"B",
position="center")
self.inputC_yoffset = self.inputB_yoffset + non_contact_pitch
self.inputC_yoffset = self.inputB_yoffset + self.m3_pitch
self.route_input_gate(self.pmos3_inst,
self.nmos3_inst,
self.inputC_yoffset,
"C",
position="right")
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """
+3
View File
@@ -211,6 +211,9 @@ class pnor2(pgate.pgate):
self.output_yoffset = self.inputA_yoffset + self.m1_nonpref_pitch
if OPTS.tech_name == "sky130":
self.enclose_npc()
def route_output(self):
""" Route the Z output """
# PMOS2 (right) drain
+1 -1
View File
@@ -196,7 +196,7 @@ class precharge(design.design):
pin_offset = self.lower_pmos_inst.get_pin("G").lr()
# This is an extra space down for some techs with contact to active spacing
contact_space = max(self.poly_space,
self.contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height
self.poly_contact_to_gate) + 0.5 * contact.poly_contact.first_layer_height
offset = pin_offset - vector(0, contact_space)
self.add_via_stack_center(from_layer="poly",
to_layer=self.en_layer,
+16 -18
View File
@@ -131,8 +131,8 @@ 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 == "sky130":
# sky130 technology is in microns, also needs mult parameter
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
# sky130 simulation cannot use the mult parameter in simulation
(self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width)
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults,
@@ -152,19 +152,17 @@ class ptx(design.design):
self.spice_device = main_str + area_str
self.spice.append("\n* ptx " + self.spice_device)
# LVS lib is always in SI units
if os.path.exists(OPTS.openram_tech + "lvs_lib"):
if OPTS.tech_name == "sky130":
# sky130 requires mult parameter too
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
# sky130 requires mult parameter too
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc("minwidth_poly"))
def setup_layout_constants(self):
"""
@@ -198,7 +196,7 @@ class ptx(design.design):
# This is the spacing between the poly gates
self.min_poly_pitch = self.poly_space + self.poly_width
self.contacted_poly_pitch = self.poly_space + contact.poly_contact.width
self.contact_pitch = 2 * self.contact_to_gate + self.poly_width + self.contact_width
self.contact_pitch = 2 * self.active_contact_to_gate + self.poly_width + self.contact_width
self.poly_pitch = max(self.min_poly_pitch,
self.contacted_poly_pitch,
self.contact_pitch)
@@ -208,7 +206,7 @@ class ptx(design.design):
# Active width is determined by enclosure on both ends and contacted pitch,
# at least one poly and n-1 poly pitches
self.active_width = 2 * self.end_to_contact + self.active_contact.width \
+ 2 * self.contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
+ 2 * self.active_contact_to_gate + self.poly_width + (self.mults - 1) * self.poly_pitch
# Active height is just the transistor width
self.active_height = self.tx_width
@@ -323,7 +321,7 @@ class ptx(design.design):
"""
# poly is one contacted spacing from the end and down an extension
poly_offset = self.contact_offset \
+ vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.contact_to_gate, 0)
+ vector(0.5 * self.active_contact.width + 0.5 * self.poly_width + self.active_contact_to_gate, 0)
# poly_positions are the bottom center of the poly gates
self.poly_positions = []