Switched to GF180D for extra metal layers, Fixed drc parameters so contacts are valid. ptx.py modified to achieve proper layer placement with gf180. ROM array and precharge DRC clean.

This commit is contained in:
Sage Walker 2023-07-25 14:45:14 -07:00 committed by SWalker
parent 0040efb86f
commit d6cb15c82d
11 changed files with 129 additions and 51 deletions

View File

@ -10,7 +10,7 @@ from openram.tech import drc, layer, preferred_directions
from openram.tech import layer as tech_layers from openram.tech import layer as tech_layers
from .hierarchy_design import hierarchy_design from .hierarchy_design import hierarchy_design
from .vector import vector from .vector import vector
from .utils import ceil
class contact(hierarchy_design): class contact(hierarchy_design):
""" """
@ -125,6 +125,8 @@ class contact(hierarchy_design):
self.first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name)) self.first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
self.first_layer_enclosure = drc("{0}_enclose_{1}".format(self.first_layer_name, self.via_layer_name)) self.first_layer_enclosure = drc("{0}_enclose_{1}".format(self.first_layer_name, self.via_layer_name))
self.first_layer_minarea = drc("minarea_{0}".format(self.first_layer_name))
# If there's a different rule for active # If there's a different rule for active
# FIXME: Make this more elegant # FIXME: Make this more elegant
if self.is_well_contact and self.first_layer_name == "active" and "tap_extend_contact" in drc.keys(): if self.is_well_contact and self.first_layer_name == "active" and "tap_extend_contact" in drc.keys():
@ -135,7 +137,7 @@ class contact(hierarchy_design):
self.second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name)) self.second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
self.second_layer_enclosure = drc("{0}_enclose_{1}".format(self.second_layer_name, self.via_layer_name)) self.second_layer_enclosure = drc("{0}_enclose_{1}".format(self.second_layer_name, self.via_layer_name))
self.second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)) self.second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
self.second_layer_minarea = drc("minarea_{0}".format(self.second_layer_name))
# In some technologies, the minimum width may be larger # In some technologies, the minimum width may be larger
# than the overlap requirement around the via, so # than the overlap requirement around the via, so
# check this for each dimension. # check this for each dimension.
@ -143,7 +145,7 @@ class contact(hierarchy_design):
self.first_layer_horizontal_enclosure = max(self.first_layer_enclosure, self.first_layer_horizontal_enclosure = max(self.first_layer_enclosure,
(self.first_layer_minwidth - self.contact_array_width) / 2) (self.first_layer_minwidth - self.contact_array_width) / 2)
self.first_layer_vertical_enclosure = max(self.first_layer_extend, self.first_layer_vertical_enclosure = max(self.first_layer_extend,
(self.first_layer_minwidth - self.contact_array_height) / 2) (self.first_layer_minwidth - self.contact_array_height) / 2)
elif self.directions[0] == "H": elif self.directions[0] == "H":
self.first_layer_horizontal_enclosure = max(self.first_layer_extend, self.first_layer_horizontal_enclosure = max(self.first_layer_extend,
(self.first_layer_minwidth - self.contact_array_width) / 2) (self.first_layer_minwidth - self.contact_array_width) / 2)
@ -166,7 +168,7 @@ class contact(hierarchy_design):
self.second_layer_vertical_enclosure = max(self.second_layer_enclosure, self.second_layer_vertical_enclosure = max(self.second_layer_enclosure,
(self.second_layer_minwidth - self.contact_array_width) / 2) (self.second_layer_minwidth - self.contact_array_width) / 2)
else: else:
debug.error("Invalid secon layer direction: ".format(self.directions[1]), -1) debug.error("Invalid second layer direction: ".format(self.directions[1]), -1)
def create_contact_array(self): def create_contact_array(self):
""" Create the contact array at the origin""" """ Create the contact array at the origin"""
@ -221,6 +223,18 @@ class contact(hierarchy_design):
first_layer_name = "tap" first_layer_name = "tap"
else: else:
first_layer_name = self.first_layer_name first_layer_name = self.first_layer_name
area = self.first_layer_width * self.first_layer_height
if area < self.first_layer_minarea and self.is_well_contact:
if self.directions[0] == "V":
area_extend = (self.first_layer_minarea / self.first_layer_width) - self.first_layer_height
self.first_layer_height = ceil(self.first_layer_height + area_extend)
self.first_layer_position = self.first_layer_position - vector(0, area_extend / 2)
elif self.directions[0] == "H":
area_extend = (self.first_layer_minarea / self.first_layer_height) - self.first_layer_width
self.first_layer_width = ceil(self.first_layer_height + area_extend)
self.first_layer_position = self.first_layer_position - vector(area_extend / 2, 0)
self.add_rect(layer=first_layer_name, self.add_rect(layer=first_layer_name,
offset=self.first_layer_position, offset=self.first_layer_position,
width=self.first_layer_width, width=self.first_layer_width,
@ -236,6 +250,7 @@ class contact(hierarchy_design):
self.second_layer_minwidth) self.second_layer_minwidth)
self.second_layer_height = max(self.contact_array_height + 2 * self.second_layer_vertical_enclosure, self.second_layer_height = max(self.contact_array_height + 2 * self.second_layer_vertical_enclosure,
self.second_layer_minwidth) self.second_layer_minwidth)
self.add_rect(layer=self.second_layer_name, self.add_rect(layer=self.second_layer_name,
offset=self.second_layer_position, offset=self.second_layer_position,
width=self.second_layer_width, width=self.second_layer_width,

View File

@ -22,7 +22,7 @@ from openram.sram_factory import factory
from openram import OPTS from openram import OPTS
from .vector import vector from .vector import vector
from .pin_layout import pin_layout from .pin_layout import pin_layout
from .utils import round_to_grid from .utils import round_to_grid, ceil
from . import geometry from . import geometry
try: try:
@ -838,8 +838,7 @@ class layout():
from_id = tech_layer_indices[from_layer] from_id = tech_layer_indices[from_layer]
to_id = tech_layer_indices[to_layer] to_id = tech_layer_indices[to_layer]
layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] > from_id and tech_layer_indices[x] < to_id]
layer_list = [x for x in tech_layer_indices.keys() if tech_layer_indices[x] >= from_id and tech_layer_indices[x] < to_id]
return layer_list return layer_list
@ -1368,12 +1367,11 @@ class layout():
min_width = drc("minwidth_{}".format(layer)) min_width = drc("minwidth_{}".format(layer))
if preferred_directions[layer] == "V": if preferred_directions[layer] == "V":
new_height = max(min_area / width, min_width) new_height = ceil(max(min_area / width, min_width))
new_width = width new_width = width
else: else:
new_width = max(min_area / height, min_width) new_width = ceil(max(min_area / height, min_width))
new_height = height new_height = height
debug.check(min_area <= round_to_grid(new_height*new_width), "Min area violated.") debug.check(min_area <= round_to_grid(new_height*new_width), "Min area violated.")
self.add_rect_center(layer=layer, self.add_rect_center(layer=layer,

View File

@ -129,12 +129,15 @@ class ptx(design):
# be decided in the layout later. # be decided in the layout later.
area_sd = 2.5 * self.poly_width * self.tx_width area_sd = 2.5 * self.poly_width * self.tx_width
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
# self.channel_length = drc("minlength_channel") if OPTS.tech_name != "gf180mcu" else drc("minlength_channel_" + self.tx_type)
self.channel_length = drc("minlength_channel")
if cell_props.ptx.model_is_subckt: if cell_props.ptx.model_is_subckt:
# sky130 # sky130
main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], main_str = "X{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) self.channel_length)
# Perimeters are in microns # Perimeters are in microns
# Area is in u since it is microns square # Area is in u since it is microns square
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd, area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
@ -143,7 +146,7 @@ class ptx(design):
main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type], main_str = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) self.channel_length)
area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd, area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd,
area_sd) area_sd)
self.spice_device = main_str + area_str self.spice_device = main_str + area_str
@ -160,17 +163,17 @@ class ptx(design):
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format("nshort" if self.tx_type == "nmos" else "pshort", self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult=1".format("nshort" if self.tx_type == "nmos" else "pshort",
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) self.channel_length)
elif cell_props.ptx.model_is_subckt: elif cell_props.ptx.model_is_subckt:
self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type], self.lvs_device = "X{{0}} {{1}} {0} m={1} w={2}u l={3}u".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) self.channel_length)
else: else:
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type], self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2}u l={3}u ".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,
drc("minwidth_poly")) self.channel_length)
def setup_layout_constants(self): def setup_layout_constants(self):
""" """
@ -196,6 +199,9 @@ class ptx(design):
directions=("V", "V"), directions=("V", "V"),
dimensions=(1, self.num_contacts)) dimensions=(1, self.num_contacts))
if OPTS.tech_name == "gf180mcu":
self.poly_width = self.channel_length
# This is the extra poly spacing due to the poly contact to poly contact pitch # This is the extra poly spacing due to the poly contact to poly contact pitch
# of contacted gates # of contacted gates
extra_poly_contact_width = self.poly_contact.width - self.poly_width extra_poly_contact_width = self.poly_contact.width - self.poly_width
@ -216,11 +222,12 @@ class ptx(design):
self.active_width = 2 * self.end_to_contact + self.active_contact.width \ self.active_width = 2 * self.end_to_contact + self.active_contact.width \
+ 2 * self.active_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 # Active height is either the transistor width or the wide enough to enclose the active contact
self.active_height = self.tx_width self.active_height = max(self.tx_width, self.active_contact.width + 2 * self.active_enclose_contact)
# 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.active_height + 2 * self.poly_extend_active
self.active_offset = vector([self.well_enclose_active] * 2) self.active_offset = vector([self.well_enclose_active] * 2)

View File

@ -10,7 +10,7 @@
import math import math
from .bitcell_base_array import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from openram.base import vector from openram.base import vector
from openram import OPTS, debug from openram import debug
from openram.sram_factory import factory from openram.sram_factory import factory
from openram.tech import drc, layer from openram.tech import drc, layer
@ -156,7 +156,7 @@ class rom_base_array(bitcell_base_array):
name = "bit_r{0}_c{1}".format(row, col) name = "bit_r{0}_c{1}".format(row, col)
# when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection # when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection
# when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection # when col = col_size - 1 connected to gnd otherwise create new bl connection
# debug.info(1, "Create cell: r{0}, c{1}".format(row, col)) # debug.info(1, "Create cell: r{0}, c{1}".format(row, col))
if row == self.row_size: if row == self.row_size:

View File

@ -80,6 +80,8 @@ class rom_base_cell(design):
self.cell_inst = self.add_inst( name=self.name + "_nmos", self.cell_inst = self.add_inst( name=self.name + "_nmos",
mod=self.nmos, mod=self.nmos,
) )
print("bitmos", self.cell_inst.height, self.cell_inst.width)
if self.bit_value == 0: if self.bit_value == 0:
self.connect_inst(["bl", "wl", "bl", "gnd"]) self.connect_inst(["bl", "wl", "bl", "gnd"])
else: else:
@ -103,6 +105,8 @@ class rom_base_cell(design):
self.copy_layout_pin(self.cell_inst, "S", "S") self.copy_layout_pin(self.cell_inst, "S", "S")
self.copy_layout_pin(self.cell_inst, "D", "D") self.copy_layout_pin(self.cell_inst, "D", "D")
self.copy_layout_pin(self.cell_inst, "G", "G")
self.source_pos = self.cell_inst.get_pin("S").center() self.source_pos = self.cell_inst.get_pin("S").center()
def place_poly(self): def place_poly(self):

