Fix 6T and replica cell contact spacing issues with Magic DRC.

DRC/LVS passing for all parameterized gates.
Magic and GDS match for SCMOS rules again.
This commit is contained in:
Matt Guthaus 2018-01-26 12:39:00 -08:00
parent fb0355ebaf
commit 1dc7752429
17 changed files with 315 additions and 299 deletions

View File

@ -115,8 +115,8 @@ class bitcell_array(design.design):
gnd_pins = self.cell_inst[0,col].get_pins("gnd") gnd_pins = self.cell_inst[0,col].get_pins("gnd")
for gnd_pin in gnd_pins: for gnd_pin in gnd_pins:
# avoid duplicates by only doing even rows # avoid duplicates by only doing even rows
# also skip if it is not the full height (a through rail) # also skip if it isn't the pin that spans the entire cell down to the bottom
if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.height()>=self.cell.height: if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.by()==lower_y:
self.add_layout_pin(text="gnd", self.add_layout_pin(text="gnd",
layer="metal2", layer="metal2",
offset=gnd_pin.ll(), offset=gnd_pin.ll(),

View File

@ -27,8 +27,13 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
# Check if the name already exists, if so, give an error # Check if the name already exists, if so, give an error
# because each reference must be a unique name. # because each reference must be a unique name.
ok_list = ['ms_flop.ms_flop', 'bitcell.bitcell', 'contact.contact', # These modules ensure unique names or have no changes if they
'ptx.ptx', 'sram.sram', # aren't unique
ok_list = ['ms_flop.ms_flop',
'bitcell.bitcell',
'contact.contact',
'ptx.ptx',
'sram.sram',
'hierarchical_predecode2x4.hierarchical_predecode2x4', 'hierarchical_predecode2x4.hierarchical_predecode2x4',
'hierarchical_predecode3x8.hierarchical_predecode3x8'] 'hierarchical_predecode3x8.hierarchical_predecode3x8']
if name not in design.name_map: if name not in design.name_map:
@ -41,6 +46,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
def setup_drc_constants(self): def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler.""" """ These are some DRC constants used in many places in the compiler."""
from tech import drc from tech import drc
self.well_width = drc["minwidth_well"]
self.poly_width = drc["minwidth_poly"] self.poly_width = drc["minwidth_poly"]
self.poly_space = drc["poly_to_poly"] self.poly_space = drc["poly_to_poly"]
self.m1_width = drc["minwidth_metal1"] self.m1_width = drc["minwidth_metal1"]
@ -49,6 +55,15 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
self.m2_space = drc["metal2_to_metal2"] self.m2_space = drc["metal2_to_metal2"]
self.m3_width = drc["minwidth_metal3"] self.m3_width = drc["minwidth_metal3"]
self.m3_space = drc["metal3_to_metal3"] self.m3_space = drc["metal3_to_metal3"]
self.active_width = drc["minwidth_active"]
self.contact_width = drc["minwidth_contact"]
self.poly_to_active = drc["poly_to_active"]
self.poly_extend_active = drc["poly_extend_active"]
self.contact_to_gate = drc["contact_to_gate"]
self.well_enclose_active = drc["well_enclosure_active"]
self.implant_enclose_active = drc["implant_enclosure_active"]
self.implant_space = drc["implant_to_implant"]
def get_layout_pins(self,inst): def get_layout_pins(self,inst):
""" Return a map of pin locations of the instance offset """ """ Return a map of pin locations of the instance offset """

View File

@ -336,14 +336,14 @@ class layout(lef.lef):
implant_type=implant_type, implant_type=implant_type,
well_type=well_type) well_type=well_type)
self.add_mod(via) self.add_mod(via)
self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=offset, offset=offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) self.connect_inst([])
return via return inst
def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None): def add_via_center(self, layers, offset, size=[1,1], mirror="R0", rotate=0, implant_type=None, well_type=None):
""" Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """
@ -371,14 +371,14 @@ class layout(lef.lef):
self.add_mod(via) self.add_mod(via)
self.add_inst(name=via.name, inst=self.add_inst(name=via.name,
mod=via, mod=via,
offset=corrected_offset, offset=corrected_offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
# We don't model the logical connectivity of wires/paths # We don't model the logical connectivity of wires/paths
self.connect_inst([]) self.connect_inst([])
return via return inst
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"): def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
"""Adds a ptx module to the design.""" """Adds a ptx module to the design."""
@ -387,12 +387,12 @@ class layout(lef.lef):
mults=mults, mults=mults,
tx_type=tx_type) tx_type=tx_type)
self.add_mod(mos) self.add_mod(mos)
self.add_inst(name=mos.name, inst=self.add_inst(name=mos.name,
mod=mos, mod=mos,
offset=offset, offset=offset,
mirror=mirror, mirror=mirror,
rotate=rotate) rotate=rotate)
return mos return inst

View File

@ -47,7 +47,7 @@ class pgate(design.design):
debug.check(nmos_gate_pin.ll().x==pmos_gate_pin.ll().x, "Connecting unaligned gates not supported.") debug.check(nmos_gate_pin.ll().x==pmos_gate_pin.ll().x, "Connecting unaligned gates not supported.")
# Pick point on the left of NMOS and connect down to PMOS # Pick point on the left of NMOS and connect down to PMOS
nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*drc["minwidth_poly"],0) nmos_gate_pos = nmos_gate_pin.ll() + vector(0.5*self.poly_width,0)
pmos_gate_pos = vector(nmos_gate_pos.x,pmos_gate_pin.bc().y) pmos_gate_pos = vector(nmos_gate_pos.x,pmos_gate_pin.bc().y)
self.add_path("poly",[nmos_gate_pos,pmos_gate_pos]) self.add_path("poly",[nmos_gate_pos,pmos_gate_pos])
@ -98,9 +98,9 @@ class pgate(design.design):
""" Extend the n/p wells to cover whole cell """ """ Extend the n/p wells to cover whole cell """
# Add a rail width to extend the well to the top of the rail # Add a rail width to extend the well to the top of the rail
self.max_y_offset = self.height + 0.5*drc["minwidth_metal1"] max_y_offset = self.height + 0.5*self.m1_width
self.nwell_position = middle_position self.nwell_position = middle_position
nwell_height = self.max_y_offset - middle_position.y nwell_height = max_y_offset - middle_position.y
if info["has_nwell"]: if info["has_nwell"]:
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
offset=middle_position, offset=middle_position,
@ -111,15 +111,15 @@ class pgate(design.design):
width=self.well_width, width=self.well_width,
height=nwell_height) height=nwell_height)
self.pwell_position = vector(0,-0.5*drc["minwidth_metal1"]) pwell_position = vector(0,-0.5*self.m1_width)
pwell_height = middle_position.y-self.pwell_position.y pwell_height = middle_position.y-pwell_position.y
if info["has_pwell"]: if info["has_pwell"]:
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=self.pwell_position, offset=pwell_position,
width=self.well_width, width=self.well_width,
height=pwell_height) height=pwell_height)
self.add_rect(layer="vtg", self.add_rect(layer="vtg",
offset=self.pwell_position, offset=pwell_position,
width=self.well_width, width=self.well_width,
height=pwell_height) height=pwell_height)
@ -132,8 +132,9 @@ class pgate(design.design):
contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"] contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
# Must be at least an well enclosure of active down from the top of the well # Must be at least an well enclosure of active down from the top of the well
# OR align the active with the top of PMOS active. # OR align the active with the top of PMOS active.
max_y_offset = self.height + 0.5*self.m1_width
contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height, contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height,
self.max_y_offset - pmos.active_contact.first_layer_height/2 - drc["well_enclosure_active"]) max_y_offset - pmos.active_contact.first_layer_height/2 - self.well_enclose_active)
contact_offset = vector(contact_xoffset, contact_yoffset) contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact in x and y # Offset by half a contact in x and y
contact_offset += vector(0.5*pmos.active_contact.first_layer_width, contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
@ -144,11 +145,11 @@ class pgate(design.design):
well_type="n") well_type="n")
self.add_rect_center(layer="metal1", self.add_rect_center(layer="metal1",
offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)), offset=contact_offset + vector(0,0.5*(self.height-contact_offset.y)),
width=self.nwell_contact.second_layer_width, width=self.nwell_contact.mod.second_layer_width,
height=self.height - contact_offset.y) height=self.height - contact_offset.y)
# Now add the full active and implant for the PMOS # Now add the full active and implant for the PMOS
active_offset = pmos_pos + vector(pmos.active_width,0) #active_offset = pmos_pos + vector(pmos.active_width,0)
# This might be needed if the spacing between the actives is not satisifed # This might be needed if the spacing between the actives is not satisifed
# self.add_rect(layer="active", # self.add_rect(layer="active",
# offset=active_offset, # offset=active_offset,
@ -156,27 +157,29 @@ class pgate(design.design):
# height=pmos.active_height) # height=pmos.active_height)
# we need to ensure implants don't overlap and are spaced far enough apart # we need to ensure implants don't overlap and are spaced far enough apart
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"] # implant_spacing = self.implant_space+self.implant_enclose_active
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"]) # implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
implant_width = pmos.active_contact.width + 2*drc["implant_enclosure_active"] # implant_width = pmos.active_contact.width + 2*self.implant_enclose_active
implant_height = pmos.active_height + 2*drc["implant_enclosure_active"] # implant_height = pmos.active_height + 2*self.implant_enclose_active
# self.add_rect(layer="nimplant", # self.add_rect(layer="nimplant",
# offset=implant_offset, # offset=implant_offset,
# width=implant_width, # width=implant_width,
# height=implant_height) # height=implant_height)
# Return the top of the well
def add_pwell_contact(self, nmos, nmos_pos): def add_pwell_contact(self, nmos, nmos_pos):
""" Add an pwell contact next to the given nmos device. """ """ Add an pwell contact next to the given nmos device. """
layer_stack = ("active", "contact", "metal1") layer_stack = ("active", "contact", "metal1")
pwell_position = vector(0,-0.5*self.m1_width)
# To the right a spacing away from the nmos right active edge # To the right a spacing away from the nmos right active edge
contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"] contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
# Must be at least an well enclosure of active up from the bottom of the well # Must be at least an well enclosure of active up from the bottom of the well
contact_yoffset = max(nmos_pos.y, contact_yoffset = max(nmos_pos.y,
drc["well_enclosure_active"] - nmos.active_contact.first_layer_height/2 - self.pwell_position.y) self.well_enclose_active - nmos.active_contact.first_layer_height/2)
contact_offset = vector(contact_xoffset, contact_yoffset) contact_offset = vector(contact_xoffset, contact_yoffset)
# Offset by half a contact # Offset by half a contact
@ -188,21 +191,21 @@ class pgate(design.design):
well_type="p") well_type="p")
self.add_rect_center(layer="metal1", self.add_rect_center(layer="metal1",
offset=contact_offset.scale(1,0.5), offset=contact_offset.scale(1,0.5),
width=self.pwell_contact.second_layer_width, width=self.pwell_contact.mod.second_layer_width,
height=contact_offset.y) height=contact_offset.y)
# Now add the full active and implant for the NMOS # Now add the full active and implant for the NMOS
active_offset = nmos_pos + vector(nmos.active_width,0) # active_offset = nmos_pos + vector(nmos.active_width,0)
# This might be needed if the spacing between the actives is not satisifed # This might be needed if the spacing between the actives is not satisifed
# self.add_rect(layer="active", # self.add_rect(layer="active",
# offset=active_offset, # offset=active_offset,
# width=nmos.active_contact.width, # width=nmos.active_contact.width,
# height=nmos.active_height) # height=nmos.active_height)
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"] # implant_spacing = self.implant_space+self.implant_enclose_active
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"]) # implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
implant_width = nmos.active_contact.width + 2*drc["implant_enclosure_active"] # implant_width = nmos.active_contact.width + 2*self.implant_enclose_active
implant_height = nmos.active_height + 2*drc["implant_enclosure_active"] # implant_height = nmos.active_height + 2*self.implant_enclose_active
# self.add_rect(layer="pimplant", # self.add_rect(layer="pimplant",
# offset=implant_offset, # offset=implant_offset,
# width=implant_width, # width=implant_width,

View File

@ -57,8 +57,8 @@ class pinv(pgate.pgate):
self.setup_layout_constants() self.setup_layout_constants()
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.extend_wells(self.well_pos)
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos)
self.connect_rails() self.connect_rails()
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0) self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
self.route_outputs() self.route_outputs()
@ -128,9 +128,6 @@ class pinv(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
def create_ptx(self): def create_ptx(self):
@ -183,8 +180,13 @@ class pinv(pgate.pgate):
self.connect_inst(["Z", "A", "gnd", "gnd"]) self.connect_inst(["Z", "A", "gnd", "gnd"])
# Output position will be in between the PMOS and NMOS # Output position will be in between the PMOS and NMOS drains
self.output_pos = vector(0,0.5*(self.pmos_pos.y+self.nmos_pos.y+self.nmos.active_height)) pmos_drain_pos = self.pmos_inst.get_pin("D").ll()
nmos_drain_pos = self.nmos_inst.get_pin("D").ul()
self.output_pos = vector(0,0.5*(pmos_drain_pos.y+nmos_drain_pos.y))
# This will help with the wells
self.well_pos = vector(0,self.nmos_inst.uy())
@ -196,8 +198,8 @@ class pinv(pgate.pgate):
pmos_drain_pin = self.pmos_inst.get_pin("D") pmos_drain_pin = self.pmos_inst.get_pin("D")
# Pick point at right most of NMOS and connect down to PMOS # Pick point at right most of NMOS and connect down to PMOS
nmos_drain_pos = nmos_drain_pin.ur() - vector(0.5*self.m1_width,0) nmos_drain_pos = nmos_drain_pin.lr() - vector(0.5*self.m1_width,0)
pmos_drain_pos = vector(nmos_drain_pos.x,pmos_drain_pin.bc().y) pmos_drain_pos = vector(nmos_drain_pos.x, pmos_drain_pin.bc().y)
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos]) self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
# Remember the mid for the output # Remember the mid for the output

View File

@ -51,8 +51,8 @@ class pnand2(pgate.pgate):
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.connect_rails() self.connect_rails()
self.extend_wells(self.well_pos)
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -94,9 +94,6 @@ class pnand2(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts # This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-self.nmos.get_pin("D").by(),0) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # This is a poly-to-poly of a flipped cell
@ -150,6 +147,9 @@ class pnand2(pgate.pgate):
# Output position will be in between the PMOS and NMOS # Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height)) self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
# This will help with the wells
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self): def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """ """ Add n/p well taps to the layout and connect to supplies AFTER the wells are created """

View File

@ -51,8 +51,8 @@ class pnand3(pgate.pgate):
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.connect_rails() self.connect_rails()
self.extend_wells(self.well_pos)
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -88,7 +88,6 @@ class pnand3(pgate.pgate):
# This will help with the wells and the input/output placement # This will help with the wells and the input/output placement
self.output_pos = vector(0,0.5*self.height) self.output_pos = vector(0,0.5*self.height)
self.well_pos = vector(0,0.4*self.height)
# This is a poly-to-poly of a flipped cell # This is a poly-to-poly of a flipped cell
# This is extra liberal for pnand3 because we know there are big transistor sizes # This is extra liberal for pnand3 because we know there are big transistor sizes
@ -153,6 +152,8 @@ class pnand3(pgate.pgate):
offset=self.nmos3_pos) offset=self.nmos3_pos)
self.connect_inst(["net2", "C", "gnd", "gnd"]) self.connect_inst(["net2", "C", "gnd", "gnd"])
# This should be placed at the top of the NMOS well
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self): def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """ """ Add n/p well taps to the layout and connect to supplies """

View File

@ -52,8 +52,8 @@ class pnor2(pgate.pgate):
self.add_supply_rails() self.add_supply_rails()
self.add_ptx() self.add_ptx()
self.connect_rails() self.connect_rails()
self.extend_wells(self.well_pos)
self.add_well_contacts() self.add_well_contacts()
self.extend_wells(self.well_pos)
self.route_inputs() self.route_inputs()
self.route_output() self.route_output()
@ -98,9 +98,6 @@ class pnor2(pgate.pgate):
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # Height is an input parameter, so it is not recomputed.
# This will help with the wells
self.well_pos = vector(0,0.4*self.height)
# This is the extra space needed to ensure DRC rules to the active contacts # This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-self.nmos.get_pin("D").by(),0) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # This is a poly-to-poly of a flipped cell
@ -154,6 +151,9 @@ class pnor2(pgate.pgate):
# Output position will be in between the PMOS and NMOS # Output position will be in between the PMOS and NMOS
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height)) self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
# This will help with the wells
self.well_pos = vector(0,self.nmos1_inst.uy())
def add_well_contacts(self): def add_well_contacts(self):
""" Add n/p well taps to the layout and connect to supplies """ """ Add n/p well taps to the layout and connect to supplies """

View File

@ -94,25 +94,19 @@ class ptx(design.design):
self.active_contact = contact(layer_stack=("active", "contact", "metal1"), self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
dimensions=(1, self.num_contacts)) dimensions=(1, self.num_contacts))
# Standard DRC rules
self.min_active_width = drc["minwidth_active"]
self.contact_width = drc["minwidth_contact"]
self.poly_width = drc["minwidth_poly"]
self.poly_to_active = drc["poly_to_active"]
self.poly_extend_active = drc["poly_extend_active"]
# The contacted poly pitch (or uncontacted in an odd technology) # The contacted poly pitch (or uncontacted in an odd technology)
self.poly_pitch = max(2*drc["contact_to_gate"] + self.contact_width + self.poly_width, self.poly_pitch = max(2*self.contact_to_gate + self.contact_width + self.poly_width,
drc["poly_to_poly"]) self.poly_space)
# The contacted poly pitch (or uncontacted in an odd technology) # The contacted poly pitch (or uncontacted in an odd technology)
self.contact_pitch = 2*drc["contact_to_gate"] + self.contact_width + self.poly_width self.contact_pitch = 2*self.contact_to_gate + self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term. # The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc["active_enclosure_contact"], active_enclose_contact = max(drc["active_enclosure_contact"],
(self.min_active_width - self.contact_width)/2) (self.active_width - self.contact_width)/2)
# This is the distance from the edge of poly to the contacted end of active # This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + drc["contact_to_gate"] self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
# Active width is determined by enclosure on both ends and contacted pitch, # Active width is determined by enclosure on both ends and contacted pitch,
@ -125,22 +119,25 @@ class ptx(design.design):
# Poly height must include poly extension over active # Poly height must include poly extension over active
self.poly_height = self.tx_width + 2*self.poly_extend_active self.poly_height = self.tx_width + 2*self.poly_extend_active
# The active offset is due to the well extension
self.active_offset = vector([self.well_enclose_active]*2)
# Well enclosure of active, ensure minwidth as well # Well enclosure of active, ensure minwidth as well
if info["has_{}well".format(self.well_type)]: if info["has_{}well".format(self.well_type)]:
self.well_width = max(self.active_width + 2*drc["well_enclosure_active"], self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
drc["minwidth_well"]) self.well_width)
self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"], self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
drc["minwidth_well"]) self.well_width)
# We are going to shift the 0,0, so include that in the width and height
self.height = self.well_height self.height = self.cell_well_height - self.active_offset.y
self.width = self.well_width self.width = self.cell_well_width - self.active_offset.x
else: else:
# If no well, use the boundary of the active and poly # If no well, use the boundary of the active and poly
self.height = self.poly_height self.height = self.poly_height
self.width = self.active_width self.width = self.active_width
# The active offset is due to the well extension # The active offset is due to the well extension
self.active_offset = vector([drc["well_enclosure_active"]]*2) self.active_offset = vector([self.well_enclose_active]*2)
# This is the center of the first active contact offset (centered vertically) # This is the center of the first active contact offset (centered vertically)
self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5*self.contact_width, self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5*self.contact_width,
@ -189,9 +186,9 @@ class ptx(design.design):
# This is the distance that we must route up or down from the center # This is the distance that we must route up or down from the center
# of the contacts to avoid DRC violations to the other contacts # of the contacts to avoid DRC violations to the other contacts
pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \ pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \
+ drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"]) + self.m1_space + 0.5*self.m1_width)
# This is the width of a contact to extend the ends of the pin # This is the width of a m1 extend the ends of the pin
end_offset = vector(self.active_contact.second_layer_width/2,0) end_offset = vector(self.m1_width/2,0)
# drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS # drains always go to the MIDDLE of the cell, so top of NMOS, bottom of PMOS
# so reverse the directions for NMOS compared to PMOS. # so reverse the directions for NMOS compared to PMOS.
@ -280,12 +277,12 @@ class ptx(design.design):
if info["has_{}well".format(self.well_type)]: if info["has_{}well".format(self.well_type)]:
self.add_rect(layer="{}well".format(self.well_type), self.add_rect(layer="{}well".format(self.well_type),
offset=(0,0), offset=(0,0),
width=self.well_width, width=self.cell_well_width,
height=self.well_height) height=self.cell_well_height)
self.add_rect(layer="vtg", self.add_rect(layer="vtg",
offset=(0,0), offset=(0,0),
width=self.well_width, width=self.cell_well_width,
height=self.well_height) height=self.cell_well_height)
def calculate_num_contacts(self): def calculate_num_contacts(self):
@ -331,8 +328,8 @@ class ptx(design.design):
self.add_layout_pin_center_rect(text="S", self.add_layout_pin_center_rect(text="S",
layer="metal1", layer="metal1",
offset=pos, offset=pos,
width=contact.second_layer_width, width=contact.mod.second_layer_width,
height=contact.second_layer_height) height=contact.mod.second_layer_height)
for pos in drain_positions: for pos in drain_positions:
@ -344,8 +341,8 @@ class ptx(design.design):
self.add_layout_pin_center_rect(text="D", self.add_layout_pin_center_rect(text="D",
layer="metal1", layer="metal1",
offset=pos, offset=pos,
width=contact.second_layer_width, width=contact.mod.second_layer_width,
height=contact.second_layer_height) height=contact.mod.second_layer_height)
if self.connect_active: if self.connect_active:
self.connect_fingered_active(drain_positions, source_positions) self.connect_fingered_active(drain_positions, source_positions)

View File

@ -12,12 +12,13 @@ ln -s 2001a current
#!/bin/sh #!/bin/sh
magic -dnull -noconsole << EOF magic -dnull -noconsole << EOF
tech load SCN3ME_SUBM.30 tech load SCN3ME_SUBM.30
gds rescale false scalegrid 1 2
gds rescale no
gds polygon subcell true gds polygon subcell true
gds warning default gds warning default
gds read $1 gds read $1
load $1 load $1
save $1 writeall force
drc count drc count
drc why drc why
quit -noprompt quit -noprompt
@ -29,7 +30,8 @@ rm -f $1.ext
rm -f $1.spice rm -f $1.spice
magic -dnull -noconsole << EOF magic -dnull -noconsole << EOF
tech load SCN3ME_SUBM.30 tech load SCN3ME_SUBM.30
gds rescale false scalegrid 1 2
gds rescale no
gds polygon subcell true gds polygon subcell true
gds warning default gds warning default
gds read $1 gds read $1
@ -72,12 +74,13 @@ def write_magic_script(cell_name, gds_name, extract=False):
f.write("#!/bin/sh\n") f.write("#!/bin/sh\n")
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1])) f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
f.write("tech load SCN3ME_SUBM.30\n") f.write("tech load SCN3ME_SUBM.30\n")
f.write("gds rescale false\n") f.write("scalegrid 1 2\n")
f.write("gds rescale no\n")
f.write("gds polygon subcell true\n") f.write("gds polygon subcell true\n")
f.write("gds warning default\n") f.write("gds warning default\n")
f.write("gds read {}\n".format(gds_name)) f.write("gds read {}\n".format(gds_name))
f.write("load {}\n".format(cell_name)) f.write("load {}\n".format(cell_name))
f.write("save {}\n".format(cell_name)) f.write("writeall force\n")
f.write("drc check\n") f.write("drc check\n")
f.write("drc catchup\n") f.write("drc catchup\n")
f.write("drc count total\n") f.write("drc count total\n")
@ -123,6 +126,12 @@ def write_netgen_script(cell_name, sp_name):
cell_name)) cell_name))
f.write("property {{{0}{1}.spice pfet}} remove as ad ps pd\n".format(OPTS.openram_temp, f.write("property {{{0}{1}.spice pfet}} remove as ad ps pd\n".format(OPTS.openram_temp,
cell_name)) cell_name))
# Allow some flexibility in W size because magic will snap to a lambda grid
# This can also cause disconnects unfortunately!
# f.write("property {{{0}{1}.spice nfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
# cell_name))
# f.write("property {{{0}{1}.spice pfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
# cell_name))
f.write("permute default\n") f.write("permute default\n")
f.write("log start\n") f.write("log start\n")
f.write("compare hierarchical {0}{1}.spice {{{2} {1}}}\n".format(OPTS.openram_temp, f.write("compare hierarchical {0}{1}.spice {{{2} {1}}}\n".format(OPTS.openram_temp,

View File

@ -149,7 +149,7 @@ class wordline_driver(design.design):
self.add_segment_center(layer="metal1", self.add_segment_center(layer="metal1",
start=clk_offset, start=clk_offset,
end=a_pos) end=a_pos)
m1m2_via = self.add_via_center(layers=("metal1", "via1", "metal2"), self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=clk_offset) offset=clk_offset)
# first inv to nand2 A # first inv to nand2 A

Binary file not shown.

View File

@ -1,119 +1,114 @@
magic magic
tech scmos tech scmos
timestamp 1516665972 timestamp 1516839303
<< nwell >> << nwell >>
rect -5 31 42 52 rect -8 29 42 50
<< pwell >> << pwell >>
rect -5 -6 42 31 rect -8 -8 42 29
<< ntransistor >> << ntransistor >>
rect 7 12 9 20 rect 7 10 9 18
rect 29 12 31 20 rect 29 10 31 18
rect 10 5 14 7 rect 10 3 14 5
rect 24 5 28 7 rect 24 3 28 5
<< ptransistor >> << ptransistor >>
rect 7 39 11 42 rect 7 37 11 40
rect 27 39 31 42 rect 27 37 31 40
<< ndiffusion >> << ndiffusion >>
rect 2 20 6 23 rect -2 16 7 18
rect 32 20 36 23
rect 6 16 7 20
rect 2 12 7 16 rect 2 12 7 16
rect 9 16 10 20 rect -2 10 7 12
rect 9 12 14 16 rect 9 14 10 18
rect 28 16 29 20 rect 9 10 14 14
rect 24 12 29 16 rect 28 14 29 18
rect 31 16 32 20 rect 24 10 29 14
rect 31 12 36 16 rect 31 16 36 18
rect 10 7 14 12 rect 31 12 32 16
rect 24 7 28 12 rect 31 10 36 12
rect 10 4 14 5 rect 10 5 14 10
rect 24 4 28 5 rect 24 5 28 10
rect 10 2 14 3
rect 24 2 28 3
<< pdiffusion >> << pdiffusion >>
rect 2 42 6 45 rect 32 40 36 43
rect 32 42 36 45 rect 2 37 7 40
rect 6 39 7 42 rect 11 37 12 40
rect 11 39 12 42 rect 26 37 27 40
rect 26 39 27 42 rect 31 37 32 40
rect 31 39 32 42
<< ndcontact >> << ndcontact >>
rect 2 16 6 20 rect -2 12 2 16
rect 10 16 14 20 rect 10 14 14 18
rect 24 16 28 20 rect 24 14 28 18
rect 32 16 36 20 rect 32 12 36 16
rect 10 0 14 4 rect 10 -2 14 2
rect 24 0 28 4 rect 24 -2 28 2
<< pdcontact >> << pdcontact >>
rect 2 38 6 42 rect -2 36 2 40
rect 12 38 16 42 rect 12 36 16 40
rect 22 38 26 42 rect 22 36 26 40
rect 32 38 36 42 rect 32 36 36 40
<< psubstratepcontact >> << psubstratepcontact >>
rect 2 23 6 27 rect 32 22 36 26
rect 32 23 36 27
<< nsubstratencontact >> << nsubstratencontact >>
rect 0 45 6 49 rect 32 43 36 47
rect 32 45 36 49
<< polysilicon >> << polysilicon >>
rect 7 42 11 44 rect 7 40 11 42
rect 27 42 31 44 rect 27 40 31 42
rect 7 37 11 39 rect 7 35 11 37
rect 7 23 9 37 rect 7 21 9 35
rect 27 36 31 39 rect 27 34 31 37
rect 15 35 31 36 rect 15 33 31 34
rect 19 34 31 35 rect 19 32 31 33
rect 7 22 21 23 rect 7 20 21 21
rect 7 21 24 22 rect 7 19 24 20
rect 7 20 9 21 rect 7 18 9 19
rect 29 20 31 34 rect 29 18 31 32
rect 7 10 9 12 rect 7 8 9 10
rect 17 7 21 8 rect 17 5 21 6
rect 29 10 31 12 rect 29 8 31 10
rect 0 5 10 7 rect -2 3 10 5
rect 14 5 24 7 rect 14 3 24 5
rect 28 5 36 7 rect 28 3 36 5
<< polycontact >> << polycontact >>
rect 15 31 19 35 rect 15 29 19 33
rect 21 22 25 26 rect 21 20 25 24
rect 17 8 21 12 rect 17 6 21 10
<< metal1 >> << metal1 >>
rect 6 45 32 49 rect -2 43 32 47
rect 2 42 6 45 rect -2 40 2 43
rect 32 42 36 45 rect 32 40 36 43
rect 2 27 6 31 rect -2 16 2 29
rect 2 20 6 23 rect 11 18 15 36
rect 11 20 15 38 rect 23 24 27 36
rect 23 26 27 38 rect 25 20 27 24
rect 25 22 27 26 rect 23 18 27 20
rect 23 20 27 22 rect 32 26 36 29
rect 32 27 36 31 rect 32 16 36 22
rect 32 20 36 23 rect -2 6 17 9
rect 0 8 17 11 rect 21 6 36 9
rect 21 8 36 11 rect -2 5 36 6
rect 0 7 36 8 rect 9 -2 10 2
rect 9 0 10 4 rect 23 -2 24 2
rect 23 0 24 4
<< m2contact >> << m2contact >>
rect 2 31 6 35 rect -2 29 2 33
rect 32 31 36 35 rect 32 29 36 33
rect 5 0 9 4 rect 5 -2 9 2
rect 19 0 23 4 rect 19 -2 23 2
<< metal2 >> << metal2 >>
rect 0 35 6 49 rect -2 33 2 47
rect 0 31 2 35 rect -2 12 2 29
rect 0 14 6 31 rect 10 2 14 47
rect 10 4 14 49 rect 20 2 24 47
rect 20 4 24 49 rect 9 -2 14 2
rect 9 0 14 4 rect 23 -2 24 2
rect 23 0 24 4 rect 32 33 36 47
rect 32 35 36 49 rect 32 -2 36 29
rect 32 0 36 31
<< m3p >> << m3p >>
rect 0 0 34 49 rect 0 0 34 45
<< labels >> << labels >>
rlabel m2contact 20 4 20 4 1 BR rlabel m2contact 20 2 20 2 1 BR
rlabel metal2 10 4 10 4 1 BL rlabel metal2 10 2 10 2 1 BL
rlabel metal2 32 31 32 31 7 gnd rlabel metal1 2 6 2 6 3 WL
rlabel metal1 32 45 32 45 4 vdd rlabel metal2 -1 28 -1 28 1 gnd
rlabel metal2 2 31 2 31 3 gnd rlabel metal2 33 28 33 28 1 gnd
rlabel metal1 2 8 2 8 3 WL rlabel metal1 17 45 17 45 5 vdd
<< end >> << end >>

View File

@ -1,122 +1,116 @@
magic magic
tech scmos tech scmos
timestamp 1516666672 timestamp 1516980606
<< nwell >> << nwell >>
rect -4 31 42 53 rect -8 29 42 50
<< pwell >> << pwell >>
rect -4 -6 42 31 rect -8 -8 42 29
<< ntransistor >> << ntransistor >>
rect 7 12 9 20 rect 7 10 9 18
rect 29 12 31 20 rect 29 10 31 18
rect 10 5 14 7 rect 10 3 14 5
rect 24 5 28 7 rect 24 3 28 5
<< ptransistor >> << ptransistor >>
rect 7 39 11 42 rect 7 37 11 40
rect 27 39 31 42 rect 27 37 31 40
<< ndiffusion >> << ndiffusion >>
rect 2 20 6 23 rect -2 16 7 18
rect 32 20 36 23
rect 6 16 7 20
rect 2 12 7 16 rect 2 12 7 16
rect 9 16 10 20 rect -2 10 7 12
rect 9 12 14 16 rect 9 14 10 18
rect 28 16 29 20 rect 9 10 14 14
rect 24 12 29 16 rect 28 14 29 18
rect 31 16 32 20 rect 24 10 29 14
rect 31 12 36 16 rect 31 16 36 18
rect 10 7 14 12 rect 31 12 32 16
rect 24 7 28 12 rect 31 10 36 12
rect 10 4 14 5 rect 10 5 14 10
rect 24 4 28 5 rect 24 5 28 10
rect 10 2 14 3
rect 24 2 28 3
<< pdiffusion >> << pdiffusion >>
rect 2 42 6 45 rect 32 40 36 43
rect 32 42 36 45 rect 2 37 7 40
rect 6 39 7 42 rect 11 37 12 40
rect 11 39 12 42 rect 26 37 27 40
rect 26 39 27 42 rect 31 37 32 40
rect 31 39 32 42
<< ndcontact >> << ndcontact >>
rect 2 16 6 20 rect -2 12 2 16
rect 10 16 14 20 rect 10 14 14 18
rect 24 16 28 20 rect 24 14 28 18
rect 32 16 36 20 rect 32 12 36 16
rect 10 0 14 4 rect 10 -2 14 2
rect 24 0 28 4 rect 24 -2 28 2
<< pdcontact >> << pdcontact >>
rect 2 38 6 42 rect -2 36 2 40
rect 12 38 16 42 rect 12 36 16 40
rect 22 38 26 42 rect 22 36 26 40
rect 32 38 36 42 rect 32 36 36 40
<< psubstratepcontact >> << psubstratepcontact >>
rect 2 23 6 27 rect 32 22 36 26
rect 32 23 36 27
<< nsubstratencontact >> << nsubstratencontact >>
rect 0 45 6 49 rect 32 43 36 47
rect 32 45 36 49
<< polysilicon >> << polysilicon >>
rect 7 42 11 44 rect 7 40 11 42
rect 27 42 31 44 rect 27 40 31 42
rect 7 37 11 39 rect 7 35 11 37
rect 7 23 9 37 rect 7 21 9 35
rect 27 36 31 39 rect 27 34 31 37
rect 15 35 31 36 rect 15 33 31 34
rect 19 34 31 35 rect 19 32 31 33
rect 7 22 21 23 rect 7 20 21 21
rect 7 21 24 22 rect 7 19 24 20
rect 7 20 9 21 rect 7 18 9 19
rect 29 20 31 34 rect 29 18 31 32
rect 7 10 9 12 rect 7 8 9 10
rect 17 7 21 8 rect 17 5 21 6
rect 29 10 31 12 rect 29 8 31 10
rect 0 5 10 7 rect -2 3 10 5
rect 14 5 24 7 rect 14 3 24 5
rect 28 5 36 7 rect 28 3 36 5
<< polycontact >> << polycontact >>
rect 15 31 19 35 rect 15 29 19 33
rect 21 22 25 26 rect 21 20 25 24
rect 17 8 21 12 rect 17 6 21 10
<< metal1 >> << metal1 >>
rect 6 45 32 49 rect -2 43 32 47
rect 2 42 6 45 rect -2 40 2 43
rect 32 42 36 45 rect 32 40 36 43
rect 11 35 15 38 rect -2 18 2 29
rect 6 31 15 35 rect 11 18 15 36
rect 2 27 6 31 rect 23 24 27 36
rect 2 20 6 23 rect 25 20 27 24
rect 11 20 15 31 rect 23 18 27 20
rect 23 26 27 38 rect 32 26 36 29
rect 25 22 27 26 rect -2 16 10 18
rect 23 20 27 22 rect 2 14 10 16
rect 32 27 36 31 rect 32 16 36 22
rect 32 20 36 23 rect -2 6 17 9
rect 2 14 6 16 rect 21 6 36 9
rect 0 8 17 11 rect -2 5 36 6
rect 21 8 36 11 rect 9 -2 10 2
rect 0 7 36 8 rect 23 -2 24 2
rect 9 0 10 4
rect 23 0 24 4
<< m2contact >> << m2contact >>
rect 2 31 6 35 rect -2 29 2 33
rect 32 31 36 35 rect 32 29 36 33
rect 5 0 9 4 rect 5 -2 9 2
rect 19 0 23 4 rect 19 -2 23 2
<< metal2 >> << metal2 >>
rect 0 35 6 49 rect -2 33 2 47
rect 0 31 2 35 rect -2 12 2 29
rect 0 14 6 31 rect 10 2 14 47
rect 10 4 14 49 rect 20 2 24 47
rect 20 4 24 49 rect 9 -2 14 2
rect 9 0 14 4 rect 23 -2 24 2
rect 23 0 24 4 rect 32 33 36 47
rect 32 35 36 49 rect 32 -2 36 29
rect 32 0 36 31
<< m3p >> << m3p >>
rect 0 0 34 49 rect 0 0 34 45
<< labels >> << labels >>
rlabel metal2 2 31 2 31 3 gnd rlabel m2contact 20 2 20 2 1 BR
rlabel metal2 32 31 32 31 7 gnd rlabel metal2 10 2 10 2 1 BL
rlabel metal2 10 4 10 4 1 BL rlabel metal1 2 6 2 6 3 WL
rlabel m2contact 20 4 20 4 1 BR rlabel metal2 -1 28 -1 28 1 gnd
rlabel nsubstratencontact 2 45 2 45 4 vdd rlabel metal2 33 28 33 28 1 gnd
rlabel metal1 2 7 2 7 3 WL rlabel metal1 17 45 17 45 5 vdd
<< end >> << end >>

View File

@ -58,7 +58,7 @@ parameter["beta"] = 2
drclvs_home=os.environ.get("DRCLVS_HOME") drclvs_home=os.environ.get("DRCLVS_HOME")
drc={} drc={}
#grid size #grid size is 1/2 a lambda
drc["grid"]=0.15 drc["grid"]=0.15
#DRC/LVS test set_up #DRC/LVS test set_up
drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul" drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul"