Merge branch 'dev' into lvs

This commit is contained in:
Jesse Cirimelli-Low 2021-12-22 15:46:09 -08:00
commit c24c37a15a
65 changed files with 3922 additions and 291 deletions

View File

@ -232,6 +232,7 @@ class layout():
# Check that the instance name is unique
debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.cell_name, name))
self.mods.add(mod)
self.inst_names.add(name)
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
debug.info(3, "adding instance {}".format(self.insts[-1]))
@ -638,7 +639,6 @@ class layout():
directions=directions,
implant_type=implant_type,
well_type=well_type)
self.add_mod(via)
inst = self.add_inst(name=via.name,
mod=via,
offset=offset)
@ -664,7 +664,6 @@ class layout():
corrected_offset = offset + vector(-0.5 * width,
-0.5 * height)
self.add_mod(via)
inst = self.add_inst(name=via.name,
mod=via,
offset=corrected_offset)
@ -756,7 +755,6 @@ class layout():
mos = ptx.ptx(width=width,
mults=mults,
tx_type=tx_type)
self.add_mod(mos)
inst = self.add_inst(name=mos.name,
mod=mos,
offset=offset,

View File

@ -45,10 +45,10 @@ class spice():
self.lvs_file = lvs_dir + cell_name + ".sp"
else:
self.lvs_file = self.sp_file
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
# Holds subckts/mods for this module
self.mods = []
self.mods = set()
# Holds the pins for this module (in order)
self.pins = []
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
@ -128,7 +128,7 @@ class spice():
new_list = [input_list[x] for x in self.pin_indices]
return new_list
def add_pin_types(self, type_list):
"""
Add pin types for all the cell's pins.
@ -140,7 +140,7 @@ class spice():
\n Module names={}\
".format(self.name, self.pins, type_list), 1)
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
def get_pin_type(self, name):
""" Returns the type of the signal pin. """
pin_type = self.pin_type[name]
@ -187,10 +187,6 @@ class spice():
inout_list.append(pin)
return inout_list
def add_mod(self, mod):
"""Adds a subckt/submodule to the subckt hierarchy"""
self.mods.append(mod)
def connect_inst(self, args, check=True):
"""
Connects the pins of the last instance added
@ -199,13 +195,13 @@ class spice():
where we dynamically generate groups of connections after a
group of modules are generated.
"""
num_pins = len(self.insts[-1].mod.pins)
num_args = len(args)
# Order the arguments if the hard cell has a custom port order
ordered_args = self.get_ordered_inputs(args)
if (check and num_pins != num_args):
if num_pins < num_args:
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
@ -372,15 +368,15 @@ class spice():
# these are wires and paths
if self.conns[i] == []:
continue
# Instance with no devices in it needs no subckt/instance
if self.insts[i].mod.no_instances:
continue
# If this is a trimmed netlist, skip it by adding comment char
if trim and self.insts[i].name in self.trim_insts:
sp.write("* ")
if lvs and hasattr(self.insts[i].mod, "lvs_device"):
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
" ".join(self.conns[i])))

View File

@ -56,7 +56,6 @@ class dummy_pbitcell(design.design):
def add_modules(self):
self.prbc = factory.create(module_type="pbitcell",
dummy_bitcell=True)
self.add_mod(self.prbc)
self.height = self.prbc.height
self.width = self.prbc.width

View File

@ -179,26 +179,21 @@ class pbitcell(bitcell_base.bitcell_base):
# create ptx for inverter transistors
self.inverter_nmos = ptx(width=inverter_nmos_width,
tx_type="nmos")
self.add_mod(self.inverter_nmos)
self.inverter_pmos = ptx(width=inverter_pmos_width,
tx_type="pmos")
self.add_mod(self.inverter_pmos)
# create ptx for readwrite transitors
self.readwrite_nmos = ptx(width=readwrite_nmos_width,
tx_type="nmos")
self.add_mod(self.readwrite_nmos)
# create ptx for write transitors
self.write_nmos = ptx(width=write_nmos_width,
tx_type="nmos")
self.add_mod(self.write_nmos)
# create ptx for read transistors
self.read_nmos = ptx(width=read_nmos_width,
tx_type="nmos")
self.add_mod(self.read_nmos)
def calculate_spacing(self):
""" Calculate transistor spacings """
@ -425,7 +420,6 @@ class pbitcell(bitcell_base.bitcell_base):
width=self.width)
self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H"))
vdd_ypos = self.inverter_nmos_ypos \
+ self.inverter_nmos.active_height \
+ self.inverter_gap \
@ -475,6 +469,7 @@ class pbitcell(bitcell_base.bitcell_base):
self.connect_inst([self.Q_bar,
self.rw_wl_names[k], br_name, "gnd"])
def place_readwrite_ports(self):
""" Places read/write ports in the bit cell """
# define read/write transistor variables as empty arrays
@ -529,6 +524,21 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.rwbr_positions[k],
height=self.height)
if self.dummy_bitcell:
bl_name = self.rw_bl_names[k]
br_name = self.rw_br_names[k]
bl_name += "_noconn"
br_name += "_noconn"
# This helps with LVS matching in klayout
drain_pin = self.readwrite_nmos_left[k].get_pin("S")
self.add_label(bl_name, drain_pin.layer, drain_pin.center())
# This helps with LVS matching in klayout
source_pin = self.readwrite_nmos_right[k].get_pin("D")
self.add_label(br_name, source_pin.layer, source_pin.center())
# update furthest left and right transistor edges
self.left_building_edge = left_readwrite_transistor_xpos
self.right_building_edge = right_readwrite_transistor_xpos \
@ -626,6 +636,20 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.wbr_positions[k],
height=self.height)
if self.dummy_bitcell:
bl_name = self.w_bl_names[k]
br_name = self.w_br_names[k]
bl_name += "_noconn"
br_name += "_noconn"
# This helps with LVS matching in klayout
drain_pin = self.write_nmos_left[k].get_pin("S")
self.add_label(bl_name, drain_pin.layer, drain_pin.center())
# This helps with LVS matching in klayout
source_pin = self.write_nmos_right[k].get_pin("D")
self.add_label(br_name, source_pin.layer, source_pin.center())
# update furthest left and right transistor edges
self.left_building_edge = left_write_transistor_xpos
self.right_building_edge = right_write_transistor_xpos \
@ -753,6 +777,20 @@ class pbitcell(bitcell_base.bitcell_base):
offset=self.rbr_positions[k],
height=self.height)
if self.dummy_bitcell:
bl_name = self.r_bl_names[k]
br_name = self.r_br_names[k]
bl_name += "_noconn"
br_name += "_noconn"
# This helps with LVS matching in klayout
drain_pin = self.read_access_nmos_left[k].get_pin("S")
self.add_label(bl_name, drain_pin.layer, drain_pin.center())
# This helps with LVS matching in klayout
source_pin = self.read_access_nmos_right[k].get_pin("D")
self.add_label(br_name, source_pin.layer, source_pin.center())
def route_wordlines(self):
""" Routes gate of transistors to their respective wordlines """
port_transistors = []
@ -1013,7 +1051,7 @@ class pbitcell(bitcell_base.bitcell_base):
well_height = max_nmos_well_height + self.port_ypos \
- self.nwell_enclose_active - self.gnd_position.y
# FIXME fudge factor xpos
well_width = self.width + 2*self.nwell_enclose_active
well_width = self.width + 2 * self.nwell_enclose_active
offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos)
self.add_rect(layer="pwell",
offset=offset,
@ -1163,7 +1201,7 @@ class pbitcell(bitcell_base.bitcell_base):
return
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
# Edges added wl->bl, wl->br for every port except write ports
rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names)
r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names)
@ -1172,4 +1210,3 @@ class pbitcell(bitcell_base.bitcell_base):
for wl, bl, br in pin_zip:
graph.add_edge(pin_dict[wl], pin_dict[bl], self)
graph.add_edge(pin_dict[wl], pin_dict[br], self)

View File

@ -58,7 +58,6 @@ class replica_pbitcell(design.design):
def add_modules(self):
self.prbc = factory.create(module_type="pbitcell",
replica_bitcell=True)
self.add_mod(self.prbc)
self.height = self.prbc.height
self.width = self.prbc.width
@ -88,4 +87,3 @@ class replica_pbitcell(design.design):
self.copy_layout_pin(self.prbc_inst, "wl{}".format(port))
self.copy_layout_pin(self.prbc_inst, "vdd")
self.copy_layout_pin(self.prbc_inst, "gnd")

View File

@ -43,9 +43,6 @@ class and2_dec(design.design):
height=self.height,
size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if "li" in layer:

View File

@ -41,9 +41,6 @@ class and3_dec(design.design):
height=self.height,
size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if "li" in layer:
self.route_layer = "li"

View File

@ -43,9 +43,6 @@ class and4_dec(design.design):
height=self.height,
size=self.size)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if "li" in layer:
self.route_layer = "li"
@ -129,4 +126,3 @@ class and4_dec(design.design):
offset=pin.center(),
width=pin.width(),
height=pin.height())

View File

@ -389,7 +389,6 @@ class bank(design.design):
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.port_address = []
for port in self.all_ports:
@ -397,7 +396,6 @@ class bank(design.design):
cols=self.num_cols + self.num_spare_cols,
rows=self.num_rows,
port=port))
self.add_mod(self.port_address[port])
self.port_data = []
self.bit_offsets = self.get_column_offsets()
@ -407,11 +405,9 @@ class bank(design.design):
port=port,
bit_offsets=self.bit_offsets)
self.port_data.append(temp_pre)
self.add_mod(self.port_data[port])
if(self.num_banks > 1):
self.bank_select = factory.create(module_type="bank_select")
self.add_mod(self.bank_select)
def create_bitcell_array(self):
""" Creating Bitcell Array """
@ -547,7 +543,6 @@ class bank(design.design):
else:
# No error checking before?
debug.error("Invalid column decoder?", -1)
self.add_mod(self.column_decoder)
self.column_decoder_inst = [None] * len(self.all_ports)
for port in self.all_ports:

View File

@ -78,20 +78,15 @@ class bank_select(design.design):
# 1x Inverter
self.inv_sel = factory.create(module_type="pinv", height=height)
self.add_mod(self.inv_sel)
# 4x Inverter
self.inv4x = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x)
self.nor2 = factory.create(module_type="pnor2", height=height)
self.add_mod(self.nor2)
self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4)
self.add_mod(self.inv4x_nor)
self.nand2 = factory.create(module_type="pnand2", height=height)
self.add_mod(self.nand2)
def calculate_module_offsets(self):

View File

@ -53,7 +53,6 @@ class bitcell_array(bitcell_base_array):
def add_modules(self):
""" Add the modules used in this design """
self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell)
def create_instances(self):
""" Create the module instances used in this design """
@ -64,11 +63,11 @@ class bitcell_array(bitcell_base_array):
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.cell)
self.connect_inst(self.get_bitcell_pins(row, col))
# If it is a "core" cell, it could be trimmed for sim time
if col>0 and col<self.column_size-1 and row>0 and row<self.row_size-1:
self.trim_insts.add(name)
def analytical_power(self, corner, load):
"""Power of Bitcell array and bitline in nW."""

View File

@ -42,14 +42,13 @@ class col_cap_array(bitcell_base_array):
self.height = self.dummy_cell.height
self.width = self.column_size * self.cell.width
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell)
def create_instances(self):
""" Create the module instances used in this design """
@ -101,4 +100,3 @@ class col_cap_array(bitcell_base_array):
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.copy_power_pin(pin)

View File

@ -87,7 +87,6 @@ class column_mux_array(design.design):
self.mux = factory.create(module_type="column_mux",
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
self.add_mod(self.mux)
self.cell = factory.create(module_type=OPTS.bitcell)
@ -177,13 +176,16 @@ class column_mux_array(design.design):
# height to connect the gate to the correct horizontal row
# sel_height = self.get_pin("sel_{}".format(sel_index)).by()
# use the y offset from the sel pin and the x offset from the gate
offset = vector(gate_offset.x,
self.get_pin("sel_{}".format(sel_index)).cy())
bl_offset = offset + vector((self.mux_inst[col].get_pin("br_out").bc().x - self.mux_inst[col].get_pin("bl_out").bc().x)/2, 0)
self.add_via_stack_center(from_layer="poly",
to_layer=self.sel_layer,
offset=offset,
offset=bl_offset,
directions=self.via_directions)
self.add_path("poly", [offset, gate_offset])
self.add_path("poly", [offset, gate_offset, bl_offset])
def route_bitlines(self):
""" Connect the output bit-lines to form the appropriate width mux """

View File

@ -91,17 +91,13 @@ class control_logic(design.design):
rows=self.num_control_signals,
columns=1)
self.add_mod(self.ctrl_dff_array)
self.and2 = factory.create(module_type="pand2",
size=12,
height=dff_height)
self.add_mod(self.and2)
self.rbl_driver = factory.create(module_type="pbuf",
size=self.num_cols,
height=dff_height)
self.add_mod(self.rbl_driver)
# clk_buf drives a flop for every address
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
@ -114,8 +110,6 @@ class control_logic(design.design):
fanout=clock_fanout,
height=dff_height)
self.add_mod(self.clk_buf_driver)
# We will use the maximum since this same value is used to size the wl_en
# and the p_en_bar drivers
# max_fanout = max(self.num_rows, self.num_cols)
@ -126,25 +120,21 @@ class control_logic(design.design):
self.wl_en_driver = factory.create(module_type="pdriver",
size_list=size_list,
height=dff_height)
self.add_mod(self.wl_en_driver)
# w_en drives every write driver
self.wen_and = factory.create(module_type="pand3",
size=self.word_size + 8,
height=dff_height)
self.add_mod(self.wen_and)
size=self.word_size + 8,
height=dff_height)
# s_en drives every sense amp
self.sen_and3 = factory.create(module_type="pand3",
size=self.word_size + self.num_spare_cols,
height=dff_height)
self.add_mod(self.sen_and3)
# used to generate inverted signals with low fanout
self.inv = factory.create(module_type="pinv",
size=1,
height=dff_height)
self.add_mod(self.inv)
# p_en_bar drives every column in the bitcell array
# but it is sized the same as the wl_en driver with
@ -152,17 +142,14 @@ class control_logic(design.design):
self.p_en_bar_driver = factory.create(module_type="pdriver",
fanout=self.num_cols,
height=dff_height)
self.add_mod(self.p_en_bar_driver)
self.nand2 = factory.create(module_type="pnand2",
height=dff_height)
self.add_mod(self.nand2)
debug.check(OPTS.delay_chain_stages % 2,
"Must use odd number of delay chain stages for inverting delay chain.")
self.delay_chain=factory.create(module_type="delay_chain",
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
self.add_mod(self.delay_chain)
def get_dynamic_delay_chain_size(self, previous_stages, previous_fanout):
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""

View File

@ -47,7 +47,7 @@ class delay_chain(design.design):
self.height = self.rows * self.inv.height
# The width is determined by the largest fanout plus the driver
self.width = (max(self.fanout_list) + 1) * self.inv.width
self.place_inverters()
self.route_inverters()
self.route_supplies()
@ -66,10 +66,9 @@ class delay_chain(design.design):
self.dff = factory.create(module_type="dff_buf")
dff_height = self.dff.height
self.inv = factory.create(module_type="pinv",
height=dff_height)
self.add_mod(self.inv)
def create_inverters(self):
""" Create the inverters and connect them based on the stage list """
@ -199,7 +198,7 @@ class delay_chain(design.design):
to_layer="m2",
offset=mid_loc)
self.add_path(a_pin.layer, [a_pin.center(), mid_loc])
self.add_layout_pin_rect_center(text="in",
layer="m2",
offset=mid_loc)
@ -213,4 +212,3 @@ class delay_chain(design.design):
self.add_layout_pin_rect_center(text="out",
layer="m1",
offset=a_pin.center())

View File

@ -48,7 +48,6 @@ class dff_array(design.design):
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self):
for row in range(self.rows):

View File

@ -58,17 +58,14 @@ class dff_buf(design.design):
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
self.inv1 = factory.create(module_type="pinv",
size=self.inv1_size,
height=self.dff.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv",
size=self.inv2_size,
height=self.dff.height)
self.add_mod(self.inv2)
def add_pins(self):
self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"],
@ -110,7 +107,7 @@ class dff_buf(design.design):
pass
well_spacing += 2 * self.well_extend_active
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing, 0))
# Add INV2 to the right

View File

@ -68,7 +68,6 @@ class dff_buf_array(design.design):
self.dff = factory.create(module_type="dff_buf",
inv1_size=self.inv1_size,
inv2_size=self.inv2_size)
self.add_mod(self.dff)
def create_dff_array(self):
self.dff_insts={}

View File

@ -7,11 +7,10 @@
#
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
from sram_factory import factory
class dff_inv(design.design):
"""
@ -66,12 +65,10 @@ class dff_inv(design.design):
def add_modules(self):
self.dff = dff_inv.dff_inv(self.inv_size)
self.add_mod(self.dff)
self.inv1 = factory.create(module_type="pinv",
size=self.inv_size,
height=self.dff.height)
self.add_mod(self.inv1)
def create_modules(self):
self.dff_inst=self.add_inst(name="dff_inv_dff",

View File

@ -53,7 +53,6 @@ class dff_inv_array(design.design):
def add_modules(self):
self.dff = factory.create(module_type="dff")
self.add_mod(self.dff)
def add_pins(self):
for row in range(self.rows):

View File

@ -45,7 +45,6 @@ class dummy_array(bitcell_base_array):
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.dummy_cell)
def create_instances(self):
""" Create the module instances used in this design """

View File

@ -64,7 +64,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
rbl=self.rbl,
left_rbl=[0],
right_rbl=[1] if len(self.all_ports) > 1 else [])
self.add_mod(la)
self.local_mods.append(la)
return
@ -90,7 +89,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
cols=cols,
rbl=self.rbl)
self.add_mod(la)
self.local_mods.append(la)
def add_pins(self):
@ -344,4 +342,3 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
"""Exclude dffs from graph as they do not represent critical path"""
self.graph_inst_exclude.add(self.ctrl_dff_inst)

View File

@ -69,14 +69,11 @@ class hierarchical_decoder(design.design):
def add_modules(self):
self.and2 = factory.create(module_type="and2_dec",
height=self.cell_height)
self.add_mod(self.and2)
self.and3 = factory.create(module_type="and3_dec",
height=self.cell_height)
self.add_mod(self.and3)
# TBD
# self.and4 = factory.create(module_type="and4_dec")
# self.add_mod(self.and4)
self.add_decoders()
@ -84,15 +81,12 @@ class hierarchical_decoder(design.design):
""" Create the decoders based on the number of pre-decodes """
self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
height=self.cell_height)
self.add_mod(self.pre2_4)
self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
height=self.cell_height)
self.add_mod(self.pre3_8)
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
height=self.cell_height)
self.add_mod(self.pre4_16)
def determine_predecodes(self, num_inputs):
"""

View File

@ -31,7 +31,7 @@ class hierarchical_predecode(design.design):
self.cell_height = b.height
else:
self.cell_height = height
self.column_decoder = column_decoder
self.input_and_rail_pos = []
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
@ -59,13 +59,11 @@ class hierarchical_predecode(design.design):
inv_type = "inv_dec"
self.and_mod = factory.create(module_type=and_type,
height=self.cell_height)
self.add_mod(self.and_mod)
# This uses the pinv_dec parameterized cell
self.inv = factory.create(module_type=inv_type,
height=self.cell_height,
size=1)
self.add_mod(self.inv)
def create_layout(self):
""" The general organization is from left to right:
@ -189,13 +187,13 @@ class hierarchical_predecode(design.design):
self.route_input_inverters()
self.route_input_ands()
self.route_output_inverters()
self.route_inputs_to_rails()
self.route_inputs_to_rails()
self.route_output_ands()
self.route_vdd_gnd()
def route_inputs_to_rails(self):
""" Route the uninverted inputs to the second set of rails """
top_and_gate = self.and_inst[-1]
for num in range(self.number_of_inputs):
if num == 0:
@ -221,7 +219,7 @@ class hierarchical_predecode(design.design):
to_layer=self.bus_layer,
offset=[self.input_rails[in_pin].cx(), y_offset],
directions= ("H", "H"))
self.add_via_stack_center(from_layer=self.input_layer,
to_layer=self.bus_layer,
offset=[self.decode_rails[a_pin].cx(), y_offset],
@ -306,7 +304,7 @@ class hierarchical_predecode(design.design):
else: # grow the stack down
search_id = 2
next_id = 0
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
via = factory.create(module_type="contact",
@ -343,7 +341,7 @@ class hierarchical_predecode(design.design):
"""
Route the different permutations of the NAND/AND decocer cells.
"""
# This 2D array defines the connection mapping
and_input_line_combination = self.get_and_input_line_combination()
for k in range(self.number_of_outputs):
@ -419,6 +417,3 @@ class hierarchical_predecode(design.design):
self.and_inst[0].lx() - self.bus_space]:
pin_pos = vector(xoffset, and_pin.cy())
self.copy_power_pin(and_pin, loc=pin_pos)

View File

@ -73,12 +73,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
rbl=self.rbl,
left_rbl=self.left_rbl,
right_rbl=self.right_rbl)
self.add_mod(self.bitcell_array)
self.wl_array = factory.create(module_type="wordline_buffer_array",
rows=self.rows + 1,
cols=self.cols)
self.add_mod(self.wl_array)
def add_pins(self):
# Outputs from the wordline driver (by port)

View File

@ -172,47 +172,36 @@ class multibank(design.design):
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
rows=self.num_rows)
self.add_mod(self.bitcell_array)
self.precharge_array = self.mod_precharge_array(columns=self.num_cols)
self.add_mod(self.precharge_array)
if self.col_addr_size > 0:
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.column_mux_array)
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
words_per_row=self.words_per_row)
self.add_mod(self.sense_amp_array)
if self.write_size:
self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_mask_driver_array)
else:
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.write_driver_array)
self.row_decoder = self.mod_decoder(rows=self.num_rows)
self.add_mod(self.row_decoder)
self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
word_size=self.word_size)
self.add_mod(self.tri_gate_array)
self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows)
self.add_mod(self.wordline_driver)
self.inv = pinv()
self.add_mod(self.inv)
if(self.num_banks > 1):
self.bank_select = self.mod_bank_select()
self.add_mod(self.bank_select)
def add_bitcell_array(self):

View File

@ -47,7 +47,6 @@ class bitcell_array(bitcell_base_array):
def add_modules(self):
""" Add the modules used in this design """
self.cell = factory.create(module_type=OPTS.bitcell)
self.add_mod(self.cell)
def create_instances(self):
""" Create the module instances used in this design """

View File

@ -145,12 +145,10 @@ class port_address(design.design):
self.row_decoder = factory.create(module_type="decoder",
num_outputs=self.num_rows)
self.add_mod(self.row_decoder)
self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
rows=self.num_rows,
cols=self.num_cols)
self.add_mod(self.wordline_driver_array)
local_array_size = OPTS.local_array_size
if local_array_size > 0:
@ -174,8 +172,6 @@ class port_address(design.design):
size=driver_size,
height=b.height)
self.add_mod(self.rbl_driver)
def create_row_decoder(self):
""" Create the hierarchical row decoder """
@ -235,7 +231,7 @@ class port_address(design.design):
# The wordline driver also had an extra gap on the right, so use this offset
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width
if self.port == 0:
rbl_driver_offset = vector(x_offset,
0)

View File

@ -29,7 +29,7 @@ class port_data(design.design):
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
else:
self.num_wmasks = 0
if num_spare_cols is not None:
self.num_spare_cols = num_spare_cols + self.num_spare_cols
if self.num_spare_cols is None:
@ -215,7 +215,6 @@ class port_data(design.design):
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port],
column_offset=self.port - 1)
self.add_mod(self.precharge_array)
if self.port in self.read_ports:
# RBLs don't get a sense amp
@ -224,7 +223,6 @@ class port_data(design.design):
offsets=self.bit_offsets,
words_per_row=self.words_per_row,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.sense_amp_array)
else:
self.sense_amp_array = None
@ -236,7 +234,6 @@ class port_data(design.design):
offsets=self.bit_offsets,
bitcell_bl=self.bl_names[self.port],
bitcell_br=self.br_names[self.port])
self.add_mod(self.column_mux_array)
else:
self.column_mux_array = None
@ -248,7 +245,6 @@ class port_data(design.design):
offsets=self.bit_offsets,
write_size=self.write_size,
num_spare_cols=self.num_spare_cols)
self.add_mod(self.write_driver_array)
if self.write_size is not None:
# RBLs don't get a write mask
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
@ -256,7 +252,6 @@ class port_data(design.design):
offsets=self.bit_offsets,
word_size=self.word_size,
write_size=self.write_size)
self.add_mod(self.write_mask_and_array)
else:
self.write_mask_and_array = None
@ -858,10 +853,10 @@ class port_data(design.design):
"""
if self.column_mux_array:
self.column_mux_array.graph_exclude_columns(column_include_num)
def graph_clear_column_mux(self):
"""
Clear mux exclusions to allow different bit tests.
"""
if self.column_mux_array:
self.column_mux_array.init_graph_params()
self.column_mux_array.init_graph_params()

View File

@ -76,8 +76,7 @@ class precharge_array(design.design):
size=self.size,
bitcell_bl=self.bitcell_bl,
bitcell_br=self.bitcell_br)
self.add_mod(self.pc_cell)
self.cell = factory.create(module_type=OPTS.bitcell)
def add_layout_pins(self):
@ -130,5 +129,3 @@ class precharge_array(design.design):
offset = vector(tempx, 0)
self.local_insts[i].place(offset=offset, mirror=mirror)

View File

@ -110,7 +110,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=1 + len(self.left_rbl),
cols=self.column_size,
rows=self.row_size)
self.add_mod(self.bitcell_array)
# Replica bitlines
self.replica_columns = {}
@ -138,7 +137,6 @@ class replica_bitcell_array(bitcell_base_array):
rbl=self.rbl,
column_offset=column_offset,
replica_bit=replica_bit)
self.add_mod(self.replica_columns[port])
# Dummy row
self.dummy_row = factory.create(module_type="dummy_array",
@ -147,7 +145,6 @@ class replica_bitcell_array(bitcell_base_array):
# dummy column + left replica column
column_offset=1 + len(self.left_rbl),
mirror=0)
self.add_mod(self.dummy_row)
# Dummy Row or Col Cap, depending on bitcell array properties
col_cap_module_type = ("col_cap_array" if self.cell.end_caps else "dummy_array")
@ -158,7 +155,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=1 + len(self.left_rbl),
mirror=0,
location="top")
self.add_mod(self.col_cap_top)
self.col_cap_bottom = factory.create(module_type=col_cap_module_type,
cols=self.column_size,
@ -167,7 +163,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=1 + len(self.left_rbl),
mirror=0,
location="bottom")
self.add_mod(self.col_cap_bottom)
# Dummy Col or Row Cap, depending on bitcell array properties
row_cap_module_type = ("row_cap_array" if self.cell.end_caps else "dummy_array")
@ -177,7 +172,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=0,
rows=self.row_size + self.extra_rows,
mirror=(self.rbl[0] + 1) % 2)
self.add_mod(self.row_cap_left)
self.row_cap_right = factory.create(module_type=row_cap_module_type,
cols=1,
@ -188,7 +182,6 @@ class replica_bitcell_array(bitcell_base_array):
column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0],
rows=self.row_size + self.extra_rows,
mirror=(self.rbl[0] + 1) %2)
self.add_mod(self.row_cap_right)
def add_pins(self):
@ -401,7 +394,7 @@ class replica_bitcell_array(bitcell_base_array):
dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul()
self.dummy_row_insts[1].place(offset=dummy_row_offset,
mirror="MX" if flip_dummy else "R0")
# Far bottom dummy row (first row below array IS flipped)
flip_dummy = (self.rbl[0] + 1) % 2
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
@ -411,7 +404,7 @@ class replica_bitcell_array(bitcell_base_array):
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset
self.dummy_col_insts[0].place(offset=dummy_col_offset)
# Far right dummy col
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array
dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr()
@ -430,7 +423,7 @@ class replica_bitcell_array(bitcell_base_array):
offset=pin.ll().scale(0, 1),
width=self.width,
height=pin.height())
# Replica wordlines (go by the row instead of replica column because we may have to add a pin
# even though the column is in another local bitcell array)
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):

View File

@ -37,7 +37,7 @@ class replica_column(bitcell_base_array):
self.left_rbl = rbl[0]
self.right_rbl = rbl[1]
self.replica_bit = replica_bit
# Total size includes the replica rows and column cap rows
self.total_size = self.left_rbl + rows + self.right_rbl + 2
@ -63,7 +63,7 @@ class replica_column(bitcell_base_array):
def create_layout(self):
self.place_instances()
self.height = self.cell_inst[-1].uy()
self.width = self.cell_inst[0].rx()
@ -85,15 +85,14 @@ class replica_column(bitcell_base_array):
def add_modules(self):
self.replica_cell = factory.create(module_type=OPTS.replica_bitcell)
self.add_mod(self.replica_cell)
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
self.add_mod(self.dummy_cell)
try:
edge_module_type = ("col_cap" if self.cell.end_caps else "dummy")
except AttributeError:
edge_module_type = "dummy"
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
self.add_mod(self.edge_cell)
def create_instances(self):
self.cell_inst = []
@ -103,7 +102,7 @@ class replica_column(bitcell_base_array):
real_row = row
if self.cell.end_caps:
real_row -= 1
# Regular array cells are replica cells
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
if (row == 0 or row == self.total_size - 1):
@ -238,4 +237,3 @@ class replica_column(bitcell_base_array):
for row, cell in enumerate(self.cell_inst):
if row != self.replica_bit:
self.graph_inst_exclude.add(cell)

View File

@ -37,14 +37,13 @@ class row_cap_array(bitcell_base_array):
self.width = max([x.rx() for x in self.insts])
self.height = max([x.uy() for x in self.insts])
self.add_boundary()
self.DRC_LVS()
def add_modules(self):
""" Add the modules used in this design """
self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.add_mod(self.dummy_cell)
self.cell = factory.create(module_type=OPTS.bitcell)
@ -114,4 +113,3 @@ class row_cap_array(bitcell_base_array):
for pin_name in ["vdd", "gnd"]:
for pin in inst.get_pins(pin_name):
self.copy_power_pin(pin)

View File

@ -91,7 +91,6 @@ class sense_amp_array(design.design):
def add_modules(self):
self.amp = factory.create(module_type="sense_amp")
self.add_mod(self.amp)
# This is just used for measurements,
# so don't add the module

View File

@ -46,7 +46,6 @@ class tri_gate_array(design.design):
def add_modules(self):
self.tri = factory.create(module_type="tri_gate")
self.add_mod(self.tri)
def add_pins(self):
"""create the name of pins depend on the word size"""
@ -120,4 +119,4 @@ class tri_gate_array(design.design):
layer="m1",
offset=enbar_pin.ll().scale(0, 1),
width=width,
height=drc("minwidth_m1"))
height=drc("minwidth_m1"))

View File

@ -64,7 +64,6 @@ class wordline_buffer_array(design.design):
self.wl_driver = factory.create(module_type="inv_dec",
size=self.cols,
height=b.height)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):
"""

View File

@ -65,8 +65,6 @@ class wordline_driver_array(design.design):
self.wl_driver = factory.create(module_type="wordline_driver",
cols=self.cols)
self.add_mod(self.wl_driver)
def route_vdd_gnd(self):
"""
Add a pin for each row of vdd/gnd which

View File

@ -94,7 +94,6 @@ class write_driver_array(design.design):
def add_modules(self):
self.driver = factory.create(module_type="write_driver")
self.add_mod(self.driver)
# This is just used for measurements,
# so don't add the module
@ -259,4 +258,3 @@ class write_driver_array(design.design):
layer="m1",
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
width=self.width)

View File

@ -63,7 +63,6 @@ class write_mask_and_array(design.design):
# Assume stage effort of 3 to compute the size
self.and2 = factory.create(module_type="pand2",
size=max(self.write_size / 4.0, 1))
self.add_mod(self.and2)
def create_and2_array(self):
self.and2_insts = {}
@ -146,7 +145,7 @@ class write_mask_and_array(design.design):
self.add_via_stack_center(from_layer=supply_pin.layer,
to_layer="m1",
offset=supply_pin.center())
for supply in ["gnd", "vdd"]:
supply_pin = self.and2_insts[0].get_pin(supply)
supply_pin_yoffset = supply_pin.cy()
@ -158,4 +157,3 @@ class write_mask_and_array(design.design):
to_layer="m1",
offset=loc)
self.copy_power_pin(supply_pin, loc=loc)

View File

@ -77,7 +77,6 @@ class column_mux(pgate.pgate):
self.ptx_width = self.tx_size * drc("minwidth_tx")
self.nmos = factory.create(module_type="ptx",
width=self.ptx_width)
self.add_mod(self.nmos)
# Space it in the center
self.nmos_lower = self.add_inst(name="mux_tx1",

View File

@ -39,9 +39,6 @@ class pand2(pgate.pgate):
height=self.height,
add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if self.vertical:
self.height = 2 * self.nand.height
@ -146,8 +143,8 @@ class pand2(pgate.pgate):
offset=pin.center(),
width=pin.width(),
height=pin.height())
def is_non_inverting(self):
"""Return input to output polarity for module"""
return True
return True

View File

@ -43,9 +43,6 @@ class pand3(pgate.pgate):
height=self.height,
add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if self.vertical:
self.height = 2 * self.nand.height

View File

@ -43,9 +43,6 @@ class pand4(pgate.pgate):
height=self.height,
add_wells=self.add_wells)
self.add_mod(self.nand)
self.add_mod(self.inv)
def create_layout(self):
if self.vertical:
self.height = 2 * self.nand.height
@ -162,4 +159,3 @@ class pand4(pgate.pgate):
slew=nand_delay.slew,
load=load)
return nand_delay + inv_delay

View File

@ -52,13 +52,11 @@ class pbuf(pgate.pgate):
self.inv1 = factory.create(module_type="pinv",
size=input_size,
height=self.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv",
size=self.size,
height=self.height,
add_wells=False)
self.add_mod(self.inv2)
def create_insts(self):
self.inv1_inst = self.add_inst(name="buf_inv1",
@ -96,4 +94,3 @@ class pbuf(pgate.pgate):
offset=a_pin.center(),
width=a_pin.width(),
height=a_pin.height())

View File

@ -52,12 +52,10 @@ class pbuf_dec(pgate.pgate):
self.inv1 = factory.create(module_type="pinv_dec",
size=input_size,
height=self.height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv_dec",
size=self.size,
height=self.height)
self.add_mod(self.inv2)
def create_insts(self):
self.inv1_inst = self.add_inst(name="buf_inv1",

View File

@ -93,7 +93,6 @@ class pdriver(pgate.pgate):
height=self.height,
add_wells=self.add_wells)
self.inv_list.append(temp_inv)
self.add_mod(temp_inv)
def create_insts(self):
self.inv_inst_list = []

View File

@ -207,7 +207,6 @@ class pinv(pgate.pgate):
add_drain_contact=self.route_layer,
connect_poly=True,
connect_drain_active=True)
self.add_mod(self.nmos)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
@ -217,7 +216,6 @@ class pinv(pgate.pgate):
add_drain_contact=self.route_layer,
connect_poly=True,
connect_drain_active=True)
self.add_mod(self.pmos)
def create_ptx(self):
"""
@ -337,30 +335,29 @@ class pinv(pgate.pgate):
Overrides base class function.
"""
self.add_graph_edges(graph, port_nets)
def is_non_inverting(self):
"""Return input to output polarity for module"""
return False
return False
def get_on_resistance(self):
"""On resistance of pinv, defined by single nmos"""
is_nchannel = True
stack = 1
is_cell = False
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
def get_input_capacitance(self):
"""Input cap of input, passes width of gates to gate cap function"""
return self.gate_c(self.nmos_width+self.pmos_width)
return self.gate_c(self.nmos_width+self.pmos_width)
def get_intrinsic_capacitance(self):
"""Get the drain capacitances of the TXs in the gate."""
nmos_stack = 1
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_stack,
self.tx_mults)
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
1,
self.tx_mults)
return nmos_drain_c + pmos_drain_c
self.tx_mults)
return nmos_drain_c + pmos_drain_c

View File

@ -65,17 +65,14 @@ class pinvbuf(pgate.pgate):
self.inv = factory.create(module_type="pinv",
size=input_size,
height=self.row_height)
self.add_mod(self.inv)
self.inv1 = factory.create(module_type="pinv",
size=self.predriver_size,
height=self.row_height)
self.add_mod(self.inv1)
self.inv2 = factory.create(module_type="pinv",
size=self.size,
height=self.row_height)
self.add_mod(self.inv2)
def create_insts(self):
# Create INV1 (capacitance shield)

View File

@ -79,7 +79,6 @@ class pnand2(pgate.pgate):
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact="active")
self.add_mod(self.nmos_left)
self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width,
@ -87,7 +86,6 @@ class pnand2(pgate.pgate):
tx_type="nmos",
add_source_contact="active",
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width,
@ -95,7 +93,6 @@ class pnand2(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width,
@ -103,7 +100,6 @@ class pnand2(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """
@ -317,28 +313,26 @@ class pnand2(pgate.pgate):
def is_non_inverting(self):
"""Return input to output polarity for module"""
return False
def get_on_resistance(self):
"""On resistance of pnand, defined by stacked NMOS"""
is_nchannel = True
stack = 2
is_cell = False
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
def get_input_capacitance(self):
"""Input cap of input, passes width of gates to gate cap function"""
return self.gate_c(self.nmos_width+self.pmos_width)
return self.gate_c(self.nmos_width+self.pmos_width)
def get_intrinsic_capacitance(self):
"""Get the drain capacitances of the TXs in the gate."""
nmos_stack = 2
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_stack,
self.tx_mults)
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
1,
self.tx_mults)
return nmos_drain_c + pmos_drain_c
self.tx_mults)
return nmos_drain_c + pmos_drain_c

View File

@ -82,7 +82,6 @@ class pnand3(pgate.pgate):
tx_type="nmos",
add_source_contact="active",
add_drain_contact="active")
self.add_mod(self.nmos_center)
self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width,
@ -90,7 +89,6 @@ class pnand3(pgate.pgate):
tx_type="nmos",
add_source_contact="active",
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.nmos_left = factory.create(module_type="ptx",
width=self.nmos_width,
@ -98,7 +96,6 @@ class pnand3(pgate.pgate):
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact="active")
self.add_mod(self.nmos_left)
self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width,
@ -106,7 +103,6 @@ class pnand3(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_center = factory.create(module_type="ptx",
width=self.pmos_width,
@ -114,7 +110,6 @@ class pnand3(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_center)
self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width,
@ -122,7 +117,6 @@ class pnand3(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """
@ -350,27 +344,26 @@ class pnand3(pgate.pgate):
def is_non_inverting(self):
"""Return input to output polarity for module"""
return False
def get_on_resistance(self):
"""On resistance of pnand, defined by stacked NMOS"""
is_nchannel = True
stack = 3
is_cell = False
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell)
def get_input_capacitance(self):
"""Input cap of input, passes width of gates to gate cap function"""
return self.gate_c(self.nmos_width+self.pmos_width)
return self.gate_c(self.nmos_width+self.pmos_width)
def get_intrinsic_capacitance(self):
"""Get the drain capacitances of the TXs in the gate."""
nmos_stack = 3
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults,
nmos_stack,
self.tx_mults)
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults,
1,
self.tx_mults)
return nmos_drain_c + pmos_drain_c
self.tx_mults)
return nmos_drain_c + pmos_drain_c

View File

@ -82,7 +82,6 @@ class pnand4(pgate.pgate):
tx_type="nmos",
add_source_contact="active",
add_drain_contact="active")
self.add_mod(self.nmos_center)
self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width,
@ -90,7 +89,6 @@ class pnand4(pgate.pgate):
tx_type="nmos",
add_source_contact="active",
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.nmos_left = factory.create(module_type="ptx",
width=self.nmos_width,
@ -98,7 +96,6 @@ class pnand4(pgate.pgate):
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact="active")
self.add_mod(self.nmos_left)
self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width,
@ -106,7 +103,6 @@ class pnand4(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_left)
self.pmos_center = factory.create(module_type="ptx",
width=self.pmos_width,
@ -114,7 +110,6 @@ class pnand4(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_center)
self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width,
@ -122,7 +117,6 @@ class pnand4(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """

View File

@ -77,7 +77,6 @@ class pnor2(pgate.pgate):
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_left)
self.nmos_right = factory.create(module_type="ptx",
width=self.nmos_width,
@ -85,7 +84,6 @@ class pnor2(pgate.pgate):
tx_type="nmos",
add_source_contact=self.route_layer,
add_drain_contact=self.route_layer)
self.add_mod(self.nmos_right)
self.pmos_left = factory.create(module_type="ptx",
width=self.pmos_width,
@ -93,7 +91,6 @@ class pnor2(pgate.pgate):
tx_type="pmos",
add_source_contact=self.route_layer,
add_drain_contact="active")
self.add_mod(self.pmos_left)
self.pmos_right = factory.create(module_type="ptx",
width=self.pmos_width,
@ -101,7 +98,6 @@ class pnor2(pgate.pgate):
tx_type="pmos",
add_source_contact="active",
add_drain_contact=self.route_layer)
self.add_mod(self.pmos_right)
def setup_layout_constants(self):
""" Pre-compute some handy layout parameters. """

View File

@ -90,7 +90,6 @@ class precharge(design.design):
width=self.ptx_width,
mults=self.ptx_mults,
tx_type="pmos")
self.add_mod(self.pmos)
def route_vdd_rail(self):
"""
@ -305,4 +304,3 @@ class precharge(design.design):
self.add_path(self.bitline_layer,
[left_pos, right_pos],
width=pmos_pin.height())

View File

@ -85,13 +85,11 @@ class ptristate_inv(pgate.pgate):
width=self.nmos_width,
mults=1,
tx_type="nmos")
self.add_mod(self.nmos)
self.pmos = factory.create(module_type="ptx",
width=self.pmos_width,
mults=1,
tx_type="pmos")
self.add_mod(self.pmos)
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """

View File

@ -66,19 +66,16 @@ class pwrite_driver(design.design):
# Tristate inverter
self.tri = factory.create(module_type="ptristate_inv", height="min")
self.add_mod(self.tri)
debug.check(self.tri.width<self.width,
"Could not create tristate inverter to match bitcell width")
#self.tbuf = factory.create(module_type="ptristate_buf",
#height="min")
#self.add_mod(self.tbuf)
#debug.check(self.tbuf.width<self.width,
#"Could not create tristate buffer to match bitcell width")
# Inverter for din and en
self.inv = factory.create(module_type="pinv", under_rail_vias=True)
self.add_mod(self.inv)
def create_insts(self):
# Enable inverter

View File

@ -62,9 +62,6 @@ class wordline_driver(design.design):
size=driver_size,
height=self.nand.height)
self.add_mod(self.nand)
self.add_mod(self.driver)
def create_layout(self):
self.width = self.nand.width + self.driver.width
if "li" in layer:

View File

@ -468,11 +468,9 @@ class sram_base(design, verilog, lef):
self.msb_address = dff_buf_array(name="msb_address",
rows=1,
columns=self.num_banks / 2)
self.add_mod(self.msb_address)
if self.num_banks>2:
self.msb_decoder = self.bank.decoder.pre2_4
self.add_mod(self.msb_decoder)
def add_modules(self):
self.bitcell = factory.create(module_type=OPTS.bitcell)
@ -480,30 +478,24 @@ class sram_base(design, verilog, lef):
# Create the bank module (up to four are instantiated)
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
self.add_mod(self.bank)
self.num_spare_cols = self.bank.num_spare_cols
# Create the address and control flops (but not the clk)
self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.add_mod(self.row_addr_dff)
if self.col_addr_size > 0:
self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size)
self.add_mod(self.col_addr_dff)
else:
self.col_addr_dff = None
self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols)
self.add_mod(self.data_dff)
if self.write_size:
self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks)
self.add_mod(self.wmask_dff)
if self.num_spare_cols:
self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols)
self.add_mod(self.spare_wen_dff)
# Create bank decoder
if(self.num_banks > 1):
@ -515,30 +507,27 @@ class sram_base(design, verilog, lef):
self.mod_control_logic = getattr(c, OPTS.control_logic)
# Create the control logic module for each port type
if len(self.readwrite_ports)>0:
if len(self.readwrite_ports) > 0:
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
spare_columns=self.num_spare_cols,
sram=self,
port_type="rw")
self.add_mod(self.control_logic_rw)
if len(self.writeonly_ports)>0:
if len(self.writeonly_ports) > 0:
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
spare_columns=self.num_spare_cols,
sram=self,
port_type="w")
self.add_mod(self.control_logic_w)
if len(self.readonly_ports)>0:
if len(self.readonly_ports) > 0:
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
words_per_row=self.words_per_row,
word_size=self.word_size,
spare_columns=self.num_spare_cols,
sram=self,
port_type="r")
self.add_mod(self.control_logic_r)
def create_bank(self, bank_num):
""" Create a bank """
@ -779,13 +768,13 @@ class sram_base(design, verilog, lef):
Clears the bit exclusions
"""
self.bank.clear_exclude_bits()
def graph_exclude_column_mux(self, column_include_num, port):
"""
Excludes all columns muxes unrelated to the target bit being simulated.
"""
self.bank.graph_exclude_column_mux(column_include_num, port)
def graph_clear_column_mux(self, port):
"""
Clear mux exclusions to allow different bit tests.