View File

@ -36,7 +36,7 @@ class rom_poly_tap(design):
self.place_via() self.place_via()
self.add_boundary() self.add_boundary()
self.extend_poly() # self.extend_poly()
if self.add_tap or self.place_poly: if self.add_tap or self.place_poly:
self.place_active_tap() self.place_active_tap()

View File

@ -17,9 +17,10 @@ class rom_precharge_array(design):
""" """
An array of inverters to create the inverted address lines for the rom decoder An array of inverters to create the inverted address lines for the rom decoder
""" """
def __init__(self, cols, name="", bitline_layer=None, strap_spacing=None, strap_layer="m2", tap_direction="row"): def __init__(self, cols, name="", bitline_layer="m2", strap_spacing=None, strap_layer="m3", tap_direction="row"):
self.cols = cols self.cols = cols
self.strap_layer = strap_layer self.strap_layer = strap_layer
self.bitline_layer = bitline_layer
self.tap_direction = tap_direction self.tap_direction = tap_direction
if "li" in layer: if "li" in layer:
@ -27,14 +28,6 @@ class rom_precharge_array(design):
else: else:
self.supply_layer = "m1" self.supply_layer = "m1"
if bitline_layer is not None:
self.bitline_layer = bitline_layer
else:
self.bitline_layer = self.supply_layer
if name=="":
name = "rom_inv_array_{0}".format(cols)
if strap_spacing != None: if strap_spacing != None:
self.strap_spacing = strap_spacing self.strap_spacing = strap_spacing
@ -128,7 +121,7 @@ class rom_precharge_array(design):
for col in range(self.cols): for col in range(self.cols):
if col % self.strap_spacing == 0: if col % self.strap_spacing == 0:
self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
strap_num += 1 strap_num += 1
if self.tap_direction == "col": if self.tap_direction == "col":
@ -137,7 +130,7 @@ class rom_precharge_array(design):
self.pmos_insts[col].place(vector(cell_x, cell_y)) self.pmos_insts[col].place(vector(cell_x, cell_y))
cell_x += self.pmos.width cell_x += self.pmos.width
self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) self.tap_insts[strap_num].place(vector(cell_x + self.poly_space, cell_y + self.poly_tap.height))
def create_layout_pins(self): def create_layout_pins(self):
self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate") self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate")
@ -158,11 +151,12 @@ class rom_precharge_array(design):
for tap in self.tap_insts: for tap in self.tap_insts:
tap_pin = tap.get_pin("poly_tap") tap_pin = tap.get_pin("poly_tap")
start = vector(tap_pin.cx(), tap_pin.by()) start = vector(tap_pin.cx(), tap_pin.by())
end = vector(start.x, tap.mod.get_pin("poly_tap").cy()) end = vector(start.x, self.pmos_insts[0].get_pin("G").cy())
self.add_segment_center(layer="poly", start=start, end=end) self.add_segment_center(layer="poly", start=start, end=end)
offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y) offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y)
offset_end = end + vector(0.5*self.poly_width, 0) offset_end = end + vector(0.5*self.poly_width, 0)
self.add_segment_center(layer="poly", start=offset_start, end=offset_end) self.add_segment_center(layer="poly", start=offset_start, end=offset_end)
self.add_segment_center(layer="poly", start=self.pmos_insts[-1].get_pin("G").center(), end=offset_end)
def extend_well(self): def extend_well(self):
self.well_offset = self.pmos.tap_offset self.well_offset = self.pmos.tap_offset

