mirror of https://github.com/VLSIDA/OpenRAM.git
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:
parent
fb0355ebaf
commit
1dc7752429
|
|
@ -115,8 +115,8 @@ class bitcell_array(design.design):
|
|||
gnd_pins = self.cell_inst[0,col].get_pins("gnd")
|
||||
for gnd_pin in gnd_pins:
|
||||
# avoid duplicates by only doing even rows
|
||||
# also skip if it is not the full height (a through rail)
|
||||
if gnd_pin.layer=="metal2" and col%2 == 0 and gnd_pin.height()>=self.cell.height:
|
||||
# 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.by()==lower_y:
|
||||
self.add_layout_pin(text="gnd",
|
||||
layer="metal2",
|
||||
offset=gnd_pin.ll(),
|
||||
|
|
|
|||
|
|
@ -27,8 +27,13 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
|
||||
# Check if the name already exists, if so, give an error
|
||||
# because each reference must be a unique name.
|
||||
ok_list = ['ms_flop.ms_flop', 'bitcell.bitcell', 'contact.contact',
|
||||
'ptx.ptx', 'sram.sram',
|
||||
# These modules ensure unique names or have no changes if they
|
||||
# aren't unique
|
||||
ok_list = ['ms_flop.ms_flop',
|
||||
'bitcell.bitcell',
|
||||
'contact.contact',
|
||||
'ptx.ptx',
|
||||
'sram.sram',
|
||||
'hierarchical_predecode2x4.hierarchical_predecode2x4',
|
||||
'hierarchical_predecode3x8.hierarchical_predecode3x8']
|
||||
if name not in design.name_map:
|
||||
|
|
@ -41,6 +46,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
def setup_drc_constants(self):
|
||||
""" These are some DRC constants used in many places in the compiler."""
|
||||
from tech import drc
|
||||
self.well_width = drc["minwidth_well"]
|
||||
self.poly_width = drc["minwidth_poly"]
|
||||
self.poly_space = drc["poly_to_poly"]
|
||||
self.m1_width = drc["minwidth_metal1"]
|
||||
|
|
@ -49,7 +55,16 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout):
|
|||
self.m2_space = drc["metal2_to_metal2"]
|
||||
self.m3_width = drc["minwidth_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):
|
||||
""" Return a map of pin locations of the instance offset """
|
||||
# find the instance
|
||||
|
|
|
|||
|
|
@ -336,14 +336,14 @@ class layout(lef.lef):
|
|||
implant_type=implant_type,
|
||||
well_type=well_type)
|
||||
self.add_mod(via)
|
||||
self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
inst=self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
# We don't model the logical connectivity of wires/paths
|
||||
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):
|
||||
""" 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_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=corrected_offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
inst=self.add_inst(name=via.name,
|
||||
mod=via,
|
||||
offset=corrected_offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
# We don't model the logical connectivity of wires/paths
|
||||
self.connect_inst([])
|
||||
return via
|
||||
return inst
|
||||
|
||||
def add_ptx(self, offset, mirror="R0", rotate=0, width=1, mults=1, tx_type="nmos"):
|
||||
"""Adds a ptx module to the design."""
|
||||
|
|
@ -387,12 +387,12 @@ class layout(lef.lef):
|
|||
mults=mults,
|
||||
tx_type=tx_type)
|
||||
self.add_mod(mos)
|
||||
self.add_inst(name=mos.name,
|
||||
mod=mos,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
return mos
|
||||
inst=self.add_inst(name=mos.name,
|
||||
mod=mos,
|
||||
offset=offset,
|
||||
mirror=mirror,
|
||||
rotate=rotate)
|
||||
return inst
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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.")
|
||||
|
||||
# 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)
|
||||
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 """
|
||||
|
||||
# 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
|
||||
nwell_height = self.max_y_offset - middle_position.y
|
||||
nwell_height = max_y_offset - middle_position.y
|
||||
if info["has_nwell"]:
|
||||
self.add_rect(layer="nwell",
|
||||
offset=middle_position,
|
||||
|
|
@ -111,15 +111,15 @@ class pgate(design.design):
|
|||
width=self.well_width,
|
||||
height=nwell_height)
|
||||
|
||||
self.pwell_position = vector(0,-0.5*drc["minwidth_metal1"])
|
||||
pwell_height = middle_position.y-self.pwell_position.y
|
||||
pwell_position = vector(0,-0.5*self.m1_width)
|
||||
pwell_height = middle_position.y-pwell_position.y
|
||||
if info["has_pwell"]:
|
||||
self.add_rect(layer="pwell",
|
||||
offset=self.pwell_position,
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=pwell_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=self.pwell_position,
|
||||
offset=pwell_position,
|
||||
width=self.well_width,
|
||||
height=pwell_height)
|
||||
|
||||
|
|
@ -132,8 +132,9 @@ class pgate(design.design):
|
|||
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
|
||||
# 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,
|
||||
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)
|
||||
# Offset by half a contact in x and y
|
||||
contact_offset += vector(0.5*pmos.active_contact.first_layer_width,
|
||||
|
|
@ -144,11 +145,11 @@ class pgate(design.design):
|
|||
well_type="n")
|
||||
self.add_rect_center(layer="metal1",
|
||||
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)
|
||||
|
||||
# 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
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
|
|
@ -156,27 +157,29 @@ class pgate(design.design):
|
|||
# height=pmos.active_height)
|
||||
|
||||
# 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_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"])
|
||||
implant_width = pmos.active_contact.width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = pmos.active_height + 2*drc["implant_enclosure_active"]
|
||||
# implant_spacing = self.implant_space+self.implant_enclose_active
|
||||
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
|
||||
# implant_width = pmos.active_contact.width + 2*self.implant_enclose_active
|
||||
# implant_height = pmos.active_height + 2*self.implant_enclose_active
|
||||
# self.add_rect(layer="nimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
# height=implant_height)
|
||||
|
||||
# Return the top of the well
|
||||
|
||||
def add_pwell_contact(self, nmos, nmos_pos):
|
||||
""" Add an pwell contact next to the given nmos device. """
|
||||
|
||||
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
|
||||
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
|
||||
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)
|
||||
|
||||
# Offset by half a contact
|
||||
|
|
@ -188,21 +191,21 @@ class pgate(design.design):
|
|||
well_type="p")
|
||||
self.add_rect_center(layer="metal1",
|
||||
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)
|
||||
|
||||
# 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
|
||||
# self.add_rect(layer="active",
|
||||
# offset=active_offset,
|
||||
# width=nmos.active_contact.width,
|
||||
# height=nmos.active_height)
|
||||
|
||||
implant_spacing = drc["implant_to_implant"]+drc["implant_enclosure_active"]
|
||||
implant_offset = active_offset + vector(implant_spacing,0) - vector(0,drc["implant_enclosure_active"])
|
||||
implant_width = nmos.active_contact.width + 2*drc["implant_enclosure_active"]
|
||||
implant_height = nmos.active_height + 2*drc["implant_enclosure_active"]
|
||||
# implant_spacing = self.implant_space+self.implant_enclose_active
|
||||
# implant_offset = active_offset + vector(implant_spacing,0) - vector(0,self.implant_enclose_active)
|
||||
# implant_width = nmos.active_contact.width + 2*self.implant_enclose_active
|
||||
# implant_height = nmos.active_height + 2*self.implant_enclose_active
|
||||
# self.add_rect(layer="pimplant",
|
||||
# offset=implant_offset,
|
||||
# width=implant_width,
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ class pinv(pgate.pgate):
|
|||
self.setup_layout_constants()
|
||||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.connect_rails()
|
||||
self.route_input_gate(self.pmos_inst, self.nmos_inst, self.output_pos.y, "A", rotate=0)
|
||||
self.route_outputs()
|
||||
|
|
@ -128,9 +128,6 @@ class pinv(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# 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):
|
||||
|
|
@ -183,9 +180,14 @@ class pinv(pgate.pgate):
|
|||
self.connect_inst(["Z", "A", "gnd", "gnd"])
|
||||
|
||||
|
||||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(self.pmos_pos.y+self.nmos_pos.y+self.nmos.active_height))
|
||||
# Output position will be in between the PMOS and NMOS drains
|
||||
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())
|
||||
|
||||
|
||||
|
||||
def route_outputs(self):
|
||||
|
|
@ -196,8 +198,8 @@ class pinv(pgate.pgate):
|
|||
pmos_drain_pin = self.pmos_inst.get_pin("D")
|
||||
|
||||
# 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)
|
||||
pmos_drain_pos = vector(nmos_drain_pos.x,pmos_drain_pin.bc().y)
|
||||
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)
|
||||
self.add_path("metal1",[nmos_drain_pos,pmos_drain_pos])
|
||||
|
||||
# Remember the mid for the output
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ class pnand2(pgate.pgate):
|
|||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -94,9 +94,6 @@ class pnand2(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# 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
|
||||
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
|
||||
# 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
|
||||
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):
|
||||
""" Add n/p well taps to the layout and connect to supplies AFTER the wells are created """
|
||||
|
||||
|
|
|
|||
|
|
@ -51,8 +51,8 @@ class pnand3(pgate.pgate):
|
|||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -88,7 +88,6 @@ class pnand3(pgate.pgate):
|
|||
|
||||
# This will help with the wells and the input/output placement
|
||||
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 extra liberal for pnand3 because we know there are big transistor sizes
|
||||
|
|
@ -153,6 +152,8 @@ class pnand3(pgate.pgate):
|
|||
offset=self.nmos3_pos)
|
||||
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):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
|
|
|||
|
|
@ -52,8 +52,8 @@ class pnor2(pgate.pgate):
|
|||
self.add_supply_rails()
|
||||
self.add_ptx()
|
||||
self.connect_rails()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.add_well_contacts()
|
||||
self.extend_wells(self.well_pos)
|
||||
self.route_inputs()
|
||||
self.route_output()
|
||||
|
||||
|
|
@ -98,9 +98,6 @@ class pnor2(pgate.pgate):
|
|||
self.width = self.well_width
|
||||
# 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
|
||||
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
|
||||
# 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
|
||||
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):
|
||||
""" Add n/p well taps to the layout and connect to supplies """
|
||||
|
||||
|
|
|
|||
|
|
@ -94,25 +94,19 @@ class ptx(design.design):
|
|||
self.active_contact = contact(layer_stack=("active", "contact", "metal1"),
|
||||
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)
|
||||
self.poly_pitch = max(2*drc["contact_to_gate"] + self.contact_width + self.poly_width,
|
||||
drc["poly_to_poly"])
|
||||
self.poly_pitch = max(2*self.contact_to_gate + self.contact_width + self.poly_width,
|
||||
self.poly_space)
|
||||
|
||||
# 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.
|
||||
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
|
||||
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,
|
||||
|
|
@ -125,22 +119,25 @@ class ptx(design.design):
|
|||
# Poly height must include poly extension over 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
|
||||
if info["has_{}well".format(self.well_type)]:
|
||||
self.well_width = max(self.active_width + 2*drc["well_enclosure_active"],
|
||||
drc["minwidth_well"])
|
||||
self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"],
|
||||
drc["minwidth_well"])
|
||||
|
||||
self.height = self.well_height
|
||||
self.width = self.well_width
|
||||
self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
|
||||
self.well_width)
|
||||
self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
|
||||
self.well_width)
|
||||
# We are going to shift the 0,0, so include that in the width and height
|
||||
self.height = self.cell_well_height - self.active_offset.y
|
||||
self.width = self.cell_well_width - self.active_offset.x
|
||||
else:
|
||||
# If no well, use the boundary of the active and poly
|
||||
self.height = self.poly_height
|
||||
self.width = self.active_width
|
||||
|
||||
# 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)
|
||||
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
|
||||
# of the contacts to avoid DRC violations to the other contacts
|
||||
pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \
|
||||
+ drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"])
|
||||
# This is the width of a contact to extend the ends of the pin
|
||||
end_offset = vector(self.active_contact.second_layer_width/2,0)
|
||||
+ self.m1_space + 0.5*self.m1_width)
|
||||
# This is the width of a m1 extend the ends of the pin
|
||||
end_offset = vector(self.m1_width/2,0)
|
||||
|
||||
# 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.
|
||||
|
|
@ -280,12 +277,12 @@ class ptx(design.design):
|
|||
if info["has_{}well".format(self.well_type)]:
|
||||
self.add_rect(layer="{}well".format(self.well_type),
|
||||
offset=(0,0),
|
||||
width=self.well_width,
|
||||
height=self.well_height)
|
||||
width=self.cell_well_width,
|
||||
height=self.cell_well_height)
|
||||
self.add_rect(layer="vtg",
|
||||
offset=(0,0),
|
||||
width=self.well_width,
|
||||
height=self.well_height)
|
||||
width=self.cell_well_width,
|
||||
height=self.cell_well_height)
|
||||
|
||||
|
||||
def calculate_num_contacts(self):
|
||||
|
|
@ -331,8 +328,8 @@ class ptx(design.design):
|
|||
self.add_layout_pin_center_rect(text="S",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
width=contact.second_layer_width,
|
||||
height=contact.second_layer_height)
|
||||
width=contact.mod.second_layer_width,
|
||||
height=contact.mod.second_layer_height)
|
||||
|
||||
|
||||
for pos in drain_positions:
|
||||
|
|
@ -344,8 +341,8 @@ class ptx(design.design):
|
|||
self.add_layout_pin_center_rect(text="D",
|
||||
layer="metal1",
|
||||
offset=pos,
|
||||
width=contact.second_layer_width,
|
||||
height=contact.second_layer_height)
|
||||
width=contact.mod.second_layer_width,
|
||||
height=contact.mod.second_layer_height)
|
||||
|
||||
if self.connect_active:
|
||||
self.connect_fingered_active(drain_positions, source_positions)
|
||||
|
|
|
|||
|
|
@ -12,12 +12,13 @@ ln -s 2001a current
|
|||
#!/bin/sh
|
||||
magic -dnull -noconsole << EOF
|
||||
tech load SCN3ME_SUBM.30
|
||||
gds rescale false
|
||||
scalegrid 1 2
|
||||
gds rescale no
|
||||
gds polygon subcell true
|
||||
gds warning default
|
||||
gds read $1
|
||||
load $1
|
||||
save $1
|
||||
writeall force
|
||||
drc count
|
||||
drc why
|
||||
quit -noprompt
|
||||
|
|
@ -29,7 +30,8 @@ rm -f $1.ext
|
|||
rm -f $1.spice
|
||||
magic -dnull -noconsole << EOF
|
||||
tech load SCN3ME_SUBM.30
|
||||
gds rescale false
|
||||
scalegrid 1 2
|
||||
gds rescale no
|
||||
gds polygon subcell true
|
||||
gds warning default
|
||||
gds read $1
|
||||
|
|
@ -72,12 +74,13 @@ def write_magic_script(cell_name, gds_name, extract=False):
|
|||
f.write("#!/bin/sh\n")
|
||||
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
|
||||
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 warning default\n")
|
||||
f.write("gds read {}\n".format(gds_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 catchup\n")
|
||||
f.write("drc count total\n")
|
||||
|
|
@ -123,6 +126,12 @@ def write_netgen_script(cell_name, sp_name):
|
|||
cell_name))
|
||||
f.write("property {{{0}{1}.spice pfet}} remove as ad ps pd\n".format(OPTS.openram_temp,
|
||||
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("log start\n")
|
||||
f.write("compare hierarchical {0}{1}.spice {{{2} {1}}}\n".format(OPTS.openram_temp,
|
||||
|
|
|
|||
|
|
@ -149,8 +149,8 @@ class wordline_driver(design.design):
|
|||
self.add_segment_center(layer="metal1",
|
||||
start=clk_offset,
|
||||
end=a_pos)
|
||||
m1m2_via = self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=clk_offset)
|
||||
self.add_via_center(layers=("metal1", "via1", "metal2"),
|
||||
offset=clk_offset)
|
||||
|
||||
# first inv to nand2 A
|
||||
zb_pos = inv1_inst.get_pin("Z").bc()
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,119 +1,114 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1516665972
|
||||
timestamp 1516839303
|
||||
<< nwell >>
|
||||
rect -5 31 42 52
|
||||
rect -8 29 42 50
|
||||
<< pwell >>
|
||||
rect -5 -6 42 31
|
||||
rect -8 -8 42 29
|
||||
<< ntransistor >>
|
||||
rect 7 12 9 20
|
||||
rect 29 12 31 20
|
||||
rect 10 5 14 7
|
||||
rect 24 5 28 7
|
||||
rect 7 10 9 18
|
||||
rect 29 10 31 18
|
||||
rect 10 3 14 5
|
||||
rect 24 3 28 5
|
||||
<< ptransistor >>
|
||||
rect 7 39 11 42
|
||||
rect 27 39 31 42
|
||||
rect 7 37 11 40
|
||||
rect 27 37 31 40
|
||||
<< ndiffusion >>
|
||||
rect 2 20 6 23
|
||||
rect 32 20 36 23
|
||||
rect 6 16 7 20
|
||||
rect -2 16 7 18
|
||||
rect 2 12 7 16
|
||||
rect 9 16 10 20
|
||||
rect 9 12 14 16
|
||||
rect 28 16 29 20
|
||||
rect 24 12 29 16
|
||||
rect 31 16 32 20
|
||||
rect 31 12 36 16
|
||||
rect 10 7 14 12
|
||||
rect 24 7 28 12
|
||||
rect 10 4 14 5
|
||||
rect 24 4 28 5
|
||||
rect -2 10 7 12
|
||||
rect 9 14 10 18
|
||||
rect 9 10 14 14
|
||||
rect 28 14 29 18
|
||||
rect 24 10 29 14
|
||||
rect 31 16 36 18
|
||||
rect 31 12 32 16
|
||||
rect 31 10 36 12
|
||||
rect 10 5 14 10
|
||||
rect 24 5 28 10
|
||||
rect 10 2 14 3
|
||||
rect 24 2 28 3
|
||||
<< pdiffusion >>
|
||||
rect 2 42 6 45
|
||||
rect 32 42 36 45
|
||||
rect 6 39 7 42
|
||||
rect 11 39 12 42
|
||||
rect 26 39 27 42
|
||||
rect 31 39 32 42
|
||||
rect 32 40 36 43
|
||||
rect 2 37 7 40
|
||||
rect 11 37 12 40
|
||||
rect 26 37 27 40
|
||||
rect 31 37 32 40
|
||||
<< ndcontact >>
|
||||
rect 2 16 6 20
|
||||
rect 10 16 14 20
|
||||
rect 24 16 28 20
|
||||
rect 32 16 36 20
|
||||
rect 10 0 14 4
|
||||
rect 24 0 28 4
|
||||
rect -2 12 2 16
|
||||
rect 10 14 14 18
|
||||
rect 24 14 28 18
|
||||
rect 32 12 36 16
|
||||
rect 10 -2 14 2
|
||||
rect 24 -2 28 2
|
||||
<< pdcontact >>
|
||||
rect 2 38 6 42
|
||||
rect 12 38 16 42
|
||||
rect 22 38 26 42
|
||||
rect 32 38 36 42
|
||||
rect -2 36 2 40
|
||||
rect 12 36 16 40
|
||||
rect 22 36 26 40
|
||||
rect 32 36 36 40
|
||||
<< psubstratepcontact >>
|
||||
rect 2 23 6 27
|
||||
rect 32 23 36 27
|
||||
rect 32 22 36 26
|
||||
<< nsubstratencontact >>
|
||||
rect 0 45 6 49
|
||||
rect 32 45 36 49
|
||||
rect 32 43 36 47
|
||||
<< polysilicon >>
|
||||
rect 7 42 11 44
|
||||
rect 27 42 31 44
|
||||
rect 7 37 11 39
|
||||
rect 7 23 9 37
|
||||
rect 27 36 31 39
|
||||
rect 15 35 31 36
|
||||
rect 19 34 31 35
|
||||
rect 7 22 21 23
|
||||
rect 7 21 24 22
|
||||
rect 7 20 9 21
|
||||
rect 29 20 31 34
|
||||
rect 7 10 9 12
|
||||
rect 17 7 21 8
|
||||
rect 29 10 31 12
|
||||
rect 0 5 10 7
|
||||
rect 14 5 24 7
|
||||
rect 28 5 36 7
|
||||
rect 7 40 11 42
|
||||
rect 27 40 31 42
|
||||
rect 7 35 11 37
|
||||
rect 7 21 9 35
|
||||
rect 27 34 31 37
|
||||
rect 15 33 31 34
|
||||
rect 19 32 31 33
|
||||
rect 7 20 21 21
|
||||
rect 7 19 24 20
|
||||
rect 7 18 9 19
|
||||
rect 29 18 31 32
|
||||
rect 7 8 9 10
|
||||
rect 17 5 21 6
|
||||
rect 29 8 31 10
|
||||
rect -2 3 10 5
|
||||
rect 14 3 24 5
|
||||
rect 28 3 36 5
|
||||
<< polycontact >>
|
||||
rect 15 31 19 35
|
||||
rect 21 22 25 26
|
||||
rect 17 8 21 12
|
||||
rect 15 29 19 33
|
||||
rect 21 20 25 24
|
||||
rect 17 6 21 10
|
||||
<< metal1 >>
|
||||
rect 6 45 32 49
|
||||
rect 2 42 6 45
|
||||
rect 32 42 36 45
|
||||
rect 2 27 6 31
|
||||
rect 2 20 6 23
|
||||
rect 11 20 15 38
|
||||
rect 23 26 27 38
|
||||
rect 25 22 27 26
|
||||
rect 23 20 27 22
|
||||
rect 32 27 36 31
|
||||
rect 32 20 36 23
|
||||
rect 0 8 17 11
|
||||
rect 21 8 36 11
|
||||
rect 0 7 36 8
|
||||
rect 9 0 10 4
|
||||
rect 23 0 24 4
|
||||
rect -2 43 32 47
|
||||
rect -2 40 2 43
|
||||
rect 32 40 36 43
|
||||
rect -2 16 2 29
|
||||
rect 11 18 15 36
|
||||
rect 23 24 27 36
|
||||
rect 25 20 27 24
|
||||
rect 23 18 27 20
|
||||
rect 32 26 36 29
|
||||
rect 32 16 36 22
|
||||
rect -2 6 17 9
|
||||
rect 21 6 36 9
|
||||
rect -2 5 36 6
|
||||
rect 9 -2 10 2
|
||||
rect 23 -2 24 2
|
||||
<< m2contact >>
|
||||
rect 2 31 6 35
|
||||
rect 32 31 36 35
|
||||
rect 5 0 9 4
|
||||
rect 19 0 23 4
|
||||
rect -2 29 2 33
|
||||
rect 32 29 36 33
|
||||
rect 5 -2 9 2
|
||||
rect 19 -2 23 2
|
||||
<< metal2 >>
|
||||
rect 0 35 6 49
|
||||
rect 0 31 2 35
|
||||
rect 0 14 6 31
|
||||
rect 10 4 14 49
|
||||
rect 20 4 24 49
|
||||
rect 9 0 14 4
|
||||
rect 23 0 24 4
|
||||
rect 32 35 36 49
|
||||
rect 32 0 36 31
|
||||
rect -2 33 2 47
|
||||
rect -2 12 2 29
|
||||
rect 10 2 14 47
|
||||
rect 20 2 24 47
|
||||
rect 9 -2 14 2
|
||||
rect 23 -2 24 2
|
||||
rect 32 33 36 47
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
rect 0 0 34 49
|
||||
rect 0 0 34 45
|
||||
<< labels >>
|
||||
rlabel m2contact 20 4 20 4 1 BR
|
||||
rlabel metal2 10 4 10 4 1 BL
|
||||
rlabel metal2 32 31 32 31 7 gnd
|
||||
rlabel metal1 32 45 32 45 4 vdd
|
||||
rlabel metal2 2 31 2 31 3 gnd
|
||||
rlabel metal1 2 8 2 8 3 WL
|
||||
rlabel m2contact 20 2 20 2 1 BR
|
||||
rlabel metal2 10 2 10 2 1 BL
|
||||
rlabel metal1 2 6 2 6 3 WL
|
||||
rlabel metal2 -1 28 -1 28 1 gnd
|
||||
rlabel metal2 33 28 33 28 1 gnd
|
||||
rlabel metal1 17 45 17 45 5 vdd
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -1,122 +1,116 @@
|
|||
magic
|
||||
tech scmos
|
||||
timestamp 1516666672
|
||||
timestamp 1516980606
|
||||
<< nwell >>
|
||||
rect -4 31 42 53
|
||||
rect -8 29 42 50
|
||||
<< pwell >>
|
||||
rect -4 -6 42 31
|
||||
rect -8 -8 42 29
|
||||
<< ntransistor >>
|
||||
rect 7 12 9 20
|
||||
rect 29 12 31 20
|
||||
rect 10 5 14 7
|
||||
rect 24 5 28 7
|
||||
rect 7 10 9 18
|
||||
rect 29 10 31 18
|
||||
rect 10 3 14 5
|
||||
rect 24 3 28 5
|
||||
<< ptransistor >>
|
||||
rect 7 39 11 42
|
||||
rect 27 39 31 42
|
||||
rect 7 37 11 40
|
||||
rect 27 37 31 40
|
||||
<< ndiffusion >>
|
||||
rect 2 20 6 23
|
||||
rect 32 20 36 23
|
||||
rect 6 16 7 20
|
||||
rect -2 16 7 18
|
||||
rect 2 12 7 16
|
||||
rect 9 16 10 20
|
||||
rect 9 12 14 16
|
||||
rect 28 16 29 20
|
||||
rect 24 12 29 16
|
||||
rect 31 16 32 20
|
||||
rect 31 12 36 16
|
||||
rect 10 7 14 12
|
||||
rect 24 7 28 12
|
||||
rect 10 4 14 5
|
||||
rect 24 4 28 5
|
||||
rect -2 10 7 12
|
||||
rect 9 14 10 18
|
||||
rect 9 10 14 14
|
||||
rect 28 14 29 18
|
||||
rect 24 10 29 14
|
||||
rect 31 16 36 18
|
||||
rect 31 12 32 16
|
||||
rect 31 10 36 12
|
||||
rect 10 5 14 10
|
||||
rect 24 5 28 10
|
||||
rect 10 2 14 3
|
||||
rect 24 2 28 3
|
||||
<< pdiffusion >>
|
||||
rect 2 42 6 45
|
||||
rect 32 42 36 45
|
||||
rect 6 39 7 42
|
||||
rect 11 39 12 42
|
||||
rect 26 39 27 42
|
||||
rect 31 39 32 42
|
||||
rect 32 40 36 43
|
||||
rect 2 37 7 40
|
||||
rect 11 37 12 40
|
||||
rect 26 37 27 40
|
||||
rect 31 37 32 40
|
||||
<< ndcontact >>
|
||||
rect 2 16 6 20
|
||||
rect 10 16 14 20
|
||||
rect 24 16 28 20
|
||||
rect 32 16 36 20
|
||||
rect 10 0 14 4
|
||||
rect 24 0 28 4
|
||||
rect -2 12 2 16
|
||||
rect 10 14 14 18
|
||||
rect 24 14 28 18
|
||||
rect 32 12 36 16
|
||||
rect 10 -2 14 2
|
||||
rect 24 -2 28 2
|
||||
<< pdcontact >>
|
||||
rect 2 38 6 42
|
||||
rect 12 38 16 42
|
||||
rect 22 38 26 42
|
||||
rect 32 38 36 42
|
||||
rect -2 36 2 40
|
||||
rect 12 36 16 40
|
||||
rect 22 36 26 40
|
||||
rect 32 36 36 40
|
||||
<< psubstratepcontact >>
|
||||
rect 2 23 6 27
|
||||
rect 32 23 36 27
|
||||
rect 32 22 36 26
|
||||
<< nsubstratencontact >>
|
||||
rect 0 45 6 49
|
||||
rect 32 45 36 49
|
||||
rect 32 43 36 47
|
||||
<< polysilicon >>
|
||||
rect 7 42 11 44
|
||||
rect 27 42 31 44
|
||||
rect 7 37 11 39
|
||||
rect 7 23 9 37
|
||||
rect 27 36 31 39
|
||||
rect 15 35 31 36
|
||||
rect 19 34 31 35
|
||||
rect 7 22 21 23
|
||||
rect 7 21 24 22
|
||||
rect 7 20 9 21
|
||||
rect 29 20 31 34
|
||||
rect 7 10 9 12
|
||||
rect 17 7 21 8
|
||||
rect 29 10 31 12
|
||||
rect 0 5 10 7
|
||||
rect 14 5 24 7
|
||||
rect 28 5 36 7
|
||||
rect 7 40 11 42
|
||||
rect 27 40 31 42
|
||||
rect 7 35 11 37
|
||||
rect 7 21 9 35
|
||||
rect 27 34 31 37
|
||||
rect 15 33 31 34
|
||||
rect 19 32 31 33
|
||||
rect 7 20 21 21
|
||||
rect 7 19 24 20
|
||||
rect 7 18 9 19
|
||||
rect 29 18 31 32
|
||||
rect 7 8 9 10
|
||||
rect 17 5 21 6
|
||||
rect 29 8 31 10
|
||||
rect -2 3 10 5
|
||||
rect 14 3 24 5
|
||||
rect 28 3 36 5
|
||||
<< polycontact >>
|
||||
rect 15 31 19 35
|
||||
rect 21 22 25 26
|
||||
rect 17 8 21 12
|
||||
rect 15 29 19 33
|
||||
rect 21 20 25 24
|
||||
rect 17 6 21 10
|
||||
<< metal1 >>
|
||||
rect 6 45 32 49
|
||||
rect 2 42 6 45
|
||||
rect 32 42 36 45
|
||||
rect 11 35 15 38
|
||||
rect 6 31 15 35
|
||||
rect 2 27 6 31
|
||||
rect 2 20 6 23
|
||||
rect 11 20 15 31
|
||||
rect 23 26 27 38
|
||||
rect 25 22 27 26
|
||||
rect 23 20 27 22
|
||||
rect 32 27 36 31
|
||||
rect 32 20 36 23
|
||||
rect 2 14 6 16
|
||||
rect 0 8 17 11
|
||||
rect 21 8 36 11
|
||||
rect 0 7 36 8
|
||||
rect 9 0 10 4
|
||||
rect 23 0 24 4
|
||||
rect -2 43 32 47
|
||||
rect -2 40 2 43
|
||||
rect 32 40 36 43
|
||||
rect -2 18 2 29
|
||||
rect 11 18 15 36
|
||||
rect 23 24 27 36
|
||||
rect 25 20 27 24
|
||||
rect 23 18 27 20
|
||||
rect 32 26 36 29
|
||||
rect -2 16 10 18
|
||||
rect 2 14 10 16
|
||||
rect 32 16 36 22
|
||||
rect -2 6 17 9
|
||||
rect 21 6 36 9
|
||||
rect -2 5 36 6
|
||||
rect 9 -2 10 2
|
||||
rect 23 -2 24 2
|
||||
<< m2contact >>
|
||||
rect 2 31 6 35
|
||||
rect 32 31 36 35
|
||||
rect 5 0 9 4
|
||||
rect 19 0 23 4
|
||||
rect -2 29 2 33
|
||||
rect 32 29 36 33
|
||||
rect 5 -2 9 2
|
||||
rect 19 -2 23 2
|
||||
<< metal2 >>
|
||||
rect 0 35 6 49
|
||||
rect 0 31 2 35
|
||||
rect 0 14 6 31
|
||||
rect 10 4 14 49
|
||||
rect 20 4 24 49
|
||||
rect 9 0 14 4
|
||||
rect 23 0 24 4
|
||||
rect 32 35 36 49
|
||||
rect 32 0 36 31
|
||||
rect -2 33 2 47
|
||||
rect -2 12 2 29
|
||||
rect 10 2 14 47
|
||||
rect 20 2 24 47
|
||||
rect 9 -2 14 2
|
||||
rect 23 -2 24 2
|
||||
rect 32 33 36 47
|
||||
rect 32 -2 36 29
|
||||
<< m3p >>
|
||||
rect 0 0 34 49
|
||||
rect 0 0 34 45
|
||||
<< labels >>
|
||||
rlabel metal2 2 31 2 31 3 gnd
|
||||
rlabel metal2 32 31 32 31 7 gnd
|
||||
rlabel metal2 10 4 10 4 1 BL
|
||||
rlabel m2contact 20 4 20 4 1 BR
|
||||
rlabel nsubstratencontact 2 45 2 45 4 vdd
|
||||
rlabel metal1 2 7 2 7 3 WL
|
||||
rlabel m2contact 20 2 20 2 1 BR
|
||||
rlabel metal2 10 2 10 2 1 BL
|
||||
rlabel metal1 2 6 2 6 3 WL
|
||||
rlabel metal2 -1 28 -1 28 1 gnd
|
||||
rlabel metal2 33 28 33 28 1 gnd
|
||||
rlabel metal1 17 45 17 45 5 vdd
|
||||
<< end >>
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ parameter["beta"] = 2
|
|||
drclvs_home=os.environ.get("DRCLVS_HOME")
|
||||
|
||||
drc={}
|
||||
#grid size
|
||||
#grid size is 1/2 a lambda
|
||||
drc["grid"]=0.15
|
||||
#DRC/LVS test set_up
|
||||
drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul"
|
||||
|
|
|
|||
Loading…
Reference in New Issue