View File

@ -41,6 +41,16 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
else:
debug.warning("Could not locate file: {}".format(full_drc_file))
# Copy .gds file into the output directory
if os.path.isabs(gds_name):
shutil.copy(gds_name, output_path)
gds_name = os.path.basename(gds_name)
# Copy .sp file into the output directory
if sp_name and os.path.isabs(sp_name):
shutil.copy(sp_name, output_path)
sp_name = os.path.basename(sp_name)
# Create an auxiliary script to run calibre with the runset
run_file = output_path + "run_drc.sh"
f = open(run_file, "w")
@ -111,14 +121,29 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out
else:
debug.warning("Could not locate file: {}".format(full_lvs_file))
# Copy .gds file into the output directory
if os.path.isabs(gds_name):
shutil.copy(gds_name, output_path)
gds_name = os.path.basename(gds_name)
# Copy .sp file into the output directory
if os.path.isabs(sp_name):
shutil.copy(sp_name, output_path)
sp_name = os.path.basename(sp_name)
run_file = output_path + "/run_lvs.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice".format(OPTS.lvs_exe[1],
lvs_file,
gds_name,
sp_name,
cell_name)
if final_verification:
connect_supplies = ""
else:
connect_supplies = "-rd connect_supplies=1"
cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice {5}".format(OPTS.lvs_exe[1],
lvs_file,
gds_name,
sp_name,
cell_name,
connect_supplies)
f.write(cmd)
f.write("\n")
f.close()

View File

@ -110,8 +110,9 @@ end
# Wells
nwell.and(pwell).output("WELL.1", "WELL.1 : nwell/pwell must not overlap")
# the rule "WELL.2 : Minimum spacing of well at different potential : 225nm" was not coded : see : https://www.klayout.de/forum/discussion/comment/6021
nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm")
pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm")
# the rule WELL.3 was not detected in the original FreePDK45 rule deck
#nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm")
#pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm")
well.separation(well, 200.nm, euclidian).output("WELL.4", "WELL.4 : Minimum width of nwell/pwell : 200nm")
vtg.not(well).output("VT.1","VT.1 : Vtg adjust layers must coincide with well")
vth.not(well).output("VT.1","VT.1 : Vth adjust layers must coincide with well")

View File

@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox
gv_ngate = ngate &amp; vtg - vth - thkox
hv_ngate = ngate - vtg - vth &amp; thkox
cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") {
cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell*", "dummy_pbitcell*", "replica_pbitcell*", "dff", "wordline_driver*") {
# PMOS transistor device extraction
extract_devices(mos4("PMOS_VTL"), { "SD" =&gt; psd, "G" =&gt; lv_pgate, "tS" =&gt; psd, "tD" =&gt; psd, "tG" =&gt; poly, "W" =&gt; nwell })
@ -205,14 +205,19 @@ connect(metal10, metal10_pin)
# Global
schematic.simplify
if $connect_supplies
connect_implicit("*", "vdd")
connect_implicit("*", "gnd")
end
connect_global(pwell, "PWELL")
connect_global(nwell, "NWELL")
connect_global(bulk, "BULK")
#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array)
# connect_explicit(pat, [ "NWELL", "vdd" ])
# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ])
#end
for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*)
connect_explicit(pat, [ "NWELL", "vdd" ])
connect_explicit(pat, [ "BULK", "PWELL", "gnd" ])
end
#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL*
# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,205 @@
<?xml version="1.0" encoding="utf-8"?>
<technology>
<name>MOSIS_SCMOS</name>
<description>MOSIS SCMOS lambda based process</description>
<group/>
<dbu>0.001</dbu>
<base-path>$(appdata_path)/tech/MOSIS_SCMOS</base-path>
<layer-properties_file>MOSIS_SCMOS.lyp</layer-properties_file>
<add-other-layers>true</add-other-layers>
<reader-options>
<gds2>
<box-mode>1</box-mode>
<allow-big-records>true</allow-big-records>
<allow-multi-xy-records>true</allow-multi-xy-records>
</gds2>
<common>
<create-other-layers>true</create-other-layers>
<layer-map>layer_map()</layer-map>
<enable-properties>true</enable-properties>
<enable-text-objects>true</enable-text-objects>
</common>
<lefdef>
<read-all-layers>true</read-all-layers>
<layer-map>layer_map()</layer-map>
<dbu>0.001</dbu>
<produce-net-names>true</produce-net-names>
<net-property-name>#1</net-property-name>
<produce-inst-names>true</produce-inst-names>
<inst-property-name>#1</inst-property-name>
<produce-pin-names>false</produce-pin-names>
<pin-property-name>#1</pin-property-name>
<produce-cell-outlines>true</produce-cell-outlines>
<cell-outline-layer>OUTLINE</cell-outline-layer>
<produce-placement-blockages>true</produce-placement-blockages>
<placement-blockage-layer>PLACEMENT_BLK</placement-blockage-layer>
<produce-regions>true</produce-regions>
<region-layer>REGIONS</region-layer>
<produce-via-geometry>true</produce-via-geometry>
<special-via_geometry-suffix-string/>
<special-via_geometry-datatype-string>0</special-via_geometry-datatype-string>
<produce-pins>true</produce-pins>
<special-pins-suffix-string>.PIN</special-pins-suffix-string>
<special-pins-datatype-string>2</special-pins-datatype-string>
<produce-lef-pins>true</produce-lef-pins>
<special-lef_pins-suffix-string>.PIN</special-lef_pins-suffix-string>
<special-lef_pins-datatype-string>2</special-lef_pins-datatype-string>
<produce-fills>true</produce-fills>
<special-fills-suffix-string>.FILL</special-fills-suffix-string>
<special-fills-datatype-string>5</special-fills-datatype-string>
<produce-obstructions>true</produce-obstructions>
<obstructions-suffix>.OBS</obstructions-suffix>
<obstructions-datatype>3</obstructions-datatype>
<produce-blockages>true</produce-blockages>
<blockages-suffix>.BLK</blockages-suffix>
<blockages-datatype>4</blockages-datatype>
<produce-labels>true</produce-labels>
<labels-suffix>.LABEL</labels-suffix>
<labels-datatype>1</labels-datatype>
<produce-routing>true</produce-routing>
<special-routing-suffix-string/>
<special-routing-datatype-string>0</special-routing-datatype-string>
<produce-special-routing>true</produce-special-routing>
<special-routing-suffix-string/>
<special-routing-datatype-string>0</special-routing-datatype-string>
<via-cellname-prefix>VIA_</via-cellname-prefix>
<read-lef-with-def>true</read-lef-with-def>
<macro-resolution-mode>default</macro-resolution-mode>
<separate-groups>false</separate-groups>
<map-file/>
</lefdef>
<mebes>
<invert>false</invert>
<subresolution>true</subresolution>
<produce-boundary>true</produce-boundary>
<num-stripes-per-cell>64</num-stripes-per-cell>
<num-shapes-per-cell>0</num-shapes-per-cell>
<data-layer>1</data-layer>
<data-datatype>0</data-datatype>
<data-name>DATA</data-name>
<boundary-layer>0</boundary-layer>
<boundary-datatype>0</boundary-datatype>
<boundary-name>BORDER</boundary-name>
<layer-map>layer_map()</layer-map>
<create-other-layers>true</create-other-layers>
</mebes>
<dxf>
<dbu>0.001</dbu>
<unit>1</unit>
<text-scaling>100</text-scaling>
<circle-points>100</circle-points>
<circle-accuracy>0</circle-accuracy>
<contour-accuracy>0</contour-accuracy>
<polyline-mode>0</polyline-mode>
<render-texts-as-polygons>false</render-texts-as-polygons>
<keep-other-cells>false</keep-other-cells>
<keep-layer-names>false</keep-layer-names>
<create-other-layers>true</create-other-layers>
<layer-map>layer_map()</layer-map>
</dxf>
<cif>
<wire-mode>0</wire-mode>
<dbu>0.001</dbu>
<layer-map>layer_map()</layer-map>
<create-other-layers>true</create-other-layers>
<keep-layer-names>false</keep-layer-names>
</cif>
<mag>
<lambda>1</lambda>
<dbu>0.001</dbu>
<layer-map>layer_map()</layer-map>
<create-other-layers>true</create-other-layers>
<keep-layer-names>false</keep-layer-names>
<merge>true</merge>
<lib-paths>
</lib-paths>
</mag>
</reader-options>
<writer-options>
<gds2>
<write-timestamps>true</write-timestamps>
<write-cell-properties>false</write-cell-properties>
<write-file-properties>false</write-file-properties>
<no-zero-length-paths>false</no-zero-length-paths>
<multi-xy-records>false</multi-xy-records>
<resolve-skew-arrays>false</resolve-skew-arrays>
<max-vertex-count>8000</max-vertex-count>
<max-cellname-length>32000</max-cellname-length>
<libname>LIB</libname>
</gds2>
<oasis>
<compression-level>2</compression-level>
<write-cblocks>false</write-cblocks>
<strict-mode>false</strict-mode>
<write-std-properties>1</write-std-properties>
<subst-char>*</subst-char>
<permissive>false</permissive>
</oasis>
<cif>
<polygon-mode>0</polygon-mode>
</cif>
<cif>
<dummy-calls>false</dummy-calls>
<blank-separator>false</blank-separator>
</cif>
<mag>
<lambda>0</lambda>
<tech/>
<write-timestamp>true</write-timestamp>
</mag>
</writer-options>
<d25>
<src># Provide z stack information here
# Each line is one layer. The specification consists of a layer specification, a colon and arguments.
# The arguments are named (like "x=...") or in serial. Parameters are separated by comma or blanks.
# Named arguments are:
#
# zstart The lower z position of the extruded layer in µm
# zstop The upper z position of the extruded layer in µm
# height The height of the extruded layer in µm
#
# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', # the upper level of the previous layer will be used.
#
# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to
# 'zstart' and 'zstop'.
#
# Examples:
# 1: 0.5 1.5 # extrude layer 1/0 from 0.5 to 1.5 vertically
# 1/0: 0.5 1.5 # same with explicit datatype
# 1: zstop=1.5, zstart=0.5 # same with named parameters
# 1: height=1.0, zstop=1.5 # same with z stop minus height
# 1: 1.0 zstop=1.5 # same with height as unnamed parameter
42: zstart=-0.1 , height=0.1
41: zstart=-0.1 , height=0.1
13: zstart=0.001 , height=0.25
46: zstart=0.1 , height=0.15
49: zstart=0.2 , height=0.05
50: zstart=0.2 , height=0.15
51: zstart=0.3 , height=0.05
61: zstart=0.3 , height=0.15
62: zstart=0.4 , height=0.05
30: zstart=0.4 , height=0.15
31: zstart=0.5 , height=0.05
32: zstart=0.5 , height=0.15
33: zstart=0.6 , height=0.05
36: zstart=0.6 , height=0.15
37: zstart=0.7 , height=0.05
127: zstart=0.7 , height=0.15
126: zstart=0.8 , height=0.05
129: zstart=0.9 , height=0.15
53: zstart=0.8 , height=0.05
26: zstart=0.9 , height=0.15
54: zstart=0.9 , height=0.2
</src>
</d25>
<connectivity>
<connection>poly,25,49</connection>
<connection>56,55,49</connection>
<connection>49,50,51</connection>
<connection>51,61,62</connection>
<connection>62,30,31</connection>
<connection>31,32,33</connection>
<connection>33,36,37</connection>
<symbols>poly='46-34'</symbols>
</connectivity>
</technology>