View File

@ -24,6 +24,8 @@ class rom_precharge_cell(rom_base_cell):
self.place_tap() self.place_tap()
self.extend_well() self.extend_well()
print("precharge", self.height, self.width)
def add_modules(self): def add_modules(self):
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
@ -42,6 +44,7 @@ class rom_precharge_cell(rom_base_cell):
self.cell_inst = self.add_inst( name="precharge_pmos", self.cell_inst = self.add_inst( name="precharge_pmos",
mod=self.pmos, mod=self.pmos,
) )
print("premos", self.cell_inst.height, self.cell_inst.width)
self.connect_inst(["bitline", "gate", "vdd", "vdd"]) self.connect_inst(["bitline", "gate", "vdd", "vdd"])
def add_pins(self): def add_pins(self):
@ -55,10 +58,10 @@ class rom_precharge_cell(rom_base_cell):
self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active)
def extend_well(self): def extend_well(self):
print(self.nwell_enclose_active)
well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width well_y = self.get_pin("vdd").cy() - 0.5 * self.tap.height - self.nwell_enclose_active
well_ll = vector(0, well_y) well_ll = vector(0, well_y)
height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y height = self.get_pin("D").cy() + self.nwell_enclose_active - well_y
self.add_rect("nwell", well_ll, self.width , height) self.add_rect("nwell", well_ll, self.width , height)
def place_tap(self): def place_tap(self):
@ -67,7 +70,7 @@ class rom_precharge_cell(rom_base_cell):
self.tap_offset = abs(tap_y) self.tap_offset = abs(tap_y)
pos = vector(source.cx(), tap_y ) pos = vector(source.cx(), tap_y )
self.add_via_center(layers=self.active_stack, self.tap = self.add_via_center(layers=self.active_stack,
offset=pos, offset=pos,
implant_type="n", implant_type="n",
well_type="n", well_type="n",

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2023 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import sys, os
import unittest
from testutils import *
import openram
from openram import debug
from openram.sram_factory import factory
from openram import OPTS
class precharge_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
# check precharge in single port
debug.info(2, "Testing rom precharge bitcell")
tx = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", bitline_layer="m2", supply_layer="m1")
self.local_check(tx)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -22,7 +22,7 @@ os.environ["MGC_TMPDIR"] = "/tmp"
# OpenPDK needed for magicrc, tech file and spice models of transistors # OpenPDK needed for magicrc, tech file and spice models of transistors
if 'PDK_ROOT' in os.environ: if 'PDK_ROOT' in os.environ:
open_pdks = os.path.join(os.environ['PDK_ROOT'], 'gf180mcuA', 'libs.tech') open_pdks = os.path.join(os.environ['PDK_ROOT'], 'gf180mcuD', 'libs.tech')
else: else:
raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.") raise SystemError("Unable to find open_pdks tech file. Set PDK_ROOT.")
@ -34,7 +34,7 @@ if not os.path.exists(gf180_lib_ngspice):
os.environ["SPICE_MODEL_DIR"] = spice_model_dir os.environ["SPICE_MODEL_DIR"] = spice_model_dir
open_pdks = os.path.abspath(open_pdks) open_pdks = os.path.abspath(open_pdks)
gf180_magicrc = os.path.join(open_pdks, 'magic', "gf180mcuA.magicrc") gf180_magicrc = os.path.join(open_pdks, 'magic', "gf180mcuD.magicrc")
if not os.path.exists(gf180_magicrc): if not os.path.exists(gf180_magicrc):
raise SystemError("Did not find {} under {}".format(gf180_magicrc, open_pdks)) raise SystemError("Did not find {} under {}".format(gf180_magicrc, open_pdks))
os.environ["OPENRAM_MAGICRC"] = gf180_magicrc os.environ["OPENRAM_MAGICRC"] = gf180_magicrc

View File

@ -189,8 +189,13 @@ drc = d.design_rules("gf180")
# grid size # grid size
drc["grid"] = 0.005 drc["grid"] = 0.005
drc["minwidth_tx"] = 0.28 # minwidth_tx with contact (no dog bone transistors)
#drc["minlength_channel"] = 0.150 drc["minwidth_tx"] = 0.5
# PL.2 Min gate width/channel length for 6V pmos (0.7 for 6V nmos)
drc["minlength_channel"] = 0.7
drc["minlength_channel_pmos"] = 0.55
drc["minlength_channel_nmos"] = 0.7
drc["pwell_to_nwell"] = 0 # assuming same potential drc["pwell_to_nwell"] = 0 # assuming same potential
@ -199,11 +204,13 @@ drc.add_layer("nwell",
spacing=0.6) spacing=0.6)
drc.add_layer("pwell", drc.add_layer("pwell",
width=0.74, # 0.6 for 1.5v width=0.74, # 0.6 for 3.3v
spacing=0.86) # equal potential 1.7 otherwise spacing=0.86) # equal potential
# PL.1 minwidth of interconnect poly 5/6V
# PL.3a poly spacing 5/6V
drc.add_layer("poly", drc.add_layer("poly",
width=0.18, width=0.2,
spacing=0.24) spacing=0.24)
drc["poly_extend_active"] = 0.22 drc["poly_extend_active"] = 0.22
@ -216,9 +223,14 @@ drc["poly_to_active"] = 0.1
#drc["poly_to_field_poly"] = 0.210 #drc["poly_to_field_poly"] = 0.210
#
# DF.1a - minwidth of active (5/6V)
# DF.3a - minspacing of active of the same type (5/6V)
# DF.9 - minarea of active area=0.2025 (5/6V)
drc.add_layer("active", drc.add_layer("active",
width=0.22, width=0.3,
spacing=0.280) spacing=0.36,
area=0.2025)
drc.add_enclosure("dnwell", drc.add_enclosure("dnwell",
layer="pwell", layer="pwell",
@ -250,22 +262,27 @@ drc.add_layer("implant",
drc.add_layer("contact", drc.add_layer("contact",
width=0.22, width=0.22,
spacing=0.25) spacing=0.25)
# CO.4 - active enclosure of contact
# extension is not a true drc rule, used to extend active to reach active min area
drc.add_enclosure("active", drc.add_enclosure("active",
layer="contact", layer="contact",
enclosure=0.01, enclosure=0.07,
extension=0.01) extension=0.07)
drc.add_enclosure("poly", drc.add_enclosure("poly",
layer="contact", layer="contact",
enclosure=0.07, enclosure=0.07,
extension=0.07) extension=0.07)
drc["active_contact_to_gate"] = 0.145 drc["active_contact_to_gate"] = 0.15
drc["poly_contact_to_gate"] = 0.165 drc["poly_contact_to_gate"] = 0.165
#drc["npc_enclose_poly"] = 0.1 #drc["npc_enclose_poly"] = 0.1
# M1.1 - width
# M1.2a - space
# M1.3 - area
drc.add_layer("m1", drc.add_layer("m1",
width=0.23, width=0.23,
spacing=0.23, spacing=0.23,