View File

@ -337,7 +337,7 @@ drc.add_enclosure("m2",
# VIA2-3.2 Minimum spacing of Via[2-3]
drc.add_layer("via2",
width=0.065,
spacing=0.075)
spacing=0.085)
# METALINT.1 Minimum width of intermediate metal
# METALINT.2 Minimum spacing of intermediate metal
@ -457,10 +457,10 @@ parameter["sa_inv_nmos_size"] = 0.27 # micro-meters
parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance
# Spice Values uses to calculate analytical delay based on CACTI equations
spice["i_on_n"] = 0.0004463 # A/um
spice["i_on_n"] = 0.0004463 # A/um
spice["i_on_p"] = 0.0000771 # A/um
spice["tox"] = 0.00114 # microns
spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data
spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data
spice["cox"] = spice["eps_ox"]/spice["tox"] # F/um^2
spice["c_g_ideal"] = spice["cox"]*drc["minlength_channel"] # F/um
spice["c_overlap"] = 0.2*spice["c_g_ideal"] # F/um
@ -477,8 +477,12 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa
# Technology Tool Preferences
###################################################
drc_name = "calibre"
lvs_name = "calibre"
pex_name = "calibre"
#drc_name = "calibre"
#lvs_name = "calibre"
#pex_name = "calibre"
drc_name = "klayout"
lvs_name = "klayout"
pex_name = "klayout"
blackbox_bitcell = False

View File

@ -0,0 +1,810 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category>drc</category>
<prolog/>
<epilog/>
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>true</show-in-menu>
<group-name>drc_scripts</group-name>
<menu-path>tools_menu.drc.end</menu-path>
<interpreter>dsl</interpreter>
<dsl-interpreter-name>drc-dsl-xml</dsl-interpreter-name>
<text>#
# MOSIS SCMOS DRC
#
########################
tstart = Time.now
# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb
if $input
if $topcell
source($input,$topcell)
else
source($input)
end
end
if $output
report("SCMOS DRC runset", $output)
else
report("SCMOS DRC runset", "SCMOS_DRC.lyrdb")
end
# PROCESS OPTIONS
########################
LAMBDA = 0.2
SUBM = true
DEEP = false
NBR_OF_METALS = 6
DFM = false
# design rules limits definitions
########################
R1_3 = ( 6 *LAMBDA ).round(3)
R2_1 = ( 3 *LAMBDA ).round(3)
R2_2 = ( 3 *LAMBDA ).round(3)
R2_4 = ( 3 *LAMBDA ).round(3)
R2_5 = ( 4 *LAMBDA ).round(3)
R3_1 = ( 2 *LAMBDA ).round(3)
R3_5 = ( 1 *LAMBDA ).round(3)
R4_1 = ( 3 *LAMBDA ).round(3)
R4_2 = ( 2 *LAMBDA ).round(3)
R5_1 = ( 2 *LAMBDA ).round(3)
R5_2 = ( 1.5 *LAMBDA ).round(3)
R5_4 = ( 2 *LAMBDA ).round(3)
R5_2_b = ( 1 *LAMBDA ).round(3)
R5_6_b = ( 2 *LAMBDA ).round(3)
R5_7_b = ( 3 *LAMBDA ).round(3)
R6_1 = ( 2 *LAMBDA ).round(3)
R6_2 = ( 1.5 *LAMBDA ).round(3)
R6_4 = ( 2 *LAMBDA ).round(3)
R6_2_b = ( 1 *LAMBDA ).round(3)
R6_5_b = ( 5 *LAMBDA ).round(3)
R6_6_b = ( 2 *LAMBDA ).round(3)
R6_7_b = ( 3 *LAMBDA ).round(3)
R6_8_b = ( 4 *LAMBDA ).round(3)
R7_1 = ( 3 *LAMBDA ).round(3)
R7_3 = ( 1 *LAMBDA ).round(3)
R8_2 = ( 3 *LAMBDA ).round(3)
R8_3 = ( 1 *LAMBDA ).round(3)
R8_4 = ( 2 *LAMBDA ).round(3)
R9_1 = ( 3 *LAMBDA ).round(3)
R9_3 = ( 1 *LAMBDA ).round(3)
R10_1 = ( 60 *LAMBDA ).round(3)
R10_2 = ( 20 *LAMBDA ).round(3)
R10_3 = ( 6 *LAMBDA ).round(3)
R10_4 = ( 30 *LAMBDA ).round(3)
R10_5 = ( 15 *LAMBDA ).round(3)
R11_2 = ( 3 *LAMBDA ).round(3)
R11_4 = ( 2 *LAMBDA ).round(3)
R11_6 = ( 2 *LAMBDA ).round(3)
R12_1 = ( 2 *LAMBDA ).round(3)
R12_2 = ( 3 *LAMBDA ).round(3)
R12_3 = ( 2 *LAMBDA ).round(3)
R12_4 = ( 1 *LAMBDA ).round(3)
R12_5 = ( 2 *LAMBDA ).round(3)
R12_6 = ( 3 *LAMBDA ).round(3)
R13_1 = ( 2 *LAMBDA ).round(3)
R13_3 = ( 3 *LAMBDA ).round(3)
R13_4 = ( 2 *LAMBDA ).round(3)
R13_5 = ( 3 *LAMBDA ).round(3)
R14_2 = ( 3 *LAMBDA ).round(3)
R14_3 = ( 1 *LAMBDA ).round(3)
R14_4 = ( 2 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 3
R15_3 = ( 1 *LAMBDA ).round(3)
else
R15_3 = ( 2 *LAMBDA ).round(3)
end
R16_1 = ( 2 *LAMBDA ).round(3)
R16_2 = ( 3 *LAMBDA ).round(3)
R16_3 = ( 2 *LAMBDA ).round(3)
R16_4 = ( 4 *LAMBDA ).round(3)
R16_5 = ( 2 *LAMBDA ).round(3)
R16_6 = ( 2 *LAMBDA ).round(3)
R16_7 = ( 6 *LAMBDA ).round(3)
R16_8 = ( 4 *LAMBDA ).round(3)
R16_9 = ( 2 *LAMBDA ).round(3)
R16_10 = ( 3 *LAMBDA ).round(3)
R16_11 = ( 2 *LAMBDA ).round(3)
R18_1 = ( 3 *LAMBDA ).round(3)
R18_2 = ( 2 *LAMBDA ).round(3)
R18_3 = ( 3 *LAMBDA ).round(3)
R18_4 = ( 2 *LAMBDA ).round(3)
R18_5 = ( 6 *LAMBDA ).round(3)
R20_1 = ( 4 *LAMBDA ).round(3)
R20_2 = ( 4 *LAMBDA ).round(3)
R20_3 = ( 2 *LAMBDA ).round(3)
R20_4 = ( 2 *LAMBDA ).round(3)
R20_5 = ( 2 *LAMBDA ).round(3)
R20_7 = ( 5 *LAMBDA ).round(3)
R20_8 = ( 7 *LAMBDA ).round(3)
R20_9 = ( 2 *LAMBDA ).round(3)
R20_10 = ( 3 *LAMBDA ).round(3)
R21_2 = ( 3 *LAMBDA ).round(3)
R21_3 = ( 1 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 4
R22_3 = ( 1 *LAMBDA ).round(3)
else
R22_3 = ( 2 *LAMBDA ).round(3)
end
R23_1 = ( 8 *LAMBDA ).round(3)
R23_2 = ( 4 *LAMBDA ).round(3)
R23_3 = ( 8 *LAMBDA ).round(3)
R23_4 = ( 3 *LAMBDA ).round(3)
R23_5 = ( 2 *LAMBDA ).round(3)
R23_6 = ( 2 *LAMBDA ).round(3)
R23_7 = ( 2 *LAMBDA ).round(3)
R23_8 = ( 4 *LAMBDA ).round(3)
R23_9 = ( 2 *LAMBDA ).round(3)
R24_1 = ( 4 *LAMBDA ).round(3)
R24_2 = ( 4 *LAMBDA ).round(3)
R24_3 = ( 4 *LAMBDA ).round(3)
R24_4 = ( 4 *LAMBDA ).round(3)
R24_5 = ( 3 *LAMBDA ).round(3)
R27_1 = ( 4 *LAMBDA ).round(3)
R27_2 = ( 4 *LAMBDA ).round(3)
R27_3 = ( 2 *LAMBDA ).round(3)
R27_4 = ( 2 *LAMBDA ).round(3)
R27_5 = ( 2 *LAMBDA ).round(3)
R27_7 = ( 5 *LAMBDA ).round(3)
R27_8 = ( 7 *LAMBDA ).round(3)
R27_9 = ( 2 *LAMBDA ).round(3)
if !SUBM &amp;&amp; !DEEP
R1_1 = ( 10 *LAMBDA ).round(3)
R1_2 = ( 9 *LAMBDA ).round(3)
R2_3 = ( 5 *LAMBDA ).round(3)
R3_2 = ( 2 *LAMBDA ).round(3)
R3_2_a = ( 2 *LAMBDA ).round(3)
R3_3 = ( 2 *LAMBDA ).round(3)
R3_4 = ( 3 *LAMBDA ).round(3)
R4_3 = ( 1 *LAMBDA ).round(3)
R4_4 = ( 2 *LAMBDA ).round(3)
R5_3 = ( 2 *LAMBDA ).round(3)
R5_5_b = ( 4 *LAMBDA ).round(3)
R6_3 = ( 2 *LAMBDA ).round(3)
R7_2 = ( 2 *LAMBDA ).round(3)
R7_4 = ( 4 *LAMBDA ).round(3)
R8_1 = ( 2 *LAMBDA ).round(3)
R8_5 = ( 2 *LAMBDA ).round(3)
R9_2 = ( 3 *LAMBDA ).round(3)
R9_4 = ( 6 *LAMBDA ).round(3)
R11_1 = ( 3 *LAMBDA ).round(3)
R11_3 = ( 2 *LAMBDA ).round(3)
R11_5 = ( 3 *LAMBDA ).round(3)
R13_2 = ( 2 *LAMBDA ).round(3)
R14_1 = ( 2 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 3
R15_1 = ( 3 *LAMBDA ).round(3)
R15_2 = ( 3 *LAMBDA ).round(3)
R15_4 = ( 6 *LAMBDA ).round(3)
else
R15_1 = ( 6 *LAMBDA ).round(3)
R15_2 = ( 4 *LAMBDA ).round(3)
R15_4 = ( 8 *LAMBDA ).round(3)
end
R17_1 = ( 10 *LAMBDA ).round(3)
R17_2 = ( 9 *LAMBDA ).round(3)
R17_3 = ( 5 *LAMBDA ).round(3)
R17_4 = ( 5 *LAMBDA ).round(3)
R20_11 = ( 3 *LAMBDA ).round(3)
R21_1 = ( 2 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 4
R22_1 = ( 3 *LAMBDA ).round(3)
R22_2 = ( 3 *LAMBDA ).round(3)
R22_4 = ( 6 *LAMBDA ).round(3)
else
R22_1 = ( 6 *LAMBDA ).round(3)
R22_2 = ( 6 *LAMBDA ).round(3)
R22_4 = ( 12 *LAMBDA ).round(3)
end
end
if SUBM
R1_1 = ( 12 *LAMBDA ).round(3)
# We are assuming the wells are at the same potential since
# DRC can't tell otherwise
#R1_2 = ( 18 *LAMBDA ).round(3)
R1_2 = ( 6 *LAMBDA ).round(3)
R2_3 = ( 6 *LAMBDA ).round(3)
R3_2 = ( 3 *LAMBDA ).round(3)
R3_2_a = ( 3 *LAMBDA ).round(3)
R3_3 = ( 2 *LAMBDA ).round(3)
R3_4 = ( 3 *LAMBDA ).round(3)
R4_3 = ( 1 *LAMBDA ).round(3)
R4_4 = ( 2 *LAMBDA ).round(3)
R5_3 = ( 3 *LAMBDA ).round(3)
R5_5_b = ( 5 *LAMBDA ).round(3)
R6_3 = ( 3 *LAMBDA ).round(3)
R7_2 = ( 3 *LAMBDA ).round(3)
R7_4 = ( 6 *LAMBDA ).round(3)
R8_1 = ( 2 *LAMBDA ).round(3)
R8_5 = ( 2 *LAMBDA ).round(3)
R9_2 = ( 3 *LAMBDA ).round(3)
R9_4 = ( 6 *LAMBDA ).round(3)
R11_1 = ( 7 *LAMBDA ).round(3)
R11_3 = ( 5 *LAMBDA ).round(3)
R11_5 = ( 6 *LAMBDA ).round(3)
R13_2 = ( 3 *LAMBDA ).round(3)
R14_1 = ( 2 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 3
R15_1 = ( 3 *LAMBDA ).round(3)
R15_2 = ( 3 *LAMBDA ).round(3)
R15_4 = ( 6 *LAMBDA ).round(3)
else
R15_1 = ( 5 *LAMBDA ).round(3)
R15_2 = ( 3 *LAMBDA ).round(3)
R15_4 = ( 6 *LAMBDA ).round(3)
end
R17_1 = ( 12 *LAMBDA ).round(3)
R17_2 = ( 18 *LAMBDA ).round(3)
R17_3 = ( 6 *LAMBDA ).round(3)
R17_4 = ( 6 *LAMBDA ).round(3)
R20_11 = ( 5 *LAMBDA ).round(3)
R21_1 = ( 2 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 4
R22_1 = ( 3 *LAMBDA ).round(3)
R22_2 = ( 3 *LAMBDA ).round(3)
R22_4 = ( 6 *LAMBDA ).round(3)
else
R22_1 = ( 6 *LAMBDA ).round(3)
R22_2 = ( 6 *LAMBDA ).round(3)
R22_4 = ( 12 *LAMBDA ).round(3)
end
R25_1 = ( 2 *LAMBDA ).round(3)
R25_2 = ( 3 *LAMBDA ).round(3)
R25_3 = ( 1 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 5
R26_1 = ( 3 *LAMBDA ).round(3)
R26_2 = ( 3 *LAMBDA ).round(3)
R26_3 = ( 1 *LAMBDA ).round(3)
R26_4 = ( 6 *LAMBDA ).round(3)
else
R26_1 = ( 4 *LAMBDA ).round(3)
R26_2 = ( 4 *LAMBDA ).round(3)
R26_3 = ( 2 *LAMBDA ).round(3)
R26_4 = ( 8 *LAMBDA ).round(3)
end
R28_1 = ( 40 *LAMBDA ).round(3)
R28_2 = ( 12 *LAMBDA ).round(3)
R28_3 = ( 4 *LAMBDA ).round(3)
R28_4 = ( 3 *LAMBDA ).round(3)
R28_5 = ( 4 *LAMBDA ).round(3)
R28_6 = ( 2 *LAMBDA ).round(3)
R28_7 = ( 25 *LAMBDA ).round(3)
R28_8 = ( 4 *LAMBDA ).round(3)
R28_9 = ( 8 *LAMBDA ).round(3)
R28_10 = ( 20 *LAMBDA ).round(3)
R28_11 = ( 40 *LAMBDA ).round(3)
R29_1 = ( 3 *LAMBDA ).round(3)
R29_2 = ( 4 *LAMBDA ).round(3)
R29_3 = ( 1 *LAMBDA ).round(3)
R30_1 = ( 5 *LAMBDA ).round(3)
R30_2 = ( 5 *LAMBDA ).round(3)
R30_3 = ( 1 *LAMBDA ).round(3)
R30_4 = ( 10 *LAMBDA ).round(3)
R31_1 = ( 30 *LAMBDA ).round(3)
R31_2 = ( 50 *LAMBDA ).round(3)
R31_3 = ( 15 *LAMBDA ).round(3)
R31_4 = ( 20 *LAMBDA ).round(3)
R31_5 = ( 35 *LAMBDA ).round(3)
R31_6 = ( 5 *LAMBDA ).round(3)
R31_7 = ( 30 *LAMBDA ).round(3)
R31_8 = ( 10 *LAMBDA ).round(3)
end
if DEEP
R1_1 = ( 12 *LAMBDA ).round(3)
# We are assuming the wells are at the same potential since
# DRC can't tell otherwise
#R1_2 = ( 18 *LAMBDA ).round(3)
R1_2 = ( 6 *LAMBDA ).round(3)
R2_3 = ( 6 *LAMBDA ).round(3)
R3_2 = ( 3 *LAMBDA ).round(3)
R3_2_a = ( 4 *LAMBDA ).round(3)
R3_3 = ( 2.5 *LAMBDA ).round(3)
R3_4 = ( 4 *LAMBDA ).round(3)
R4_3 = ( 1.5 *LAMBDA ).round(3)
R4_4 = ( 4 *LAMBDA ).round(3)
R5_3 = ( 4 *LAMBDA ).round(3)
R5_5_b = ( 5 *LAMBDA ).round(3)
R6_3 = ( 4 *LAMBDA ).round(3)
R7_2 = ( 3 *LAMBDA ).round(3)
R7_4 = ( 6 *LAMBDA ).round(3)
R8_1 = ( 3 *LAMBDA ).round(3)
R9_2 = ( 4 *LAMBDA ).round(3)
R9_4 = ( 8 *LAMBDA ).round(3)
R11_1 = ( 7 *LAMBDA ).round(3)
R11_3 = ( 5 *LAMBDA ).round(3)
R11_5 = ( 6 *LAMBDA ).round(3)
R13_2 = ( 3 *LAMBDA ).round(3)
R14_1 = ( 3 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 3
R15_1 = ( 3 *LAMBDA ).round(3)
R15_2 = ( 4 *LAMBDA ).round(3)
R15_4 = ( 8 *LAMBDA ).round(3)
else
R15_1 = ( 5 *LAMBDA ).round(3)
R15_2 = ( 3 *LAMBDA ).round(3)
R15_4 = ( 6 *LAMBDA ).round(3)
end
R17_1 = ( 12 *LAMBDA ).round(3)
R17_2 = ( 18 *LAMBDA ).round(3)
R17_3 = ( 6 *LAMBDA ).round(3)
R17_4 = ( 6 *LAMBDA ).round(3)
R20_11 = ( 5 *LAMBDA ).round(3)
R21_1 = ( 3 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 4
R22_1 = ( 3 *LAMBDA ).round(3)
R22_2 = ( 4 *LAMBDA ).round(3)
R22_4 = ( 8 *LAMBDA ).round(3)
else
R22_1 = ( 6 *LAMBDA ).round(3)
R22_2 = ( 6 *LAMBDA ).round(3)
R22_4 = ( 12 *LAMBDA ).round(3)
end
R25_1 = ( 3 *LAMBDA ).round(3)
R25_2 = ( 3 *LAMBDA ).round(3)
R25_3 = ( 1 *LAMBDA ).round(3)
if NBR_OF_METALS &gt; 5
R26_1 = ( 3 *LAMBDA ).round(3)
R26_2 = ( 4 *LAMBDA ).round(3)
R26_3 = ( 1 *LAMBDA ).round(3)
R26_4 = ( 8 *LAMBDA ).round(3)
else
R26_1 = ( 4 *LAMBDA ).round(3)
R26_2 = ( 4 *LAMBDA ).round(3)
R26_3 = ( 2 *LAMBDA ).round(3)
R26_4 = ( 8 *LAMBDA ).round(3)
end
R28_1 = ( 45 *LAMBDA ).round(3)
R28_2 = ( 14 *LAMBDA ).round(3)
R28_3 = ( 5 *LAMBDA ).round(3)
R28_4 = ( 3 *LAMBDA ).round(3)
R28_5 = ( 5 *LAMBDA ).round(3)
R28_6 = ( 2 *LAMBDA ).round(3)
R28_7 = ( 25 *LAMBDA ).round(3)
R28_8 = ( 5 *LAMBDA ).round(3)
R28_9 = ( 9 *LAMBDA ).round(3)
R28_10 = ( 23 *LAMBDA ).round(3)
R28_11 = ( 45 *LAMBDA ).round(3)
R29_1 = ( 4 *LAMBDA ).round(3)
R29_2 = ( 4 *LAMBDA ).round(3)
R29_3 = ( 1 *LAMBDA ).round(3)
R30_1 = ( 5 *LAMBDA ).round(3)
R30_2 = ( 5 *LAMBDA ).round(3)
R30_3 = ( 2 *LAMBDA ).round(3)
R30_4 = ( 10 *LAMBDA ).round(3)
R31_1 = ( 34 *LAMBDA ).round(3)
R31_2 = ( 56 *LAMBDA ).round(3)
R31_3 = ( 17 *LAMBDA ).round(3)
R31_4 = ( 23 *LAMBDA ).round(3)
R31_5 = ( 39 *LAMBDA ).round(3)
R31_6 = ( 6 *LAMBDA ).round(3)
R31_7 = ( 34 *LAMBDA ).round(3)
R31_8 = ( 13 *LAMBDA ).round(3)
end
# KLAYOUT setttings
########################
# Use a tile size of 1mm
tiles(1000.um)
# Use a tile border of 10 micron:
tile_borders(1.um)
#no_borders
# Use 4 CPU cores
threads(4)
verbose(true)
# Define a new custom function that selects polygons by their number of holes:
# It will return a new layer containing those polygons with min to max holes.
# max can be nil to omit the upper limit.
class DRC::DRCLayer
def with_holes(min, max)
new_data = RBA::Region::new
self.data.each do |p|
if p.holes &gt;= (min || 0) &amp;&amp; (!max || p.holes &lt;= max)
new_data.insert(p)
end
end
DRC::DRCLayer::new(@engine, new_data)
end
end
# layers definitions
########################
info("Layers definitions")
DNW = input(38,0)
NW = input(42,0)
PW = input(41,0)
CW = input(59,0)
AA = input(43,0)
TA = input(60,0)
PBase = input(58,0)
PL = input(46,0)
SB = input(29,0)
Nselect = input(45,0)
Pselect = input(44,0)
PO2 = input(56,0)
HR = input(34,0)
Contact = input(25,0)
ContactPoly = input(47,0)
ContactActive = input(48,0)
ContactPoly2 = input(55, 0)
CT = Contact + ContactPoly + ContactActive + ContactPoly2
M1 = input(49,0)
V1 = input(50,0)
M2 = input(51,0)
V2 = input(61,0)
M3 = input(62,0)
V3 = input(30,0)
M4 = input(31,0)
CTM = input(35,0)
V4 = input(32,0)
M5 = input(33,0)
V5 = input(36,0)
M6 = input(37,0)
Glass = input(52,0)
Pads = input(26,0)
# layers processing
########################
info("Layers processing")
#CHIP = extent.sized(1.0)
NP = AA &amp; Nselect
PP = AA &amp; Pselect
NSTP = NP.and(NW)
PSTP = PP.not(NW)
GATE = PL &amp; AA
# DRC section
########################
info("DRC section")
### Deep NWell
DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW")
DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW")
DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell")
DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um")
DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um")
NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um")
DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um")
DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um")
DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um")
DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um")
### Nwell / Pwell
NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell")
NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell")
NW.and(PW).output("NW_PW","NW over PW not allowed")
NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um")
NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um")
NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um")
PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um")
PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um")
PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um")
### Active
AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA")
AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA")
AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um")
AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um")
NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um")
PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um")
NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um")
PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um")
NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)")
### TA Thick Active
TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA")
TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA")
TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um")
TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um")
TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um")
TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um")
TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um")
AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA")
### Poly
PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly")
PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly")
PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um")
PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um")
GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um")
PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um")
AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um")
PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um")
### Poly2
if !DEEP
PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2")
PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2")
PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um")
PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um")
# rule R12.3 not coded
PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um")
PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um")
PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um")
PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um")
PO2cap = PL &amp; PO2
PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um")
PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um")
PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um")
PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um")
PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um")
PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um")
PO2cap.forget
### Capacitor Well
CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell")
CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell")
CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um")
CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um")
AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um")
CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um")
LinCap = PL &amp; CW
LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um")
LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um")
LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um")
LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um")
LinCap.forget
end
### N+/P+ Select
Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect")
Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect")
Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect")
Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect")
NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um")
PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um")
Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um")
Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um")
Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um")
Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um")
Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um")
Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um")
Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um")
Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um")
Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed")
### HR - High Resistive
HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes")
HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes")
HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um")
HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um")
HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed")
HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um")
HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um")
HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um")
HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed")
HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed")
HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um")
HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um")
HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um")
### SB - Silicide block
SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block")
SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block")
SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um")
SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um")
SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um")
SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed")
SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um")
SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um")
SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed")
SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed")
SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um")
SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um")
SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um")
AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um")
SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um")
PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um")
SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um")
### Contact
CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact")
CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact")
CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed")
CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended")
# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um")
CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um")
CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2")
CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um")
PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um")
AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um")
PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um")
CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um")
CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um")
CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um")
# rule 5.7.b not coded
CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um")
CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um")
CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um")
# rule 6.8.b not coded
CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um")
CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um")
M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um")
### Metal 1
M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1")
M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1")
M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2")
M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um")
M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um")
M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is &gt; #{10*LAMBDA}um : #{R7_4}um")
### Via 1
V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1")
V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed")
V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed")
V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1")
V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um")
V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2")
V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um")
M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um")
M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um")
if !DEEP &amp;&amp; NBR_OF_METALS &lt; 4
V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um")
V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um")
end
if DFM
M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed")
end
### Metal 2
M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2")
M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2")
M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um")
M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um")
M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is &gt; #{10*LAMBDA}um : #{R9_4}um")
### Via 2
V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2")
V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed")
V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed")
V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2")
V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um")
V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2")
V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um")
M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um")
M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um")
if !DEEP &amp;&amp; NBR_OF_METALS &lt; 4
V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um")
end
if DFM
M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed")
end
### Metal 3
M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3")
M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3")
M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um")
M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um")
M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is &gt; #{10*LAMBDA}um : #{R15_4}um")
### Cap Top Metal
if SUBM || DEEP
CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM")
CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM")
CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um")
CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um")
if NBR_OF_METALS == 4
TM = M4
VT = V3
TB = V2
end
if NBR_OF_METALS == 5
TM = M5
VT = V4
VB = V3
end
if NBR_OF_METALS == 6
TM = M6
VT = V5
VB = V4
end
TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um")
CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um")
CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um")
CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um")
TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um")
# rule 28.7 not coded
CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um")
TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um")
VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um")
VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um")
CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um")
TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um")
CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed")
CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed")
end
### Via 3
if NBR_OF_METALS &gt; 3
V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3")
V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed")
V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed")
V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3")
V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um")
V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2")
V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um")
M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um")
M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um")
if DFM
M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed")
end
### Metal 4
M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4")
M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4")
M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um")
M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um")
M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is &gt; #{10*LAMBDA}um : #{R22_4}um")
### Via 4
if NBR_OF_METALS &gt; 4
V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4")
V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed")
V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed")
V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4")
V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um")
V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2")
V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um")
M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um")
M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um")
if DFM
M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed")
end
### Metal 5
M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5")
M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5")
M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um")
M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um")
M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is &gt; #{10*LAMBDA}um : #{R26_4}um")
### Via 5
if NBR_OF_METALS &gt; 5
V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5")
V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed")
V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed")
V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5")
V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um")
V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2")
V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um")
M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um")
M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um")
if DFM
M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed")
end
### Metal 6
M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6")
M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5")
M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um")
M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um")
M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is &gt; #{10*LAMBDA}um : #{R30_4}um")
end
end
end
# time spent for the DRC
time = Time.now
hours = ((time - tstart)/3600).to_i
minutes = ((time - tstart)/60 - hours * 60).to_i
seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i
$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n"</text>
</klayout-macro>

View File

@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<klayout-macro>
<description/>
<version/>
<category>lvs</category>
<prolog/>
<epilog/>
<doc/>
<autorun>false</autorun>
<autorun-early>false</autorun-early>
<shortcut/>
<show-in-menu>true</show-in-menu>
<group-name>lvs_scripts</group-name>
<menu-path>tools_menu.lvs.end</menu-path>
<interpreter>dsl</interpreter>
<dsl-interpreter-name>lvs-dsl-xml</dsl-interpreter-name>
<text>#
# Extraction for freePDK45
#
############################
tstart = Time.now
# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r lvs_freepdk45.lvs
if $input
source($input)
end
if $report
report_lvs($report)
else
report_lvs("lvs_report.lvsdb")
end
if $schematic
#reference netlist
schematic($schematic)
else
schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp"))
end
# true: use net names instead of numbers
# false: use numbers for nets
spice_with_net_names = true
# true: put in comments with details
# false: no comments
spice_with_comments = true
if $target_netlist
target_netlist($target_netlist)
else
# target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.")
target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}")
end
# Hierarchical mode
deep
# Use 4 CPU cores
threads(4)
# Print details
verbose(true)
# layers definitions
########################
info("Layers definitions")
DNW = input(38,0)
nwell = input(42,0)
pwell = input(41,0)
CW = input(59,0)
active = input(43,0)
TA = input(60,0)
PBase = input(58,0)
poly = input(46,0)
SB = input(29,0)
nplus = input(45,0)
pplus = input(44,0)
PO2 = input(56,0)
HR = input(34,0)
Contact = input(25,0)
ContactPoly = input(47,0)
ContactActive = input(48,0)
ContactPoly2 = input(55, 0)
CT = Contact + ContactPoly + ContactActive + ContactPoly2
M1 = input(49,0)
V1 = input(50,0)
M2 = input(51,0)
V2 = input(61,0)
M3 = input(62,0)
V3 = input(30,0)
M4 = input(31,0)
CTM = input(35,0)
V4 = input(32,0)
M5 = input(33,0)
V5 = input(36,0)
M6 = input(37,0)
Glass = input(52,0)
Pads = input(26,0)
# layers processing
########################
info("Layers processing")
# Bulk layer for terminal provisioning
bulk = polygon_layer
active_in_nwell = active &amp; nwell
pactive = active_in_nwell &amp; pplus
ntie = active_in_nwell &amp; nplus
pgate = pactive &amp; poly
psd = pactive - pgate
active_in_pwell = active &amp; pwell
nactive = active_in_pwell &amp; nplus
ptie = active_in_pwell &amp; pplus
ngate = nactive &amp; poly
nsd = nactive - ngate
cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") {
# PMOS transistor device extraction
extract_devices(mos4("p"), { "SD" =&gt; psd, "G" =&gt; pgate, "tS" =&gt; psd, "tD" =&gt; psd, "tG" =&gt; poly, "W" =&gt; nwell })
# NMOS transistor device extraction
extract_devices(mos4("n"), { "SD" =&gt; nsd, "G" =&gt; ngate, "tS" =&gt; nsd, "tD" =&gt; nsd, "tG" =&gt; poly, "W" =&gt; pwell })
}
# Define connectivity for netlist extraction
# Inter-layer
connect(nwell, ntie)
connect(pwell, ptie)
connect(CT, ntie)
connect(CT, ptie)
connect(psd, CT)
connect(nsd, CT)
connect(poly, CT)
connect(CT, M1)
connect(CT, M1)
connect(M1, V1)
connect(V1, M2)
connect(M2, V2)
connect(V2, M3)
connect(M3, V3)
connect(V3, M4)
connect(M4, V4)
connect(V4, M5)
connect(M5, V5)
connect(V5, M6)
# Global
schematic.simplify
if $connect_supplies
connect_implicit("vdd")
connect_implicit("gnd")
end
connect_global(pwell, "PWELL")
connect_global(nwell, "NWELL")
#connect_global(bulk, "BULK")
for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*)
connect_explicit(pat, [ "NWELL", "vdd" ])
connect_explicit(pat, [ "BULK", "PWELL", "gnd" ])
end
# Actually performs the extraction
netlist # ... not really required
# Flatten cells which are present in one netlist only
align
# SIMPLIFICATION of the netlist
#netlist.make_top_level_pins
#netlist.combine_devices
#netlist.purge
#netlist.purge_nets
netlist.simplify
# Tolerances for the devices extracted parameters
# tolerance(device_class_name, parameter_name [, :absolute =&gt; absolute_tolerance] [, :relative =&gt; relative_tolerance])
tolerance("P", "W", :absolute =&gt; 1.nm, :relative =&gt; 0.001)
tolerance("N", "W", :absolute =&gt; 1.nm, :relative =&gt; 0.001)
#max_res(1000000)
#min_caps(1e-15)
max_branch_complexity(65536)
max_depth(16)
if ! compare
#raise "ERROR : Netlists don't match"
puts "ERROR : Netlists don't match"
else
puts "CONGRATULATIONS! Netlists match."
end
# time spent for the LVS
time = Time.now
hours = ((time - tstart)/3600).to_i
minutes = ((time - tstart)/60 - hours * 60).to_i
seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i
$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n"</text>
</klayout-macro>