mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into docker
This commit is contained in:
commit
47690e0076
|
|
@ -232,6 +232,7 @@ class layout():
|
||||||
# Check that the instance name is unique
|
# 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))
|
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.inst_names.add(name)
|
||||||
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
|
self.insts.append(geometry.instance(name, mod, offset, mirror, rotate))
|
||||||
debug.info(3, "adding instance {}".format(self.insts[-1]))
|
debug.info(3, "adding instance {}".format(self.insts[-1]))
|
||||||
|
|
@ -638,7 +639,6 @@ class layout():
|
||||||
directions=directions,
|
directions=directions,
|
||||||
implant_type=implant_type,
|
implant_type=implant_type,
|
||||||
well_type=well_type)
|
well_type=well_type)
|
||||||
self.add_mod(via)
|
|
||||||
inst = self.add_inst(name=via.name,
|
inst = self.add_inst(name=via.name,
|
||||||
mod=via,
|
mod=via,
|
||||||
offset=offset)
|
offset=offset)
|
||||||
|
|
@ -664,7 +664,6 @@ class layout():
|
||||||
corrected_offset = offset + vector(-0.5 * width,
|
corrected_offset = offset + vector(-0.5 * width,
|
||||||
-0.5 * height)
|
-0.5 * height)
|
||||||
|
|
||||||
self.add_mod(via)
|
|
||||||
inst = self.add_inst(name=via.name,
|
inst = self.add_inst(name=via.name,
|
||||||
mod=via,
|
mod=via,
|
||||||
offset=corrected_offset)
|
offset=corrected_offset)
|
||||||
|
|
@ -756,7 +755,6 @@ class layout():
|
||||||
mos = ptx.ptx(width=width,
|
mos = ptx.ptx(width=width,
|
||||||
mults=mults,
|
mults=mults,
|
||||||
tx_type=tx_type)
|
tx_type=tx_type)
|
||||||
self.add_mod(mos)
|
|
||||||
inst = self.add_inst(name=mos.name,
|
inst = self.add_inst(name=mos.name,
|
||||||
mod=mos,
|
mod=mos,
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
|
||||||
|
|
@ -45,10 +45,10 @@ class spice():
|
||||||
self.lvs_file = lvs_dir + cell_name + ".sp"
|
self.lvs_file = lvs_dir + cell_name + ".sp"
|
||||||
else:
|
else:
|
||||||
self.lvs_file = self.sp_file
|
self.lvs_file = self.sp_file
|
||||||
|
|
||||||
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
|
self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"]
|
||||||
# Holds subckts/mods for this module
|
# Holds subckts/mods for this module
|
||||||
self.mods = []
|
self.mods = set()
|
||||||
# Holds the pins for this module (in order)
|
# Holds the pins for this module (in order)
|
||||||
self.pins = []
|
self.pins = []
|
||||||
# The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND
|
# 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]
|
new_list = [input_list[x] for x in self.pin_indices]
|
||||||
return new_list
|
return new_list
|
||||||
|
|
||||||
def add_pin_types(self, type_list):
|
def add_pin_types(self, type_list):
|
||||||
"""
|
"""
|
||||||
Add pin types for all the cell's pins.
|
Add pin types for all the cell's pins.
|
||||||
|
|
@ -140,7 +140,7 @@ class spice():
|
||||||
\n Module names={}\
|
\n Module names={}\
|
||||||
".format(self.name, self.pins, type_list), 1)
|
".format(self.name, self.pins, type_list), 1)
|
||||||
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
|
self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)}
|
||||||
|
|
||||||
def get_pin_type(self, name):
|
def get_pin_type(self, name):
|
||||||
""" Returns the type of the signal pin. """
|
""" Returns the type of the signal pin. """
|
||||||
pin_type = self.pin_type[name]
|
pin_type = self.pin_type[name]
|
||||||
|
|
@ -187,10 +187,6 @@ class spice():
|
||||||
inout_list.append(pin)
|
inout_list.append(pin)
|
||||||
return inout_list
|
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):
|
def connect_inst(self, args, check=True):
|
||||||
"""
|
"""
|
||||||
Connects the pins of the last instance added
|
Connects the pins of the last instance added
|
||||||
|
|
@ -199,13 +195,13 @@ class spice():
|
||||||
where we dynamically generate groups of connections after a
|
where we dynamically generate groups of connections after a
|
||||||
group of modules are generated.
|
group of modules are generated.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
num_pins = len(self.insts[-1].mod.pins)
|
num_pins = len(self.insts[-1].mod.pins)
|
||||||
num_args = len(args)
|
num_args = len(args)
|
||||||
|
|
||||||
# Order the arguments if the hard cell has a custom port order
|
# Order the arguments if the hard cell has a custom port order
|
||||||
ordered_args = self.get_ordered_inputs(args)
|
ordered_args = self.get_ordered_inputs(args)
|
||||||
|
|
||||||
if (check and num_pins != num_args):
|
if (check and num_pins != num_args):
|
||||||
if num_pins < num_args:
|
if num_pins < num_args:
|
||||||
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
|
mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins)
|
||||||
|
|
@ -372,15 +368,15 @@ class spice():
|
||||||
# these are wires and paths
|
# these are wires and paths
|
||||||
if self.conns[i] == []:
|
if self.conns[i] == []:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Instance with no devices in it needs no subckt/instance
|
# Instance with no devices in it needs no subckt/instance
|
||||||
if self.insts[i].mod.no_instances:
|
if self.insts[i].mod.no_instances:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# If this is a trimmed netlist, skip it by adding comment char
|
# If this is a trimmed netlist, skip it by adding comment char
|
||||||
if trim and self.insts[i].name in self.trim_insts:
|
if trim and self.insts[i].name in self.trim_insts:
|
||||||
sp.write("* ")
|
sp.write("* ")
|
||||||
|
|
||||||
if lvs and hasattr(self.insts[i].mod, "lvs_device"):
|
if lvs and hasattr(self.insts[i].mod, "lvs_device"):
|
||||||
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
|
sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name,
|
||||||
" ".join(self.conns[i])))
|
" ".join(self.conns[i])))
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,6 @@ class dummy_pbitcell(design.design):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.prbc = factory.create(module_type="pbitcell",
|
self.prbc = factory.create(module_type="pbitcell",
|
||||||
dummy_bitcell=True)
|
dummy_bitcell=True)
|
||||||
self.add_mod(self.prbc)
|
|
||||||
|
|
||||||
self.height = self.prbc.height
|
self.height = self.prbc.height
|
||||||
self.width = self.prbc.width
|
self.width = self.prbc.width
|
||||||
|
|
|
||||||
|
|
@ -179,26 +179,21 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
# create ptx for inverter transistors
|
# create ptx for inverter transistors
|
||||||
self.inverter_nmos = ptx(width=inverter_nmos_width,
|
self.inverter_nmos = ptx(width=inverter_nmos_width,
|
||||||
tx_type="nmos")
|
tx_type="nmos")
|
||||||
self.add_mod(self.inverter_nmos)
|
|
||||||
|
|
||||||
self.inverter_pmos = ptx(width=inverter_pmos_width,
|
self.inverter_pmos = ptx(width=inverter_pmos_width,
|
||||||
tx_type="pmos")
|
tx_type="pmos")
|
||||||
self.add_mod(self.inverter_pmos)
|
|
||||||
|
|
||||||
# create ptx for readwrite transitors
|
# create ptx for readwrite transitors
|
||||||
self.readwrite_nmos = ptx(width=readwrite_nmos_width,
|
self.readwrite_nmos = ptx(width=readwrite_nmos_width,
|
||||||
tx_type="nmos")
|
tx_type="nmos")
|
||||||
self.add_mod(self.readwrite_nmos)
|
|
||||||
|
|
||||||
# create ptx for write transitors
|
# create ptx for write transitors
|
||||||
self.write_nmos = ptx(width=write_nmos_width,
|
self.write_nmos = ptx(width=write_nmos_width,
|
||||||
tx_type="nmos")
|
tx_type="nmos")
|
||||||
self.add_mod(self.write_nmos)
|
|
||||||
|
|
||||||
# create ptx for read transistors
|
# create ptx for read transistors
|
||||||
self.read_nmos = ptx(width=read_nmos_width,
|
self.read_nmos = ptx(width=read_nmos_width,
|
||||||
tx_type="nmos")
|
tx_type="nmos")
|
||||||
self.add_mod(self.read_nmos)
|
|
||||||
|
|
||||||
def calculate_spacing(self):
|
def calculate_spacing(self):
|
||||||
""" Calculate transistor spacings """
|
""" Calculate transistor spacings """
|
||||||
|
|
@ -425,7 +420,6 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
width=self.width)
|
width=self.width)
|
||||||
self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H"))
|
self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H"))
|
||||||
|
|
||||||
|
|
||||||
vdd_ypos = self.inverter_nmos_ypos \
|
vdd_ypos = self.inverter_nmos_ypos \
|
||||||
+ self.inverter_nmos.active_height \
|
+ self.inverter_nmos.active_height \
|
||||||
+ self.inverter_gap \
|
+ self.inverter_gap \
|
||||||
|
|
@ -475,6 +469,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
self.connect_inst([self.Q_bar,
|
self.connect_inst([self.Q_bar,
|
||||||
self.rw_wl_names[k], br_name, "gnd"])
|
self.rw_wl_names[k], br_name, "gnd"])
|
||||||
|
|
||||||
|
|
||||||
def place_readwrite_ports(self):
|
def place_readwrite_ports(self):
|
||||||
""" Places read/write ports in the bit cell """
|
""" Places read/write ports in the bit cell """
|
||||||
# define read/write transistor variables as empty arrays
|
# define read/write transistor variables as empty arrays
|
||||||
|
|
@ -529,6 +524,21 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
offset=self.rwbr_positions[k],
|
offset=self.rwbr_positions[k],
|
||||||
height=self.height)
|
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
|
# update furthest left and right transistor edges
|
||||||
self.left_building_edge = left_readwrite_transistor_xpos
|
self.left_building_edge = left_readwrite_transistor_xpos
|
||||||
self.right_building_edge = right_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],
|
offset=self.wbr_positions[k],
|
||||||
height=self.height)
|
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
|
# update furthest left and right transistor edges
|
||||||
self.left_building_edge = left_write_transistor_xpos
|
self.left_building_edge = left_write_transistor_xpos
|
||||||
self.right_building_edge = right_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],
|
offset=self.rbr_positions[k],
|
||||||
height=self.height)
|
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):
|
def route_wordlines(self):
|
||||||
""" Routes gate of transistors to their respective wordlines """
|
""" Routes gate of transistors to their respective wordlines """
|
||||||
port_transistors = []
|
port_transistors = []
|
||||||
|
|
@ -1013,7 +1051,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
well_height = max_nmos_well_height + self.port_ypos \
|
well_height = max_nmos_well_height + self.port_ypos \
|
||||||
- self.nwell_enclose_active - self.gnd_position.y
|
- self.nwell_enclose_active - self.gnd_position.y
|
||||||
# FIXME fudge factor xpos
|
# 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)
|
offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos)
|
||||||
self.add_rect(layer="pwell",
|
self.add_rect(layer="pwell",
|
||||||
offset=offset,
|
offset=offset,
|
||||||
|
|
@ -1163,7 +1201,7 @@ class pbitcell(bitcell_base.bitcell_base):
|
||||||
return
|
return
|
||||||
|
|
||||||
pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)}
|
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
|
# 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)
|
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)
|
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:
|
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[bl], self)
|
||||||
graph.add_edge(pin_dict[wl], pin_dict[br], self)
|
graph.add_edge(pin_dict[wl], pin_dict[br], self)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,6 @@ class replica_pbitcell(design.design):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.prbc = factory.create(module_type="pbitcell",
|
self.prbc = factory.create(module_type="pbitcell",
|
||||||
replica_bitcell=True)
|
replica_bitcell=True)
|
||||||
self.add_mod(self.prbc)
|
|
||||||
|
|
||||||
self.height = self.prbc.height
|
self.height = self.prbc.height
|
||||||
self.width = self.prbc.width
|
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, "wl{}".format(port))
|
||||||
self.copy_layout_pin(self.prbc_inst, "vdd")
|
self.copy_layout_pin(self.prbc_inst, "vdd")
|
||||||
self.copy_layout_pin(self.prbc_inst, "gnd")
|
self.copy_layout_pin(self.prbc_inst, "gnd")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ class and2_dec(design.design):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
size=self.size)
|
size=self.size)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
|
|
||||||
if "li" in layer:
|
if "li" in layer:
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,6 @@ class and3_dec(design.design):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
size=self.size)
|
size=self.size)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
if "li" in layer:
|
if "li" in layer:
|
||||||
self.route_layer = "li"
|
self.route_layer = "li"
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ class and4_dec(design.design):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
size=self.size)
|
size=self.size)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
if "li" in layer:
|
if "li" in layer:
|
||||||
self.route_layer = "li"
|
self.route_layer = "li"
|
||||||
|
|
@ -129,4 +126,3 @@ class and4_dec(design.design):
|
||||||
offset=pin.center(),
|
offset=pin.center(),
|
||||||
width=pin.width(),
|
width=pin.width(),
|
||||||
height=pin.height())
|
height=pin.height())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -389,7 +389,6 @@ class bank(design.design):
|
||||||
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
|
self.bitcell_array = factory.create(module_type="replica_bitcell_array",
|
||||||
cols=self.num_cols + self.num_spare_cols,
|
cols=self.num_cols + self.num_spare_cols,
|
||||||
rows=self.num_rows)
|
rows=self.num_rows)
|
||||||
self.add_mod(self.bitcell_array)
|
|
||||||
|
|
||||||
self.port_address = []
|
self.port_address = []
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
|
@ -397,7 +396,6 @@ class bank(design.design):
|
||||||
cols=self.num_cols + self.num_spare_cols,
|
cols=self.num_cols + self.num_spare_cols,
|
||||||
rows=self.num_rows,
|
rows=self.num_rows,
|
||||||
port=port))
|
port=port))
|
||||||
self.add_mod(self.port_address[port])
|
|
||||||
|
|
||||||
self.port_data = []
|
self.port_data = []
|
||||||
self.bit_offsets = self.get_column_offsets()
|
self.bit_offsets = self.get_column_offsets()
|
||||||
|
|
@ -407,11 +405,9 @@ class bank(design.design):
|
||||||
port=port,
|
port=port,
|
||||||
bit_offsets=self.bit_offsets)
|
bit_offsets=self.bit_offsets)
|
||||||
self.port_data.append(temp_pre)
|
self.port_data.append(temp_pre)
|
||||||
self.add_mod(self.port_data[port])
|
|
||||||
|
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.bank_select = factory.create(module_type="bank_select")
|
self.bank_select = factory.create(module_type="bank_select")
|
||||||
self.add_mod(self.bank_select)
|
|
||||||
|
|
||||||
def create_bitcell_array(self):
|
def create_bitcell_array(self):
|
||||||
""" Creating Bitcell Array """
|
""" Creating Bitcell Array """
|
||||||
|
|
@ -547,7 +543,6 @@ class bank(design.design):
|
||||||
else:
|
else:
|
||||||
# No error checking before?
|
# No error checking before?
|
||||||
debug.error("Invalid column decoder?", -1)
|
debug.error("Invalid column decoder?", -1)
|
||||||
self.add_mod(self.column_decoder)
|
|
||||||
|
|
||||||
self.column_decoder_inst = [None] * len(self.all_ports)
|
self.column_decoder_inst = [None] * len(self.all_ports)
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
|
|
|
||||||
|
|
@ -78,20 +78,15 @@ class bank_select(design.design):
|
||||||
|
|
||||||
# 1x Inverter
|
# 1x Inverter
|
||||||
self.inv_sel = factory.create(module_type="pinv", height=height)
|
self.inv_sel = factory.create(module_type="pinv", height=height)
|
||||||
self.add_mod(self.inv_sel)
|
|
||||||
|
|
||||||
# 4x Inverter
|
# 4x Inverter
|
||||||
self.inv4x = factory.create(module_type="pinv", height=height, size=4)
|
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.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.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.nand2 = factory.create(module_type="pnand2", height=height)
|
||||||
self.add_mod(self.nand2)
|
|
||||||
|
|
||||||
def calculate_module_offsets(self):
|
def calculate_module_offsets(self):
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ class bitcell_array(bitcell_base_array):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
self.add_mod(self.cell)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" 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,
|
self.cell_inst[row, col]=self.add_inst(name=name,
|
||||||
mod=self.cell)
|
mod=self.cell)
|
||||||
self.connect_inst(self.get_bitcell_pins(row, col))
|
self.connect_inst(self.get_bitcell_pins(row, col))
|
||||||
|
|
||||||
# If it is a "core" cell, it could be trimmed for sim time
|
# 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:
|
if col>0 and col<self.column_size-1 and row>0 and row<self.row_size-1:
|
||||||
self.trim_insts.add(name)
|
self.trim_insts.add(name)
|
||||||
|
|
||||||
def analytical_power(self, corner, load):
|
def analytical_power(self, corner, load):
|
||||||
"""Power of Bitcell array and bitline in nW."""
|
"""Power of Bitcell array and bitline in nW."""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,11 +43,11 @@ class bitcell_base_array(design.design):
|
||||||
# Make a flat list too
|
# Make a flat list too
|
||||||
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
|
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
|
||||||
|
|
||||||
def create_all_wordline_names(self, row_size=None):
|
def create_all_wordline_names(self, row_size=None, start_row=0):
|
||||||
if row_size == None:
|
if row_size == None:
|
||||||
row_size = self.row_size
|
row_size = self.row_size
|
||||||
|
|
||||||
for row in range(row_size):
|
for row in range(start_row, row_size):
|
||||||
for port in self.all_ports:
|
for port in self.all_ports:
|
||||||
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
|
self.wordline_names[port].append("wl_{0}_{1}".format(port, row))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,14 +42,13 @@ class col_cap_array(bitcell_base_array):
|
||||||
|
|
||||||
self.height = self.dummy_cell.height
|
self.height = self.dummy_cell.height
|
||||||
self.width = self.column_size * self.cell.width
|
self.width = self.column_size * self.cell.width
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
|
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
|
||||||
self.add_mod(self.dummy_cell)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" 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_name in ["vdd", "gnd"]:
|
||||||
for pin in inst.get_pins(pin_name):
|
for pin in inst.get_pins(pin_name):
|
||||||
self.copy_power_pin(pin)
|
self.copy_power_pin(pin)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ class column_mux_array(design.design):
|
||||||
self.mux = factory.create(module_type="column_mux",
|
self.mux = factory.create(module_type="column_mux",
|
||||||
bitcell_bl=self.bitcell_bl,
|
bitcell_bl=self.bitcell_bl,
|
||||||
bitcell_br=self.bitcell_br)
|
bitcell_br=self.bitcell_br)
|
||||||
self.add_mod(self.mux)
|
|
||||||
|
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
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
|
# height to connect the gate to the correct horizontal row
|
||||||
# sel_height = self.get_pin("sel_{}".format(sel_index)).by()
|
# 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
|
# use the y offset from the sel pin and the x offset from the gate
|
||||||
|
|
||||||
offset = vector(gate_offset.x,
|
offset = vector(gate_offset.x,
|
||||||
self.get_pin("sel_{}".format(sel_index)).cy())
|
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",
|
self.add_via_stack_center(from_layer="poly",
|
||||||
to_layer=self.sel_layer,
|
to_layer=self.sel_layer,
|
||||||
offset=offset,
|
offset=bl_offset,
|
||||||
directions=self.via_directions)
|
directions=self.via_directions)
|
||||||
self.add_path("poly", [offset, gate_offset])
|
self.add_path("poly", [offset, gate_offset, bl_offset])
|
||||||
|
|
||||||
def route_bitlines(self):
|
def route_bitlines(self):
|
||||||
""" Connect the output bit-lines to form the appropriate width mux """
|
""" Connect the output bit-lines to form the appropriate width mux """
|
||||||
|
|
|
||||||
|
|
@ -91,17 +91,13 @@ class control_logic(design.design):
|
||||||
rows=self.num_control_signals,
|
rows=self.num_control_signals,
|
||||||
columns=1)
|
columns=1)
|
||||||
|
|
||||||
self.add_mod(self.ctrl_dff_array)
|
|
||||||
|
|
||||||
self.and2 = factory.create(module_type="pand2",
|
self.and2 = factory.create(module_type="pand2",
|
||||||
size=12,
|
size=12,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.and2)
|
|
||||||
|
|
||||||
self.rbl_driver = factory.create(module_type="pbuf",
|
self.rbl_driver = factory.create(module_type="pbuf",
|
||||||
size=self.num_cols,
|
size=self.num_cols,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.rbl_driver)
|
|
||||||
|
|
||||||
# clk_buf drives a flop for every address
|
# clk_buf drives a flop for every address
|
||||||
addr_flops = math.log(self.num_words, 2) + math.log(self.words_per_row, 2)
|
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,
|
fanout=clock_fanout,
|
||||||
height=dff_height)
|
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
|
# We will use the maximum since this same value is used to size the wl_en
|
||||||
# and the p_en_bar drivers
|
# and the p_en_bar drivers
|
||||||
# max_fanout = max(self.num_rows, self.num_cols)
|
# 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",
|
self.wl_en_driver = factory.create(module_type="pdriver",
|
||||||
size_list=size_list,
|
size_list=size_list,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.wl_en_driver)
|
|
||||||
|
|
||||||
# w_en drives every write driver
|
# w_en drives every write driver
|
||||||
self.wen_and = factory.create(module_type="pand3",
|
self.wen_and = factory.create(module_type="pand3",
|
||||||
size=self.word_size + 8,
|
size=self.word_size + 8,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.wen_and)
|
|
||||||
|
|
||||||
# s_en drives every sense amp
|
# s_en drives every sense amp
|
||||||
self.sen_and3 = factory.create(module_type="pand3",
|
self.sen_and3 = factory.create(module_type="pand3",
|
||||||
size=self.word_size + self.num_spare_cols,
|
size=self.word_size + self.num_spare_cols,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.sen_and3)
|
|
||||||
|
|
||||||
# used to generate inverted signals with low fanout
|
# used to generate inverted signals with low fanout
|
||||||
self.inv = factory.create(module_type="pinv",
|
self.inv = factory.create(module_type="pinv",
|
||||||
size=1,
|
size=1,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
# p_en_bar drives every column in the bitcell array
|
# p_en_bar drives every column in the bitcell array
|
||||||
# but it is sized the same as the wl_en driver with
|
# 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",
|
self.p_en_bar_driver = factory.create(module_type="pdriver",
|
||||||
fanout=self.num_cols,
|
fanout=self.num_cols,
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.p_en_bar_driver)
|
|
||||||
|
|
||||||
self.nand2 = factory.create(module_type="pnand2",
|
self.nand2 = factory.create(module_type="pnand2",
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.nand2)
|
|
||||||
|
|
||||||
debug.check(OPTS.delay_chain_stages % 2,
|
debug.check(OPTS.delay_chain_stages % 2,
|
||||||
"Must use odd number of delay chain stages for inverting delay chain.")
|
"Must use odd number of delay chain stages for inverting delay chain.")
|
||||||
self.delay_chain=factory.create(module_type="delay_chain",
|
self.delay_chain=factory.create(module_type="delay_chain",
|
||||||
fanout_list = OPTS.delay_chain_stages * [ OPTS.delay_chain_fanout_per_stage ])
|
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):
|
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"""
|
"""Determine the size of the delay chain used for the Sense Amp Enable using path delays"""
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ class delay_chain(design.design):
|
||||||
self.height = self.rows * self.inv.height
|
self.height = self.rows * self.inv.height
|
||||||
# The width is determined by the largest fanout plus the driver
|
# The width is determined by the largest fanout plus the driver
|
||||||
self.width = (max(self.fanout_list) + 1) * self.inv.width
|
self.width = (max(self.fanout_list) + 1) * self.inv.width
|
||||||
|
|
||||||
self.place_inverters()
|
self.place_inverters()
|
||||||
self.route_inverters()
|
self.route_inverters()
|
||||||
self.route_supplies()
|
self.route_supplies()
|
||||||
|
|
@ -66,10 +66,9 @@ class delay_chain(design.design):
|
||||||
|
|
||||||
self.dff = factory.create(module_type="dff_buf")
|
self.dff = factory.create(module_type="dff_buf")
|
||||||
dff_height = self.dff.height
|
dff_height = self.dff.height
|
||||||
|
|
||||||
self.inv = factory.create(module_type="pinv",
|
self.inv = factory.create(module_type="pinv",
|
||||||
height=dff_height)
|
height=dff_height)
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_inverters(self):
|
def create_inverters(self):
|
||||||
""" Create the inverters and connect them based on the stage list """
|
""" Create the inverters and connect them based on the stage list """
|
||||||
|
|
@ -199,7 +198,7 @@ class delay_chain(design.design):
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=mid_loc)
|
offset=mid_loc)
|
||||||
self.add_path(a_pin.layer, [a_pin.center(), mid_loc])
|
self.add_path(a_pin.layer, [a_pin.center(), mid_loc])
|
||||||
|
|
||||||
self.add_layout_pin_rect_center(text="in",
|
self.add_layout_pin_rect_center(text="in",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
offset=mid_loc)
|
offset=mid_loc)
|
||||||
|
|
@ -213,4 +212,3 @@ class delay_chain(design.design):
|
||||||
self.add_layout_pin_rect_center(text="out",
|
self.add_layout_pin_rect_center(text="out",
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=a_pin.center())
|
offset=a_pin.center())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,6 @@ class dff_array(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.dff = factory.create(module_type="dff")
|
self.dff = factory.create(module_type="dff")
|
||||||
self.add_mod(self.dff)
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
|
|
|
||||||
|
|
@ -58,17 +58,14 @@ class dff_buf(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.dff = factory.create(module_type="dff")
|
self.dff = factory.create(module_type="dff")
|
||||||
self.add_mod(self.dff)
|
|
||||||
|
|
||||||
self.inv1 = factory.create(module_type="pinv",
|
self.inv1 = factory.create(module_type="pinv",
|
||||||
size=self.inv1_size,
|
size=self.inv1_size,
|
||||||
height=self.dff.height)
|
height=self.dff.height)
|
||||||
self.add_mod(self.inv1)
|
|
||||||
|
|
||||||
self.inv2 = factory.create(module_type="pinv",
|
self.inv2 = factory.create(module_type="pinv",
|
||||||
size=self.inv2_size,
|
size=self.inv2_size,
|
||||||
height=self.dff.height)
|
height=self.dff.height)
|
||||||
self.add_mod(self.inv2)
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"],
|
self.add_pin_list(["D", "Q", "Qb", "clk", "vdd", "gnd"],
|
||||||
|
|
@ -110,7 +107,7 @@ class dff_buf(design.design):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
well_spacing += 2 * self.well_extend_active
|
well_spacing += 2 * self.well_extend_active
|
||||||
|
|
||||||
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing, 0))
|
self.inv1_inst.place(vector(self.dff_inst.rx() + well_spacing, 0))
|
||||||
|
|
||||||
# Add INV2 to the right
|
# Add INV2 to the right
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,6 @@ class dff_buf_array(design.design):
|
||||||
self.dff = factory.create(module_type="dff_buf",
|
self.dff = factory.create(module_type="dff_buf",
|
||||||
inv1_size=self.inv1_size,
|
inv1_size=self.inv1_size,
|
||||||
inv2_size=self.inv2_size)
|
inv2_size=self.inv2_size)
|
||||||
self.add_mod(self.dff)
|
|
||||||
|
|
||||||
def create_dff_array(self):
|
def create_dff_array(self):
|
||||||
self.dff_insts={}
|
self.dff_insts={}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,10 @@
|
||||||
#
|
#
|
||||||
import debug
|
import debug
|
||||||
import design
|
import design
|
||||||
from tech import drc
|
|
||||||
from math import log
|
|
||||||
from vector import vector
|
from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from pinv import pinv
|
from sram_factory import factory
|
||||||
|
|
||||||
|
|
||||||
class dff_inv(design.design):
|
class dff_inv(design.design):
|
||||||
"""
|
"""
|
||||||
|
|
@ -66,12 +65,10 @@ class dff_inv(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.dff = dff_inv.dff_inv(self.inv_size)
|
self.dff = dff_inv.dff_inv(self.inv_size)
|
||||||
self.add_mod(self.dff)
|
|
||||||
|
|
||||||
self.inv1 = factory.create(module_type="pinv",
|
self.inv1 = factory.create(module_type="pinv",
|
||||||
size=self.inv_size,
|
size=self.inv_size,
|
||||||
height=self.dff.height)
|
height=self.dff.height)
|
||||||
self.add_mod(self.inv1)
|
|
||||||
|
|
||||||
def create_modules(self):
|
def create_modules(self):
|
||||||
self.dff_inst=self.add_inst(name="dff_inv_dff",
|
self.dff_inst=self.add_inst(name="dff_inv_dff",
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,6 @@ class dff_inv_array(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.dff = factory.create(module_type="dff")
|
self.dff = factory.create(module_type="dff")
|
||||||
self.add_mod(self.dff)
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
for row in range(self.rows):
|
for row in range(self.rows):
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@ class dummy_array(bitcell_base_array):
|
||||||
|
|
||||||
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
|
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
self.add_mod(self.dummy_cell)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" Create the module instances used in this design """
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
rbl=self.rbl,
|
rbl=self.rbl,
|
||||||
left_rbl=[0],
|
left_rbl=[0],
|
||||||
right_rbl=[1] if len(self.all_ports) > 1 else [])
|
right_rbl=[1] if len(self.all_ports) > 1 else [])
|
||||||
self.add_mod(la)
|
|
||||||
self.local_mods.append(la)
|
self.local_mods.append(la)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -90,7 +89,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
cols=cols,
|
cols=cols,
|
||||||
rbl=self.rbl)
|
rbl=self.rbl)
|
||||||
|
|
||||||
self.add_mod(la)
|
|
||||||
self.local_mods.append(la)
|
self.local_mods.append(la)
|
||||||
|
|
||||||
def add_pins(self):
|
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"""
|
"""Exclude dffs from graph as they do not represent critical path"""
|
||||||
|
|
||||||
self.graph_inst_exclude.add(self.ctrl_dff_inst)
|
self.graph_inst_exclude.add(self.ctrl_dff_inst)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,11 @@ class hierarchical_decoder(design.design):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.and2 = factory.create(module_type="and2_dec",
|
self.and2 = factory.create(module_type="and2_dec",
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.and2)
|
|
||||||
|
|
||||||
self.and3 = factory.create(module_type="and3_dec",
|
self.and3 = factory.create(module_type="and3_dec",
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.and3)
|
|
||||||
# TBD
|
# TBD
|
||||||
# self.and4 = factory.create(module_type="and4_dec")
|
# self.and4 = factory.create(module_type="and4_dec")
|
||||||
# self.add_mod(self.and4)
|
|
||||||
|
|
||||||
self.add_decoders()
|
self.add_decoders()
|
||||||
|
|
||||||
|
|
@ -84,15 +81,12 @@ class hierarchical_decoder(design.design):
|
||||||
""" Create the decoders based on the number of pre-decodes """
|
""" Create the decoders based on the number of pre-decodes """
|
||||||
self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
|
self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4",
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.pre2_4)
|
|
||||||
|
|
||||||
self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
|
self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8",
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.pre3_8)
|
|
||||||
|
|
||||||
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
|
self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16",
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.pre4_16)
|
|
||||||
|
|
||||||
def determine_predecodes(self, num_inputs):
|
def determine_predecodes(self, num_inputs):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ class hierarchical_predecode(design.design):
|
||||||
self.cell_height = b.height
|
self.cell_height = b.height
|
||||||
else:
|
else:
|
||||||
self.cell_height = height
|
self.cell_height = height
|
||||||
|
|
||||||
self.column_decoder = column_decoder
|
self.column_decoder = column_decoder
|
||||||
self.input_and_rail_pos = []
|
self.input_and_rail_pos = []
|
||||||
self.number_of_outputs = int(math.pow(2, self.number_of_inputs))
|
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"
|
inv_type = "inv_dec"
|
||||||
self.and_mod = factory.create(module_type=and_type,
|
self.and_mod = factory.create(module_type=and_type,
|
||||||
height=self.cell_height)
|
height=self.cell_height)
|
||||||
self.add_mod(self.and_mod)
|
|
||||||
|
|
||||||
# This uses the pinv_dec parameterized cell
|
# This uses the pinv_dec parameterized cell
|
||||||
self.inv = factory.create(module_type=inv_type,
|
self.inv = factory.create(module_type=inv_type,
|
||||||
height=self.cell_height,
|
height=self.cell_height,
|
||||||
size=1)
|
size=1)
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
""" The general organization is from left to right:
|
""" The general organization is from left to right:
|
||||||
|
|
@ -189,13 +187,13 @@ class hierarchical_predecode(design.design):
|
||||||
self.route_input_inverters()
|
self.route_input_inverters()
|
||||||
self.route_input_ands()
|
self.route_input_ands()
|
||||||
self.route_output_inverters()
|
self.route_output_inverters()
|
||||||
self.route_inputs_to_rails()
|
self.route_inputs_to_rails()
|
||||||
self.route_output_ands()
|
self.route_output_ands()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
|
|
||||||
def route_inputs_to_rails(self):
|
def route_inputs_to_rails(self):
|
||||||
""" Route the uninverted inputs to the second set of rails """
|
""" Route the uninverted inputs to the second set of rails """
|
||||||
|
|
||||||
top_and_gate = self.and_inst[-1]
|
top_and_gate = self.and_inst[-1]
|
||||||
for num in range(self.number_of_inputs):
|
for num in range(self.number_of_inputs):
|
||||||
if num == 0:
|
if num == 0:
|
||||||
|
|
@ -221,7 +219,7 @@ class hierarchical_predecode(design.design):
|
||||||
to_layer=self.bus_layer,
|
to_layer=self.bus_layer,
|
||||||
offset=[self.input_rails[in_pin].cx(), y_offset],
|
offset=[self.input_rails[in_pin].cx(), y_offset],
|
||||||
directions= ("H", "H"))
|
directions= ("H", "H"))
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=self.input_layer,
|
self.add_via_stack_center(from_layer=self.input_layer,
|
||||||
to_layer=self.bus_layer,
|
to_layer=self.bus_layer,
|
||||||
offset=[self.decode_rails[a_pin].cx(), y_offset],
|
offset=[self.decode_rails[a_pin].cx(), y_offset],
|
||||||
|
|
@ -306,7 +304,7 @@ class hierarchical_predecode(design.design):
|
||||||
else: # grow the stack down
|
else: # grow the stack down
|
||||||
search_id = 2
|
search_id = 2
|
||||||
next_id = 0
|
next_id = 0
|
||||||
|
|
||||||
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
|
curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None)
|
||||||
|
|
||||||
via = factory.create(module_type="contact",
|
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.
|
Route the different permutations of the NAND/AND decocer cells.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# This 2D array defines the connection mapping
|
# This 2D array defines the connection mapping
|
||||||
and_input_line_combination = self.get_and_input_line_combination()
|
and_input_line_combination = self.get_and_input_line_combination()
|
||||||
for k in range(self.number_of_outputs):
|
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]:
|
self.and_inst[0].lx() - self.bus_space]:
|
||||||
pin_pos = vector(xoffset, and_pin.cy())
|
pin_pos = vector(xoffset, and_pin.cy())
|
||||||
self.copy_power_pin(and_pin, loc=pin_pos)
|
self.copy_power_pin(and_pin, loc=pin_pos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array):
|
||||||
rbl=self.rbl,
|
rbl=self.rbl,
|
||||||
left_rbl=self.left_rbl,
|
left_rbl=self.left_rbl,
|
||||||
right_rbl=self.right_rbl)
|
right_rbl=self.right_rbl)
|
||||||
self.add_mod(self.bitcell_array)
|
|
||||||
|
|
||||||
self.wl_array = factory.create(module_type="wordline_buffer_array",
|
self.wl_array = factory.create(module_type="wordline_buffer_array",
|
||||||
rows=self.rows + 1,
|
rows=self.rows + 1,
|
||||||
cols=self.cols)
|
cols=self.cols)
|
||||||
self.add_mod(self.wl_array)
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
# Outputs from the wordline driver (by port)
|
# Outputs from the wordline driver (by port)
|
||||||
|
|
|
||||||
|
|
@ -172,47 +172,36 @@ class multibank(design.design):
|
||||||
|
|
||||||
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
|
self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols,
|
||||||
rows=self.num_rows)
|
rows=self.num_rows)
|
||||||
self.add_mod(self.bitcell_array)
|
|
||||||
|
|
||||||
self.precharge_array = self.mod_precharge_array(columns=self.num_cols)
|
self.precharge_array = self.mod_precharge_array(columns=self.num_cols)
|
||||||
self.add_mod(self.precharge_array)
|
|
||||||
|
|
||||||
if self.col_addr_size > 0:
|
if self.col_addr_size > 0:
|
||||||
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
|
self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols,
|
||||||
word_size=self.word_size)
|
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,
|
self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size,
|
||||||
words_per_row=self.words_per_row)
|
words_per_row=self.words_per_row)
|
||||||
self.add_mod(self.sense_amp_array)
|
|
||||||
|
|
||||||
if self.write_size:
|
if self.write_size:
|
||||||
self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
|
self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
write_size=self.write_size)
|
write_size=self.write_size)
|
||||||
self.add_mod(self.write_mask_driver_array)
|
|
||||||
else:
|
else:
|
||||||
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
|
self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols,
|
||||||
word_size=self.word_size)
|
word_size=self.word_size)
|
||||||
self.add_mod(self.write_driver_array)
|
|
||||||
|
|
||||||
self.row_decoder = self.mod_decoder(rows=self.num_rows)
|
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,
|
self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols,
|
||||||
word_size=self.word_size)
|
word_size=self.word_size)
|
||||||
self.add_mod(self.tri_gate_array)
|
|
||||||
|
|
||||||
self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows)
|
self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows)
|
||||||
self.add_mod(self.wordline_driver)
|
|
||||||
|
|
||||||
self.inv = pinv()
|
self.inv = pinv()
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
self.bank_select = self.mod_bank_select()
|
self.bank_select = self.mod_bank_select()
|
||||||
self.add_mod(self.bank_select)
|
|
||||||
|
|
||||||
|
|
||||||
def add_bitcell_array(self):
|
def add_bitcell_array(self):
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,6 @@ class bitcell_array(bitcell_base_array):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
self.add_mod(self.cell)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" Create the module instances used in this design """
|
||||||
|
|
|
||||||
|
|
@ -145,12 +145,10 @@ class port_address(design.design):
|
||||||
|
|
||||||
self.row_decoder = factory.create(module_type="decoder",
|
self.row_decoder = factory.create(module_type="decoder",
|
||||||
num_outputs=self.num_rows)
|
num_outputs=self.num_rows)
|
||||||
self.add_mod(self.row_decoder)
|
|
||||||
|
|
||||||
self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
|
self.wordline_driver_array = factory.create(module_type="wordline_driver_array",
|
||||||
rows=self.num_rows,
|
rows=self.num_rows,
|
||||||
cols=self.num_cols)
|
cols=self.num_cols)
|
||||||
self.add_mod(self.wordline_driver_array)
|
|
||||||
|
|
||||||
local_array_size = OPTS.local_array_size
|
local_array_size = OPTS.local_array_size
|
||||||
if local_array_size > 0:
|
if local_array_size > 0:
|
||||||
|
|
@ -174,8 +172,6 @@ class port_address(design.design):
|
||||||
size=driver_size,
|
size=driver_size,
|
||||||
height=b.height)
|
height=b.height)
|
||||||
|
|
||||||
self.add_mod(self.rbl_driver)
|
|
||||||
|
|
||||||
def create_row_decoder(self):
|
def create_row_decoder(self):
|
||||||
""" Create the hierarchical row decoder """
|
""" 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
|
# 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")
|
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
|
x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width
|
||||||
|
|
||||||
if self.port == 0:
|
if self.port == 0:
|
||||||
rbl_driver_offset = vector(x_offset,
|
rbl_driver_offset = vector(x_offset,
|
||||||
0)
|
0)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class port_data(design.design):
|
||||||
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
self.num_wmasks = int(math.ceil(self.word_size / self.write_size))
|
||||||
else:
|
else:
|
||||||
self.num_wmasks = 0
|
self.num_wmasks = 0
|
||||||
|
|
||||||
if num_spare_cols is not None:
|
if num_spare_cols is not None:
|
||||||
self.num_spare_cols = num_spare_cols + self.num_spare_cols
|
self.num_spare_cols = num_spare_cols + self.num_spare_cols
|
||||||
if self.num_spare_cols is None:
|
if self.num_spare_cols is None:
|
||||||
|
|
@ -215,7 +215,6 @@ class port_data(design.design):
|
||||||
bitcell_bl=self.bl_names[self.port],
|
bitcell_bl=self.bl_names[self.port],
|
||||||
bitcell_br=self.br_names[self.port],
|
bitcell_br=self.br_names[self.port],
|
||||||
column_offset=self.port - 1)
|
column_offset=self.port - 1)
|
||||||
self.add_mod(self.precharge_array)
|
|
||||||
|
|
||||||
if self.port in self.read_ports:
|
if self.port in self.read_ports:
|
||||||
# RBLs don't get a sense amp
|
# RBLs don't get a sense amp
|
||||||
|
|
@ -224,7 +223,6 @@ class port_data(design.design):
|
||||||
offsets=self.bit_offsets,
|
offsets=self.bit_offsets,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
num_spare_cols=self.num_spare_cols)
|
num_spare_cols=self.num_spare_cols)
|
||||||
self.add_mod(self.sense_amp_array)
|
|
||||||
else:
|
else:
|
||||||
self.sense_amp_array = None
|
self.sense_amp_array = None
|
||||||
|
|
||||||
|
|
@ -236,7 +234,6 @@ class port_data(design.design):
|
||||||
offsets=self.bit_offsets,
|
offsets=self.bit_offsets,
|
||||||
bitcell_bl=self.bl_names[self.port],
|
bitcell_bl=self.bl_names[self.port],
|
||||||
bitcell_br=self.br_names[self.port])
|
bitcell_br=self.br_names[self.port])
|
||||||
self.add_mod(self.column_mux_array)
|
|
||||||
else:
|
else:
|
||||||
self.column_mux_array = None
|
self.column_mux_array = None
|
||||||
|
|
||||||
|
|
@ -248,7 +245,6 @@ class port_data(design.design):
|
||||||
offsets=self.bit_offsets,
|
offsets=self.bit_offsets,
|
||||||
write_size=self.write_size,
|
write_size=self.write_size,
|
||||||
num_spare_cols=self.num_spare_cols)
|
num_spare_cols=self.num_spare_cols)
|
||||||
self.add_mod(self.write_driver_array)
|
|
||||||
if self.write_size is not None:
|
if self.write_size is not None:
|
||||||
# RBLs don't get a write mask
|
# RBLs don't get a write mask
|
||||||
self.write_mask_and_array = factory.create(module_type="write_mask_and_array",
|
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,
|
offsets=self.bit_offsets,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
write_size=self.write_size)
|
write_size=self.write_size)
|
||||||
self.add_mod(self.write_mask_and_array)
|
|
||||||
else:
|
else:
|
||||||
self.write_mask_and_array = None
|
self.write_mask_and_array = None
|
||||||
|
|
||||||
|
|
@ -858,10 +853,10 @@ class port_data(design.design):
|
||||||
"""
|
"""
|
||||||
if self.column_mux_array:
|
if self.column_mux_array:
|
||||||
self.column_mux_array.graph_exclude_columns(column_include_num)
|
self.column_mux_array.graph_exclude_columns(column_include_num)
|
||||||
|
|
||||||
def graph_clear_column_mux(self):
|
def graph_clear_column_mux(self):
|
||||||
"""
|
"""
|
||||||
Clear mux exclusions to allow different bit tests.
|
Clear mux exclusions to allow different bit tests.
|
||||||
"""
|
"""
|
||||||
if self.column_mux_array:
|
if self.column_mux_array:
|
||||||
self.column_mux_array.init_graph_params()
|
self.column_mux_array.init_graph_params()
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,7 @@ class precharge_array(design.design):
|
||||||
size=self.size,
|
size=self.size,
|
||||||
bitcell_bl=self.bitcell_bl,
|
bitcell_bl=self.bitcell_bl,
|
||||||
bitcell_br=self.bitcell_br)
|
bitcell_br=self.bitcell_br)
|
||||||
|
|
||||||
self.add_mod(self.pc_cell)
|
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
|
|
||||||
def add_layout_pins(self):
|
def add_layout_pins(self):
|
||||||
|
|
@ -130,5 +129,3 @@ class precharge_array(design.design):
|
||||||
|
|
||||||
offset = vector(tempx, 0)
|
offset = vector(tempx, 0)
|
||||||
self.local_insts[i].place(offset=offset, mirror=mirror)
|
self.local_insts[i].place(offset=offset, mirror=mirror)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,7 +110,6 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
column_offset=1 + len(self.left_rbl),
|
column_offset=1 + len(self.left_rbl),
|
||||||
cols=self.column_size,
|
cols=self.column_size,
|
||||||
rows=self.row_size)
|
rows=self.row_size)
|
||||||
self.add_mod(self.bitcell_array)
|
|
||||||
|
|
||||||
# Replica bitlines
|
# Replica bitlines
|
||||||
self.replica_columns = {}
|
self.replica_columns = {}
|
||||||
|
|
@ -138,7 +137,6 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
rbl=self.rbl,
|
rbl=self.rbl,
|
||||||
column_offset=column_offset,
|
column_offset=column_offset,
|
||||||
replica_bit=replica_bit)
|
replica_bit=replica_bit)
|
||||||
self.add_mod(self.replica_columns[port])
|
|
||||||
|
|
||||||
# Dummy row
|
# Dummy row
|
||||||
self.dummy_row = factory.create(module_type="dummy_array",
|
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
|
# dummy column + left replica column
|
||||||
column_offset=1 + len(self.left_rbl),
|
column_offset=1 + len(self.left_rbl),
|
||||||
mirror=0)
|
mirror=0)
|
||||||
self.add_mod(self.dummy_row)
|
|
||||||
|
|
||||||
# Dummy Row or Col Cap, depending on bitcell array properties
|
# 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")
|
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),
|
column_offset=1 + len(self.left_rbl),
|
||||||
mirror=0,
|
mirror=0,
|
||||||
location="top")
|
location="top")
|
||||||
self.add_mod(self.col_cap_top)
|
|
||||||
|
|
||||||
self.col_cap_bottom = factory.create(module_type=col_cap_module_type,
|
self.col_cap_bottom = factory.create(module_type=col_cap_module_type,
|
||||||
cols=self.column_size,
|
cols=self.column_size,
|
||||||
|
|
@ -167,7 +163,6 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
column_offset=1 + len(self.left_rbl),
|
column_offset=1 + len(self.left_rbl),
|
||||||
mirror=0,
|
mirror=0,
|
||||||
location="bottom")
|
location="bottom")
|
||||||
self.add_mod(self.col_cap_bottom)
|
|
||||||
|
|
||||||
# Dummy Col or Row Cap, depending on bitcell array properties
|
# 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")
|
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,
|
column_offset=0,
|
||||||
rows=self.row_size + self.extra_rows,
|
rows=self.row_size + self.extra_rows,
|
||||||
mirror=(self.rbl[0] + 1) % 2)
|
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,
|
self.row_cap_right = factory.create(module_type=row_cap_module_type,
|
||||||
cols=1,
|
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],
|
column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0],
|
||||||
rows=self.row_size + self.extra_rows,
|
rows=self.row_size + self.extra_rows,
|
||||||
mirror=(self.rbl[0] + 1) %2)
|
mirror=(self.rbl[0] + 1) %2)
|
||||||
self.add_mod(self.row_cap_right)
|
|
||||||
|
|
||||||
def add_pins(self):
|
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()
|
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,
|
self.dummy_row_insts[1].place(offset=dummy_row_offset,
|
||||||
mirror="MX" if flip_dummy else "R0")
|
mirror="MX" if flip_dummy else "R0")
|
||||||
|
|
||||||
# Far bottom dummy row (first row below array IS flipped)
|
# Far bottom dummy row (first row below array IS flipped)
|
||||||
flip_dummy = (self.rbl[0] + 1) % 2
|
flip_dummy = (self.rbl[0] + 1) % 2
|
||||||
dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset
|
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
|
# 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
|
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)
|
self.dummy_col_insts[0].place(offset=dummy_col_offset)
|
||||||
|
|
||||||
# Far right dummy col
|
# Far right dummy col
|
||||||
# Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell 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.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr()
|
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),
|
offset=pin.ll().scale(0, 1),
|
||||||
width=self.width,
|
width=self.width,
|
||||||
height=pin.height())
|
height=pin.height())
|
||||||
|
|
||||||
# Replica wordlines (go by the row instead of replica column because we may have to add a pin
|
# 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)
|
# even though the column is in another local bitcell array)
|
||||||
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
|
for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts):
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ class replica_column(bitcell_base_array):
|
||||||
self.left_rbl = rbl[0]
|
self.left_rbl = rbl[0]
|
||||||
self.right_rbl = rbl[1]
|
self.right_rbl = rbl[1]
|
||||||
self.replica_bit = replica_bit
|
self.replica_bit = replica_bit
|
||||||
|
|
||||||
# Total size includes the replica rows and column cap rows
|
# Total size includes the replica rows and column cap rows
|
||||||
self.total_size = self.left_rbl + rows + self.right_rbl + 2
|
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):
|
def create_layout(self):
|
||||||
self.place_instances()
|
self.place_instances()
|
||||||
|
|
||||||
self.height = self.cell_inst[-1].uy()
|
self.height = self.cell_inst[-1].uy()
|
||||||
self.width = self.cell_inst[0].rx()
|
self.width = self.cell_inst[0].rx()
|
||||||
|
|
||||||
|
|
@ -85,15 +85,14 @@ class replica_column(bitcell_base_array):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.replica_cell = factory.create(module_type=OPTS.replica_bitcell)
|
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.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell)
|
||||||
self.add_mod(self.dummy_cell)
|
|
||||||
try:
|
try:
|
||||||
edge_module_type = ("col_cap" if self.cell.end_caps else "dummy")
|
edge_module_type = ("col_cap" if self.cell.end_caps else "dummy")
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
edge_module_type = "dummy"
|
edge_module_type = "dummy"
|
||||||
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
|
self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell)
|
||||||
self.add_mod(self.edge_cell)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
self.cell_inst = []
|
self.cell_inst = []
|
||||||
|
|
@ -103,7 +102,7 @@ class replica_column(bitcell_base_array):
|
||||||
real_row = row
|
real_row = row
|
||||||
if self.cell.end_caps:
|
if self.cell.end_caps:
|
||||||
real_row -= 1
|
real_row -= 1
|
||||||
|
|
||||||
# Regular array cells are replica cells
|
# Regular array cells are replica cells
|
||||||
# Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell.
|
# 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):
|
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):
|
for row, cell in enumerate(self.cell_inst):
|
||||||
if row != self.replica_bit:
|
if row != self.replica_bit:
|
||||||
self.graph_inst_exclude.add(cell)
|
self.graph_inst_exclude.add(cell)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,13 @@ class row_cap_array(bitcell_base_array):
|
||||||
|
|
||||||
self.width = max([x.rx() for x in self.insts])
|
self.width = max([x.rx() for x in self.insts])
|
||||||
self.height = max([x.uy() for x in self.insts])
|
self.height = max([x.uy() for x in self.insts])
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
|
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)
|
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_name in ["vdd", "gnd"]:
|
||||||
for pin in inst.get_pins(pin_name):
|
for pin in inst.get_pins(pin_name):
|
||||||
self.copy_power_pin(pin)
|
self.copy_power_pin(pin)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,6 @@ class sense_amp_array(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.amp = factory.create(module_type="sense_amp")
|
self.amp = factory.create(module_type="sense_amp")
|
||||||
self.add_mod(self.amp)
|
|
||||||
|
|
||||||
# This is just used for measurements,
|
# This is just used for measurements,
|
||||||
# so don't add the module
|
# so don't add the module
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ class tri_gate_array(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.tri = factory.create(module_type="tri_gate")
|
self.tri = factory.create(module_type="tri_gate")
|
||||||
self.add_mod(self.tri)
|
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
"""create the name of pins depend on the word size"""
|
"""create the name of pins depend on the word size"""
|
||||||
|
|
@ -120,4 +119,4 @@ class tri_gate_array(design.design):
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=enbar_pin.ll().scale(0, 1),
|
offset=enbar_pin.ll().scale(0, 1),
|
||||||
width=width,
|
width=width,
|
||||||
height=drc("minwidth_m1"))
|
height=drc("minwidth_m1"))
|
||||||
|
|
|
||||||
|
|
@ -64,7 +64,6 @@ class wordline_buffer_array(design.design):
|
||||||
self.wl_driver = factory.create(module_type="inv_dec",
|
self.wl_driver = factory.create(module_type="inv_dec",
|
||||||
size=self.cols,
|
size=self.cols,
|
||||||
height=b.height)
|
height=b.height)
|
||||||
self.add_mod(self.wl_driver)
|
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,6 @@ class wordline_driver_array(design.design):
|
||||||
self.wl_driver = factory.create(module_type="wordline_driver",
|
self.wl_driver = factory.create(module_type="wordline_driver",
|
||||||
cols=self.cols)
|
cols=self.cols)
|
||||||
|
|
||||||
self.add_mod(self.wl_driver)
|
|
||||||
|
|
||||||
def route_vdd_gnd(self):
|
def route_vdd_gnd(self):
|
||||||
"""
|
"""
|
||||||
Add a pin for each row of vdd/gnd which
|
Add a pin for each row of vdd/gnd which
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,6 @@ class write_driver_array(design.design):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.driver = factory.create(module_type="write_driver")
|
self.driver = factory.create(module_type="write_driver")
|
||||||
self.add_mod(self.driver)
|
|
||||||
|
|
||||||
# This is just used for measurements,
|
# This is just used for measurements,
|
||||||
# so don't add the module
|
# so don't add the module
|
||||||
|
|
@ -259,4 +258,3 @@ class write_driver_array(design.design):
|
||||||
layer="m1",
|
layer="m1",
|
||||||
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1),
|
||||||
width=self.width)
|
width=self.width)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ class write_mask_and_array(design.design):
|
||||||
# Assume stage effort of 3 to compute the size
|
# Assume stage effort of 3 to compute the size
|
||||||
self.and2 = factory.create(module_type="pand2",
|
self.and2 = factory.create(module_type="pand2",
|
||||||
size=max(self.write_size / 4.0, 1))
|
size=max(self.write_size / 4.0, 1))
|
||||||
self.add_mod(self.and2)
|
|
||||||
|
|
||||||
def create_and2_array(self):
|
def create_and2_array(self):
|
||||||
self.and2_insts = {}
|
self.and2_insts = {}
|
||||||
|
|
@ -146,7 +145,7 @@ class write_mask_and_array(design.design):
|
||||||
self.add_via_stack_center(from_layer=supply_pin.layer,
|
self.add_via_stack_center(from_layer=supply_pin.layer,
|
||||||
to_layer="m1",
|
to_layer="m1",
|
||||||
offset=supply_pin.center())
|
offset=supply_pin.center())
|
||||||
|
|
||||||
for supply in ["gnd", "vdd"]:
|
for supply in ["gnd", "vdd"]:
|
||||||
supply_pin = self.and2_insts[0].get_pin(supply)
|
supply_pin = self.and2_insts[0].get_pin(supply)
|
||||||
supply_pin_yoffset = supply_pin.cy()
|
supply_pin_yoffset = supply_pin.cy()
|
||||||
|
|
@ -158,4 +157,3 @@ class write_mask_and_array(design.design):
|
||||||
to_layer="m1",
|
to_layer="m1",
|
||||||
offset=loc)
|
offset=loc)
|
||||||
self.copy_power_pin(supply_pin, loc=loc)
|
self.copy_power_pin(supply_pin, loc=loc)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ class column_mux(pgate.pgate):
|
||||||
self.ptx_width = self.tx_size * drc("minwidth_tx")
|
self.ptx_width = self.tx_size * drc("minwidth_tx")
|
||||||
self.nmos = factory.create(module_type="ptx",
|
self.nmos = factory.create(module_type="ptx",
|
||||||
width=self.ptx_width)
|
width=self.ptx_width)
|
||||||
self.add_mod(self.nmos)
|
|
||||||
|
|
||||||
# Space it in the center
|
# Space it in the center
|
||||||
self.nmos_lower = self.add_inst(name="mux_tx1",
|
self.nmos_lower = self.add_inst(name="mux_tx1",
|
||||||
|
|
|
||||||
|
|
@ -39,9 +39,6 @@ class pand2(pgate.pgate):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
add_wells=self.add_wells)
|
add_wells=self.add_wells)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
if self.vertical:
|
if self.vertical:
|
||||||
self.height = 2 * self.nand.height
|
self.height = 2 * self.nand.height
|
||||||
|
|
@ -146,8 +143,8 @@ class pand2(pgate.pgate):
|
||||||
offset=pin.center(),
|
offset=pin.center(),
|
||||||
width=pin.width(),
|
width=pin.width(),
|
||||||
height=pin.height())
|
height=pin.height())
|
||||||
|
|
||||||
def is_non_inverting(self):
|
def is_non_inverting(self):
|
||||||
"""Return input to output polarity for module"""
|
"""Return input to output polarity for module"""
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ class pand3(pgate.pgate):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
add_wells=self.add_wells)
|
add_wells=self.add_wells)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
if self.vertical:
|
if self.vertical:
|
||||||
self.height = 2 * self.nand.height
|
self.height = 2 * self.nand.height
|
||||||
|
|
|
||||||
|
|
@ -43,9 +43,6 @@ class pand4(pgate.pgate):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
add_wells=self.add_wells)
|
add_wells=self.add_wells)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
if self.vertical:
|
if self.vertical:
|
||||||
self.height = 2 * self.nand.height
|
self.height = 2 * self.nand.height
|
||||||
|
|
@ -162,4 +159,3 @@ class pand4(pgate.pgate):
|
||||||
slew=nand_delay.slew,
|
slew=nand_delay.slew,
|
||||||
load=load)
|
load=load)
|
||||||
return nand_delay + inv_delay
|
return nand_delay + inv_delay
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,13 +52,11 @@ class pbuf(pgate.pgate):
|
||||||
self.inv1 = factory.create(module_type="pinv",
|
self.inv1 = factory.create(module_type="pinv",
|
||||||
size=input_size,
|
size=input_size,
|
||||||
height=self.height)
|
height=self.height)
|
||||||
self.add_mod(self.inv1)
|
|
||||||
|
|
||||||
self.inv2 = factory.create(module_type="pinv",
|
self.inv2 = factory.create(module_type="pinv",
|
||||||
size=self.size,
|
size=self.size,
|
||||||
height=self.height,
|
height=self.height,
|
||||||
add_wells=False)
|
add_wells=False)
|
||||||
self.add_mod(self.inv2)
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
self.inv1_inst = self.add_inst(name="buf_inv1",
|
self.inv1_inst = self.add_inst(name="buf_inv1",
|
||||||
|
|
@ -96,4 +94,3 @@ class pbuf(pgate.pgate):
|
||||||
offset=a_pin.center(),
|
offset=a_pin.center(),
|
||||||
width=a_pin.width(),
|
width=a_pin.width(),
|
||||||
height=a_pin.height())
|
height=a_pin.height())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,12 +52,10 @@ class pbuf_dec(pgate.pgate):
|
||||||
self.inv1 = factory.create(module_type="pinv_dec",
|
self.inv1 = factory.create(module_type="pinv_dec",
|
||||||
size=input_size,
|
size=input_size,
|
||||||
height=self.height)
|
height=self.height)
|
||||||
self.add_mod(self.inv1)
|
|
||||||
|
|
||||||
self.inv2 = factory.create(module_type="pinv_dec",
|
self.inv2 = factory.create(module_type="pinv_dec",
|
||||||
size=self.size,
|
size=self.size,
|
||||||
height=self.height)
|
height=self.height)
|
||||||
self.add_mod(self.inv2)
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
self.inv1_inst = self.add_inst(name="buf_inv1",
|
self.inv1_inst = self.add_inst(name="buf_inv1",
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,6 @@ class pdriver(pgate.pgate):
|
||||||
height=self.height,
|
height=self.height,
|
||||||
add_wells=self.add_wells)
|
add_wells=self.add_wells)
|
||||||
self.inv_list.append(temp_inv)
|
self.inv_list.append(temp_inv)
|
||||||
self.add_mod(temp_inv)
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
self.inv_inst_list = []
|
self.inv_inst_list = []
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,6 @@ class pinv(pgate.pgate):
|
||||||
add_drain_contact=self.route_layer,
|
add_drain_contact=self.route_layer,
|
||||||
connect_poly=True,
|
connect_poly=True,
|
||||||
connect_drain_active=True)
|
connect_drain_active=True)
|
||||||
self.add_mod(self.nmos)
|
|
||||||
|
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -217,7 +216,6 @@ class pinv(pgate.pgate):
|
||||||
add_drain_contact=self.route_layer,
|
add_drain_contact=self.route_layer,
|
||||||
connect_poly=True,
|
connect_poly=True,
|
||||||
connect_drain_active=True)
|
connect_drain_active=True)
|
||||||
self.add_mod(self.pmos)
|
|
||||||
|
|
||||||
def create_ptx(self):
|
def create_ptx(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -337,30 +335,29 @@ class pinv(pgate.pgate):
|
||||||
Overrides base class function.
|
Overrides base class function.
|
||||||
"""
|
"""
|
||||||
self.add_graph_edges(graph, port_nets)
|
self.add_graph_edges(graph, port_nets)
|
||||||
|
|
||||||
def is_non_inverting(self):
|
def is_non_inverting(self):
|
||||||
"""Return input to output polarity for module"""
|
"""Return input to output polarity for module"""
|
||||||
|
return False
|
||||||
return False
|
|
||||||
|
|
||||||
def get_on_resistance(self):
|
def get_on_resistance(self):
|
||||||
"""On resistance of pinv, defined by single nmos"""
|
"""On resistance of pinv, defined by single nmos"""
|
||||||
is_nchannel = True
|
is_nchannel = True
|
||||||
stack = 1
|
stack = 1
|
||||||
is_cell = False
|
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):
|
def get_input_capacitance(self):
|
||||||
"""Input cap of input, passes width of gates to gate cap function"""
|
"""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):
|
def get_intrinsic_capacitance(self):
|
||||||
"""Get the drain capacitances of the TXs in the gate."""
|
"""Get the drain capacitances of the TXs in the gate."""
|
||||||
nmos_stack = 1
|
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,
|
nmos_stack,
|
||||||
self.tx_mults)
|
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,
|
1,
|
||||||
self.tx_mults)
|
self.tx_mults)
|
||||||
return nmos_drain_c + pmos_drain_c
|
return nmos_drain_c + pmos_drain_c
|
||||||
|
|
|
||||||
|
|
@ -65,17 +65,14 @@ class pinvbuf(pgate.pgate):
|
||||||
self.inv = factory.create(module_type="pinv",
|
self.inv = factory.create(module_type="pinv",
|
||||||
size=input_size,
|
size=input_size,
|
||||||
height=self.row_height)
|
height=self.row_height)
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
self.inv1 = factory.create(module_type="pinv",
|
self.inv1 = factory.create(module_type="pinv",
|
||||||
size=self.predriver_size,
|
size=self.predriver_size,
|
||||||
height=self.row_height)
|
height=self.row_height)
|
||||||
self.add_mod(self.inv1)
|
|
||||||
|
|
||||||
self.inv2 = factory.create(module_type="pinv",
|
self.inv2 = factory.create(module_type="pinv",
|
||||||
size=self.size,
|
size=self.size,
|
||||||
height=self.row_height)
|
height=self.row_height)
|
||||||
self.add_mod(self.inv2)
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
# Create INV1 (capacitance shield)
|
# Create INV1 (capacitance shield)
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ class pnand2(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.nmos_left)
|
|
||||||
|
|
||||||
self.nmos_right = factory.create(module_type="ptx",
|
self.nmos_right = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -87,7 +86,6 @@ class pnand2(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.nmos_right)
|
|
||||||
|
|
||||||
self.pmos_left = factory.create(module_type="ptx",
|
self.pmos_left = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -95,7 +93,6 @@ class pnand2(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_left)
|
|
||||||
|
|
||||||
self.pmos_right = factory.create(module_type="ptx",
|
self.pmos_right = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -103,7 +100,6 @@ class pnand2(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_right)
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Pre-compute some handy layout parameters. """
|
""" Pre-compute some handy layout parameters. """
|
||||||
|
|
@ -317,28 +313,26 @@ class pnand2(pgate.pgate):
|
||||||
|
|
||||||
def is_non_inverting(self):
|
def is_non_inverting(self):
|
||||||
"""Return input to output polarity for module"""
|
"""Return input to output polarity for module"""
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_on_resistance(self):
|
def get_on_resistance(self):
|
||||||
"""On resistance of pnand, defined by stacked NMOS"""
|
"""On resistance of pnand, defined by stacked NMOS"""
|
||||||
is_nchannel = True
|
is_nchannel = True
|
||||||
stack = 2
|
stack = 2
|
||||||
is_cell = False
|
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):
|
def get_input_capacitance(self):
|
||||||
"""Input cap of input, passes width of gates to gate cap function"""
|
"""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):
|
def get_intrinsic_capacitance(self):
|
||||||
"""Get the drain capacitances of the TXs in the gate."""
|
"""Get the drain capacitances of the TXs in the gate."""
|
||||||
nmos_stack = 2
|
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,
|
nmos_stack,
|
||||||
self.tx_mults)
|
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,
|
1,
|
||||||
self.tx_mults)
|
self.tx_mults)
|
||||||
return nmos_drain_c + pmos_drain_c
|
return nmos_drain_c + pmos_drain_c
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.nmos_center)
|
|
||||||
|
|
||||||
self.nmos_right = factory.create(module_type="ptx",
|
self.nmos_right = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -90,7 +89,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.nmos_right)
|
|
||||||
|
|
||||||
self.nmos_left = factory.create(module_type="ptx",
|
self.nmos_left = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -98,7 +96,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.nmos_left)
|
|
||||||
|
|
||||||
self.pmos_left = factory.create(module_type="ptx",
|
self.pmos_left = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -106,7 +103,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_left)
|
|
||||||
|
|
||||||
self.pmos_center = factory.create(module_type="ptx",
|
self.pmos_center = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -114,7 +110,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_center)
|
|
||||||
|
|
||||||
self.pmos_right = factory.create(module_type="ptx",
|
self.pmos_right = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -122,7 +117,6 @@ class pnand3(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_right)
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Pre-compute some handy layout parameters. """
|
""" Pre-compute some handy layout parameters. """
|
||||||
|
|
@ -350,27 +344,26 @@ class pnand3(pgate.pgate):
|
||||||
|
|
||||||
def is_non_inverting(self):
|
def is_non_inverting(self):
|
||||||
"""Return input to output polarity for module"""
|
"""Return input to output polarity for module"""
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_on_resistance(self):
|
def get_on_resistance(self):
|
||||||
"""On resistance of pnand, defined by stacked NMOS"""
|
"""On resistance of pnand, defined by stacked NMOS"""
|
||||||
is_nchannel = True
|
is_nchannel = True
|
||||||
stack = 3
|
stack = 3
|
||||||
is_cell = False
|
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):
|
def get_input_capacitance(self):
|
||||||
"""Input cap of input, passes width of gates to gate cap function"""
|
"""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):
|
def get_intrinsic_capacitance(self):
|
||||||
"""Get the drain capacitances of the TXs in the gate."""
|
"""Get the drain capacitances of the TXs in the gate."""
|
||||||
nmos_stack = 3
|
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,
|
nmos_stack,
|
||||||
self.tx_mults)
|
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,
|
1,
|
||||||
self.tx_mults)
|
self.tx_mults)
|
||||||
return nmos_drain_c + pmos_drain_c
|
return nmos_drain_c + pmos_drain_c
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.nmos_center)
|
|
||||||
|
|
||||||
self.nmos_right = factory.create(module_type="ptx",
|
self.nmos_right = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -90,7 +89,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.nmos_right)
|
|
||||||
|
|
||||||
self.nmos_left = factory.create(module_type="ptx",
|
self.nmos_left = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -98,7 +96,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.nmos_left)
|
|
||||||
|
|
||||||
self.pmos_left = factory.create(module_type="ptx",
|
self.pmos_left = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -106,7 +103,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_left)
|
|
||||||
|
|
||||||
self.pmos_center = factory.create(module_type="ptx",
|
self.pmos_center = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -114,7 +110,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_center)
|
|
||||||
|
|
||||||
self.pmos_right = factory.create(module_type="ptx",
|
self.pmos_right = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -122,7 +117,6 @@ class pnand4(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_right)
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Pre-compute some handy layout parameters. """
|
""" Pre-compute some handy layout parameters. """
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@ class pnor2(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.nmos_left)
|
|
||||||
|
|
||||||
self.nmos_right = factory.create(module_type="ptx",
|
self.nmos_right = factory.create(module_type="ptx",
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
|
|
@ -85,7 +84,6 @@ class pnor2(pgate.pgate):
|
||||||
tx_type="nmos",
|
tx_type="nmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.nmos_right)
|
|
||||||
|
|
||||||
self.pmos_left = factory.create(module_type="ptx",
|
self.pmos_left = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -93,7 +91,6 @@ class pnor2(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact=self.route_layer,
|
add_source_contact=self.route_layer,
|
||||||
add_drain_contact="active")
|
add_drain_contact="active")
|
||||||
self.add_mod(self.pmos_left)
|
|
||||||
|
|
||||||
self.pmos_right = factory.create(module_type="ptx",
|
self.pmos_right = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
|
|
@ -101,7 +98,6 @@ class pnor2(pgate.pgate):
|
||||||
tx_type="pmos",
|
tx_type="pmos",
|
||||||
add_source_contact="active",
|
add_source_contact="active",
|
||||||
add_drain_contact=self.route_layer)
|
add_drain_contact=self.route_layer)
|
||||||
self.add_mod(self.pmos_right)
|
|
||||||
|
|
||||||
def setup_layout_constants(self):
|
def setup_layout_constants(self):
|
||||||
""" Pre-compute some handy layout parameters. """
|
""" Pre-compute some handy layout parameters. """
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,6 @@ class precharge(design.design):
|
||||||
width=self.ptx_width,
|
width=self.ptx_width,
|
||||||
mults=self.ptx_mults,
|
mults=self.ptx_mults,
|
||||||
tx_type="pmos")
|
tx_type="pmos")
|
||||||
self.add_mod(self.pmos)
|
|
||||||
|
|
||||||
def route_vdd_rail(self):
|
def route_vdd_rail(self):
|
||||||
"""
|
"""
|
||||||
|
|
@ -305,4 +304,3 @@ class precharge(design.design):
|
||||||
self.add_path(self.bitline_layer,
|
self.add_path(self.bitline_layer,
|
||||||
[left_pos, right_pos],
|
[left_pos, right_pos],
|
||||||
width=pmos_pin.height())
|
width=pmos_pin.height())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,13 +85,11 @@ class ptristate_inv(pgate.pgate):
|
||||||
width=self.nmos_width,
|
width=self.nmos_width,
|
||||||
mults=1,
|
mults=1,
|
||||||
tx_type="nmos")
|
tx_type="nmos")
|
||||||
self.add_mod(self.nmos)
|
|
||||||
|
|
||||||
self.pmos = factory.create(module_type="ptx",
|
self.pmos = factory.create(module_type="ptx",
|
||||||
width=self.pmos_width,
|
width=self.pmos_width,
|
||||||
mults=1,
|
mults=1,
|
||||||
tx_type="pmos")
|
tx_type="pmos")
|
||||||
self.add_mod(self.pmos)
|
|
||||||
|
|
||||||
def route_supply_rails(self):
|
def route_supply_rails(self):
|
||||||
""" Add vdd/gnd rails to the top and bottom. """
|
""" Add vdd/gnd rails to the top and bottom. """
|
||||||
|
|
|
||||||
|
|
@ -66,19 +66,16 @@ class pwrite_driver(design.design):
|
||||||
|
|
||||||
# Tristate inverter
|
# Tristate inverter
|
||||||
self.tri = factory.create(module_type="ptristate_inv", height="min")
|
self.tri = factory.create(module_type="ptristate_inv", height="min")
|
||||||
self.add_mod(self.tri)
|
|
||||||
debug.check(self.tri.width<self.width,
|
debug.check(self.tri.width<self.width,
|
||||||
"Could not create tristate inverter to match bitcell width")
|
"Could not create tristate inverter to match bitcell width")
|
||||||
|
|
||||||
#self.tbuf = factory.create(module_type="ptristate_buf",
|
#self.tbuf = factory.create(module_type="ptristate_buf",
|
||||||
#height="min")
|
#height="min")
|
||||||
#self.add_mod(self.tbuf)
|
|
||||||
#debug.check(self.tbuf.width<self.width,
|
#debug.check(self.tbuf.width<self.width,
|
||||||
#"Could not create tristate buffer to match bitcell width")
|
#"Could not create tristate buffer to match bitcell width")
|
||||||
|
|
||||||
# Inverter for din and en
|
# Inverter for din and en
|
||||||
self.inv = factory.create(module_type="pinv", under_rail_vias=True)
|
self.inv = factory.create(module_type="pinv", under_rail_vias=True)
|
||||||
self.add_mod(self.inv)
|
|
||||||
|
|
||||||
def create_insts(self):
|
def create_insts(self):
|
||||||
# Enable inverter
|
# Enable inverter
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,6 @@ class wordline_driver(design.design):
|
||||||
size=driver_size,
|
size=driver_size,
|
||||||
height=self.nand.height)
|
height=self.nand.height)
|
||||||
|
|
||||||
self.add_mod(self.nand)
|
|
||||||
self.add_mod(self.driver)
|
|
||||||
|
|
||||||
def create_layout(self):
|
def create_layout(self):
|
||||||
self.width = self.nand.width + self.driver.width
|
self.width = self.nand.width + self.driver.width
|
||||||
if "li" in layer:
|
if "li" in layer:
|
||||||
|
|
|
||||||
|
|
@ -468,11 +468,9 @@ class sram_base(design, verilog, lef):
|
||||||
self.msb_address = dff_buf_array(name="msb_address",
|
self.msb_address = dff_buf_array(name="msb_address",
|
||||||
rows=1,
|
rows=1,
|
||||||
columns=self.num_banks / 2)
|
columns=self.num_banks / 2)
|
||||||
self.add_mod(self.msb_address)
|
|
||||||
|
|
||||||
if self.num_banks>2:
|
if self.num_banks>2:
|
||||||
self.msb_decoder = self.bank.decoder.pre2_4
|
self.msb_decoder = self.bank.decoder.pre2_4
|
||||||
self.add_mod(self.msb_decoder)
|
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.bitcell = factory.create(module_type=OPTS.bitcell)
|
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)
|
# Create the bank module (up to four are instantiated)
|
||||||
self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
|
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
|
self.num_spare_cols = self.bank.num_spare_cols
|
||||||
|
|
||||||
# Create the address and control flops (but not the clk)
|
# 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.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:
|
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.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:
|
else:
|
||||||
self.col_addr_dff = None
|
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.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:
|
if self.write_size:
|
||||||
self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks)
|
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:
|
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.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
|
# Create bank decoder
|
||||||
if(self.num_banks > 1):
|
if(self.num_banks > 1):
|
||||||
|
|
@ -515,30 +507,27 @@ class sram_base(design, verilog, lef):
|
||||||
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
self.mod_control_logic = getattr(c, OPTS.control_logic)
|
||||||
|
|
||||||
# Create the control logic module for each port type
|
# 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,
|
self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
spare_columns=self.num_spare_cols,
|
spare_columns=self.num_spare_cols,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="rw")
|
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,
|
self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
spare_columns=self.num_spare_cols,
|
spare_columns=self.num_spare_cols,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="w")
|
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,
|
self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows,
|
||||||
words_per_row=self.words_per_row,
|
words_per_row=self.words_per_row,
|
||||||
word_size=self.word_size,
|
word_size=self.word_size,
|
||||||
spare_columns=self.num_spare_cols,
|
spare_columns=self.num_spare_cols,
|
||||||
sram=self,
|
sram=self,
|
||||||
port_type="r")
|
port_type="r")
|
||||||
self.add_mod(self.control_logic_r)
|
|
||||||
|
|
||||||
def create_bank(self, bank_num):
|
def create_bank(self, bank_num):
|
||||||
""" Create a bank """
|
""" Create a bank """
|
||||||
|
|
@ -779,13 +768,13 @@ class sram_base(design, verilog, lef):
|
||||||
Clears the bit exclusions
|
Clears the bit exclusions
|
||||||
"""
|
"""
|
||||||
self.bank.clear_exclude_bits()
|
self.bank.clear_exclude_bits()
|
||||||
|
|
||||||
def graph_exclude_column_mux(self, column_include_num, port):
|
def graph_exclude_column_mux(self, column_include_num, port):
|
||||||
"""
|
"""
|
||||||
Excludes all columns muxes unrelated to the target bit being simulated.
|
Excludes all columns muxes unrelated to the target bit being simulated.
|
||||||
"""
|
"""
|
||||||
self.bank.graph_exclude_column_mux(column_include_num, port)
|
self.bank.graph_exclude_column_mux(column_include_num, port)
|
||||||
|
|
||||||
def graph_clear_column_mux(self, port):
|
def graph_clear_column_mux(self, port):
|
||||||
"""
|
"""
|
||||||
Clear mux exclusions to allow different bit tests.
|
Clear mux exclusions to allow different bit tests.
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,16 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
|
||||||
else:
|
else:
|
||||||
debug.warning("Could not locate file: {}".format(full_drc_file))
|
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
|
# Create an auxiliary script to run calibre with the runset
|
||||||
run_file = output_path + "run_drc.sh"
|
run_file = output_path + "run_drc.sh"
|
||||||
f = open(run_file, "w")
|
f = open(run_file, "w")
|
||||||
|
|
@ -111,14 +121,29 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out
|
||||||
else:
|
else:
|
||||||
debug.warning("Could not locate file: {}".format(full_lvs_file))
|
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"
|
run_file = output_path + "/run_lvs.sh"
|
||||||
f = open(run_file, "w")
|
f = open(run_file, "w")
|
||||||
f.write("#!/bin/sh\n")
|
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],
|
if final_verification:
|
||||||
lvs_file,
|
connect_supplies = ""
|
||||||
gds_name,
|
else:
|
||||||
sp_name,
|
connect_supplies = "-rd connect_supplies=1"
|
||||||
cell_name)
|
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(cmd)
|
||||||
f.write("\n")
|
f.write("\n")
|
||||||
f.close()
|
f.close()
|
||||||
|
|
|
||||||
|
|
@ -337,16 +337,25 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=
|
||||||
|
|
||||||
# Netlists match uniquely.
|
# Netlists match uniquely.
|
||||||
test = re.compile("match uniquely.")
|
test = re.compile("match uniquely.")
|
||||||
correct = list(filter(test.search, final_results))
|
uniquely = list(filter(test.search, final_results))
|
||||||
|
|
||||||
|
# Netlists match uniquely.
|
||||||
|
test = re.compile("match correctly.")
|
||||||
|
correctly = list(filter(test.search, final_results))
|
||||||
|
|
||||||
# Fail if they don't match. Something went wrong!
|
# Fail if they don't match. Something went wrong!
|
||||||
if len(correct) == 0:
|
if len(uniquely) == 0 and len(correctly) == 0:
|
||||||
total_errors += 1
|
total_errors += 1
|
||||||
|
|
||||||
|
if len(uniquely) == 0 and len(correctly) > 0:
|
||||||
|
debug.warning("{0}\tLVS matches but not uniquely".format(cell_name))
|
||||||
|
|
||||||
if total_errors>0:
|
if total_errors>0:
|
||||||
# Just print out the whole file, it is short.
|
# Just print out the whole file, it is short.
|
||||||
for e in results:
|
for e in results:
|
||||||
debug.info(1,e.strip("\n"))
|
debug.info(1,e.strip("\n"))
|
||||||
debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,resultsfile))
|
debug.error("{0}\tLVS mismatch (results in {1})".format(cell_name,
|
||||||
|
resultsfile))
|
||||||
else:
|
else:
|
||||||
debug.info(1, "{0}\tLVS matches".format(cell_name))
|
debug.info(1, "{0}\tLVS matches".format(cell_name))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,8 +110,9 @@ end
|
||||||
# Wells
|
# Wells
|
||||||
nwell.and(pwell).output("WELL.1", "WELL.1 : nwell/pwell must not overlap")
|
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
|
# 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")
|
# the rule WELL.3 was not detected in the original FreePDK45 rule deck
|
||||||
pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm")
|
#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")
|
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")
|
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")
|
vth.not(well).output("VT.1","VT.1 : Vth adjust layers must coincide with well")
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox
|
||||||
gv_ngate = ngate & vtg - vth - thkox
|
gv_ngate = ngate & vtg - vth - thkox
|
||||||
hv_ngate = ngate - vtg - vth & thkox
|
hv_ngate = ngate - vtg - vth & 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
|
# PMOS transistor device extraction
|
||||||
extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell })
|
extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell })
|
||||||
|
|
@ -205,15 +205,26 @@ connect(metal10, metal10_pin)
|
||||||
# Global
|
# Global
|
||||||
schematic.simplify
|
schematic.simplify
|
||||||
|
|
||||||
|
if $connect_supplies
|
||||||
|
connect_implicit("*", "vdd")
|
||||||
|
connect_implicit("*", "gnd")
|
||||||
|
end
|
||||||
|
|
||||||
connect_global(pwell, "PWELL")
|
connect_global(pwell, "PWELL")
|
||||||
connect_global(nwell, "NWELL")
|
connect_global(nwell, "NWELL")
|
||||||
connect_global(bulk, "BULK")
|
connect_global(bulk, "BULK")
|
||||||
|
|
||||||
for pat in %w(pnand* and2_dec* port_address* replica_bitcell_array)
|
for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*)
|
||||||
connect_explicit(pat, [ "NWELL", "vdd" ])
|
connect_explicit(pat, [ "NWELL", "vdd" ])
|
||||||
connect_explicit(pat, [ "BULK", "PWELL", "gnd" ])
|
connect_explicit(pat, [ "BULK", "PWELL", "gnd" ])
|
||||||
end
|
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*)
|
||||||
|
# connect_explicit(pat, [ "NWELL", "VDD" ])
|
||||||
|
# connect_explicit(pat, [ "BULK", "VSS" ])
|
||||||
|
#end
|
||||||
|
|
||||||
# Actually performs the extraction
|
# Actually performs the extraction
|
||||||
netlist # ... not really required
|
netlist # ... not really required
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -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>
|
||||||
|
|
@ -337,7 +337,7 @@ drc.add_enclosure("m2",
|
||||||
# VIA2-3.2 Minimum spacing of Via[2-3]
|
# VIA2-3.2 Minimum spacing of Via[2-3]
|
||||||
drc.add_layer("via2",
|
drc.add_layer("via2",
|
||||||
width=0.065,
|
width=0.065,
|
||||||
spacing=0.075)
|
spacing=0.085)
|
||||||
|
|
||||||
# METALINT.1 Minimum width of intermediate metal
|
# METALINT.1 Minimum width of intermediate metal
|
||||||
# METALINT.2 Minimum spacing of intermediate metal
|
# METALINT.2 Minimum spacing of intermediate metal
|
||||||
|
|
@ -480,6 +480,7 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa
|
||||||
#drc_name = "calibre"
|
#drc_name = "calibre"
|
||||||
#lvs_name = "calibre"
|
#lvs_name = "calibre"
|
||||||
#pex_name = "calibre"
|
#pex_name = "calibre"
|
||||||
|
|
||||||
drc_name = "klayout"
|
drc_name = "klayout"
|
||||||
lvs_name = "klayout"
|
lvs_name = "klayout"
|
||||||
pex_name = "klayout"
|
pex_name = "klayout"
|
||||||
|
|
|
||||||
|
|
@ -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 > 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 > 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 && !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 > 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 > 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 > 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 > 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 > 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 > 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 > 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 > 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 >= (min || 0) && (!max || p.holes <= 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 & Nselect
|
||||||
|
PP = AA & Pselect
|
||||||
|
NSTP = NP.and(NW)
|
||||||
|
PSTP = PP.not(NW)
|
||||||
|
GATE = PL & 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 & 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 & 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 > #{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 && NBR_OF_METALS < 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 > #{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 && NBR_OF_METALS < 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 > #{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 > 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 > #{10*LAMBDA}um : #{R22_4}um")
|
||||||
|
|
||||||
|
### Via 4
|
||||||
|
if NBR_OF_METALS > 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 > #{10*LAMBDA}um : #{R26_4}um")
|
||||||
|
|
||||||
|
### Via 5
|
||||||
|
if NBR_OF_METALS > 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 > #{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>
|
||||||
|
|
@ -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 & nwell
|
||||||
|
pactive = active_in_nwell & pplus
|
||||||
|
ntie = active_in_nwell & nplus
|
||||||
|
pgate = pactive & poly
|
||||||
|
psd = pactive - pgate
|
||||||
|
|
||||||
|
active_in_pwell = active & pwell
|
||||||
|
nactive = active_in_pwell & nplus
|
||||||
|
ptie = active_in_pwell & pplus
|
||||||
|
ngate = nactive & 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" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell })
|
||||||
|
|
||||||
|
# NMOS transistor device extraction
|
||||||
|
extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => 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 => absolute_tolerance] [, :relative => relative_tolerance])
|
||||||
|
tolerance("P", "W", :absolute => 1.nm, :relative => 0.001)
|
||||||
|
tolerance("N", "W", :absolute => 1.nm, :relative => 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>
|
||||||
|
|
@ -38,15 +38,11 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
# Bitcell for port names only
|
# Bitcell for port names only
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||||
self.add_mod(self.cell)
|
|
||||||
self.cell2 = factory.create(module_type=OPTS.bitcell, version="opt1a")
|
self.cell2 = factory.create(module_type=OPTS.bitcell, version="opt1a")
|
||||||
self.add_mod(self.cell2)
|
|
||||||
self.strap = factory.create(module_type="internal", version="wlstrap")
|
self.strap = factory.create(module_type="internal", version="wlstrap")
|
||||||
self.add_mod(self.strap)
|
|
||||||
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
||||||
self.add_mod(self.strap2)
|
|
||||||
self.strap3 = factory.create(module_type="internal", version="wlstrapa")
|
self.strap3 = factory.create(module_type="internal", version="wlstrapa")
|
||||||
self.add_mod(self.strap3)
|
self.strap4 = factory.create(module_type="internal", version="wlstrapa_p")
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
""" Create the module instances used in this design """
|
""" Create the module instances used in this design """
|
||||||
|
|
@ -71,21 +67,28 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array):
|
||||||
self.connect_inst(self.get_bitcell_pins(row, col))
|
self.connect_inst(self.get_bitcell_pins(row, col))
|
||||||
if col != self.column_size - 1:
|
if col != self.column_size - 1:
|
||||||
if alternate_strap:
|
if alternate_strap:
|
||||||
row_layout.append(self.strap2)
|
if row % 2:
|
||||||
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
row_layout.append(self.strap4)
|
||||||
mod=self.strap2)
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
|
mod=self.strap4)
|
||||||
|
else:
|
||||||
|
row_layout.append(self.strap2)
|
||||||
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
|
mod=self.strap2)
|
||||||
alternate_strap = 0
|
alternate_strap = 0
|
||||||
else:
|
else:
|
||||||
if row % 2:
|
if row % 2:
|
||||||
|
name="row_{}_col_{}_wlstrapa".format(row, col)
|
||||||
row_layout.append(self.strap3)
|
row_layout.append(self.strap3)
|
||||||
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
self.add_inst(name=name.format(row, col),
|
||||||
mod=self.strap3)
|
mod=self.strap3)
|
||||||
else:
|
else:
|
||||||
|
name="row_{}_col_{}_wlstrap".format(row, col)
|
||||||
row_layout.append(self.strap)
|
row_layout.append(self.strap)
|
||||||
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
self.add_inst(name=name.format(row, col),
|
||||||
mod=self.strap)
|
mod=self.strap)
|
||||||
alternate_strap = 1
|
alternate_strap = 1
|
||||||
self.connect_inst(self.get_strap_pins(row, col))
|
self.connect_inst(self.get_strap_pins(row, col, name))
|
||||||
if alternate_bitcell == 0:
|
if alternate_bitcell == 0:
|
||||||
alternate_bitcell = 1
|
alternate_bitcell = 1
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -77,21 +77,24 @@ class sky130_bitcell_base_array(bitcell_base_array):
|
||||||
|
|
||||||
return bitcell_pins
|
return bitcell_pins
|
||||||
|
|
||||||
def get_strap_pins(self, row, col):
|
def get_strap_pins(self, row, col, name=""):
|
||||||
"""
|
"""
|
||||||
Creates a list of connections in the strap cell,
|
Creates a list of connections in the strap cell,
|
||||||
indexed by column and row, for instance use in bitcell_array
|
indexed by column and row, for instance use in bitcell_array
|
||||||
"""
|
"""
|
||||||
strap_pins = ["vdd"]
|
if name and "_p" in name:
|
||||||
return strap_pins
|
strap_pins = ["gnd"]
|
||||||
|
else:
|
||||||
def get_col_cap_pins(self, row, col):
|
strap_pins = ["vdd"]
|
||||||
"""
|
|
||||||
"""
|
|
||||||
strap_pins = ["gnd", "gnd", "vdd"]
|
|
||||||
return strap_pins
|
return strap_pins
|
||||||
|
|
||||||
def get_col_cap_p_pins(self, row, col):
|
def get_col_cap_p_pins(self, row, col):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
strap_pins = ["gnd", "vdd", "gnd"]
|
||||||
|
return strap_pins
|
||||||
|
|
||||||
|
def get_col_cap_pins(self, row, col):
|
||||||
"""
|
"""
|
||||||
"""
|
"""
|
||||||
strap_pins = []
|
strap_pins = []
|
||||||
|
|
|
||||||
|
|
@ -49,18 +49,12 @@ class sky130_col_cap_array(sky130_bitcell_base_array):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
if self.location == "top":
|
if self.location == "top":
|
||||||
self.colend1 = factory.create(module_type="col_cap", version="colend")
|
self.colend1 = factory.create(module_type="col_cap", version="colend")
|
||||||
self.add_mod(self.colend1)
|
|
||||||
self.colend2 = factory.create(module_type="col_cap", version="colend_p_cent")
|
self.colend2 = factory.create(module_type="col_cap", version="colend_p_cent")
|
||||||
self.add_mod(self.colend2)
|
|
||||||
self.colend3 = factory.create(module_type="col_cap", version="colend_cent")
|
self.colend3 = factory.create(module_type="col_cap", version="colend_cent")
|
||||||
self.add_mod(self.colend3)
|
|
||||||
elif self.location == "bottom":
|
elif self.location == "bottom":
|
||||||
self.colend1 = factory.create(module_type="col_cap", version="colenda")
|
self.colend1 = factory.create(module_type="col_cap", version="colenda")
|
||||||
self.add_mod(self.colend1)
|
|
||||||
self.colend2 = factory.create(module_type="col_cap", version="colenda_p_cent")
|
self.colend2 = factory.create(module_type="col_cap", version="colenda_p_cent")
|
||||||
self.add_mod(self.colend2)
|
|
||||||
self.colend3 = factory.create(module_type="col_cap", version="colenda_cent")
|
self.colend3 = factory.create(module_type="col_cap", version="colenda_cent")
|
||||||
self.add_mod(self.colend3)
|
|
||||||
|
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,11 @@ class sky130_dummy_array(sky130_bitcell_base_array):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell, version="opt1")
|
self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell, version="opt1")
|
||||||
self.add_mod(self.dummy_cell)
|
|
||||||
self.dummy_cell2 = factory.create(module_type=OPTS.dummy_bitcell, version="opt1a")
|
self.dummy_cell2 = factory.create(module_type=OPTS.dummy_bitcell, version="opt1a")
|
||||||
self.add_mod(self.dummy_cell2)
|
|
||||||
self.strap = factory.create(module_type="internal", version="wlstrap")
|
self.strap = factory.create(module_type="internal", version="wlstrap")
|
||||||
self.add_mod(self.strap)
|
|
||||||
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
||||||
self.add_mod(self.strap2)
|
self.strap3 = factory.create(module_type="internal", version="wlstrapa")
|
||||||
|
self.strap4 = factory.create(module_type="internal", version="wlstrapa_p")
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
|
|
@ -77,15 +75,24 @@ class sky130_dummy_array(sky130_bitcell_base_array):
|
||||||
self.connect_inst(self.get_bitcell_pins(row, col))
|
self.connect_inst(self.get_bitcell_pins(row, col))
|
||||||
if col != self.column_size - 1:
|
if col != self.column_size - 1:
|
||||||
if alternate_strap:
|
if alternate_strap:
|
||||||
row_layout.append(self.strap2)
|
if col % 2:
|
||||||
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
row_layout.append(self.strap4)
|
||||||
mod=self.strap2)
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
|
mod=self.strap4)
|
||||||
|
else:
|
||||||
|
row_layout.append(self.strap4)
|
||||||
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
|
mod=self.strap4)
|
||||||
alternate_strap = 0
|
alternate_strap = 0
|
||||||
else:
|
else:
|
||||||
|
if col % 2:
|
||||||
row_layout.append(self.strap)
|
row_layout.append(self.strap)
|
||||||
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
mod=self.strap)
|
mod=self.strap)
|
||||||
|
else:
|
||||||
|
row_layout.append(self.strap3)
|
||||||
|
self.add_inst(name="row_{}_col_{}_wlstrap".format(row, col),
|
||||||
|
mod=self.strap3)
|
||||||
alternate_strap = 1
|
alternate_strap = 1
|
||||||
self.connect_inst(self.get_strap_pins(row, col))
|
self.connect_inst(self.get_strap_pins(row, col))
|
||||||
if alternate_bitcell == 0:
|
if alternate_bitcell == 0:
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ class sky130_internal(design.design):
|
||||||
self.name = "sky130_fd_bd_sram__sram_sp_wlstrap_p"
|
self.name = "sky130_fd_bd_sram__sram_sp_wlstrap_p"
|
||||||
elif version == "wlstrapa":
|
elif version == "wlstrapa":
|
||||||
self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa"
|
self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa"
|
||||||
|
elif version == "wlstrapa_p":
|
||||||
|
self.name = "sky130_fd_bd_sram__sram_sp_wlstrapa_p"
|
||||||
else:
|
else:
|
||||||
debug.error("Invalid version", -1)
|
debug.error("Invalid version", -1)
|
||||||
design.design.__init__(self, name=self.name)
|
design.design.__init__(self, name=self.name)
|
||||||
|
|
|
||||||
|
|
@ -338,3 +338,82 @@ class sky130_replica_bitcell_array(replica_bitcell_array, sky130_bitcell_base_ar
|
||||||
width=pin.width(),
|
width=pin.width(),
|
||||||
height=self.height - 2 *(pin_height + drc_width*2))
|
height=self.height - 2 *(pin_height + drc_width*2))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def add_wordline_pins(self):
|
||||||
|
|
||||||
|
# Wordlines to ground
|
||||||
|
self.gnd_wordline_names = []
|
||||||
|
|
||||||
|
for port in self.all_ports:
|
||||||
|
for bit in self.all_ports:
|
||||||
|
self.rbl_wordline_names[port].append("rbl_wl_{0}_{1}".format(port, bit))
|
||||||
|
if bit != port:
|
||||||
|
self.gnd_wordline_names.append("rbl_wl_{0}_{1}".format(port, bit))
|
||||||
|
|
||||||
|
self.all_rbl_wordline_names = [x for sl in self.rbl_wordline_names for x in sl]
|
||||||
|
|
||||||
|
self.wordline_names = self.bitcell_array.wordline_names
|
||||||
|
self.all_wordline_names = self.bitcell_array.all_wordline_names
|
||||||
|
|
||||||
|
# All wordlines including dummy and RBL
|
||||||
|
self.replica_array_wordline_names = []
|
||||||
|
#self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names()))
|
||||||
|
for bit in range(self.rbl[0]):
|
||||||
|
self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[bit]])
|
||||||
|
self.replica_array_wordline_names.extend(self.all_wordline_names)
|
||||||
|
for bit in range(self.rbl[1]):
|
||||||
|
self.replica_array_wordline_names.extend([x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[self.rbl[0] + bit]])
|
||||||
|
#self.replica_array_wordline_names.extend(["gnd"] * len(self.col_cap_top.get_wordline_names()))
|
||||||
|
|
||||||
|
for port in range(self.rbl[0]):
|
||||||
|
self.add_pin(self.rbl_wordline_names[port][port], "INPUT")
|
||||||
|
self.add_pin_list(self.all_wordline_names, "INPUT")
|
||||||
|
for port in range(self.rbl[0], self.rbl[0] + self.rbl[1]):
|
||||||
|
self.add_pin(self.rbl_wordline_names[port][port], "INPUT")
|
||||||
|
|
||||||
|
def create_instances(self):
|
||||||
|
""" Create the module instances used in this design """
|
||||||
|
self.supplies = ["vdd", "gnd"]
|
||||||
|
|
||||||
|
# Used for names/dimensions only
|
||||||
|
# self.cell = factory.create(module_type=OPTS.bitcell)
|
||||||
|
|
||||||
|
# Main array
|
||||||
|
self.bitcell_array_inst=self.add_inst(name="bitcell_array",
|
||||||
|
mod=self.bitcell_array)
|
||||||
|
self.connect_inst(self.all_bitline_names + self.all_wordline_names + self.supplies)
|
||||||
|
# Replica columns
|
||||||
|
self.replica_col_insts = []
|
||||||
|
for port in self.all_ports:
|
||||||
|
if port in self.rbls:
|
||||||
|
self.replica_col_insts.append(self.add_inst(name="replica_col_{}".format(port),
|
||||||
|
mod=self.replica_columns[port]))
|
||||||
|
self.connect_inst(self.rbl_bitline_names[port] + self.replica_array_wordline_names + self.supplies)
|
||||||
|
else:
|
||||||
|
self.replica_col_insts.append(None)
|
||||||
|
|
||||||
|
# Dummy rows under the bitcell array (connected with with the replica cell wl)
|
||||||
|
self.dummy_row_replica_insts = []
|
||||||
|
# Note, this is the number of left and right even if we aren't adding the columns to this bitcell array!
|
||||||
|
for port in self.all_ports:
|
||||||
|
self.dummy_row_replica_insts.append(self.add_inst(name="dummy_row_{}".format(port),
|
||||||
|
mod=self.dummy_row))
|
||||||
|
self.connect_inst(self.all_bitline_names + [x if x not in self.gnd_wordline_names else "gnd" for x in self.rbl_wordline_names[port]] + self.supplies)
|
||||||
|
|
||||||
|
# Top/bottom dummy rows or col caps
|
||||||
|
self.dummy_row_insts = []
|
||||||
|
self.dummy_row_insts.append(self.add_inst(name="dummy_row_bot",
|
||||||
|
mod=self.col_cap_bottom))
|
||||||
|
self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_bottom.get_wordline_names()) + self.supplies)
|
||||||
|
self.dummy_row_insts.append(self.add_inst(name="dummy_row_top",
|
||||||
|
mod=self.col_cap_top))
|
||||||
|
self.connect_inst(self.all_bitline_names + ["gnd"] * len(self.col_cap_top.get_wordline_names()) + self.supplies)
|
||||||
|
|
||||||
|
# Left/right Dummy columns
|
||||||
|
self.dummy_col_insts = []
|
||||||
|
self.dummy_col_insts.append(self.add_inst(name="dummy_col_left",
|
||||||
|
mod=self.row_cap_left))
|
||||||
|
self.connect_inst(["dummy_left_" + bl for bl in self.row_cap_left.all_bitline_names] + ["gnd"] + self.replica_array_wordline_names + ["gnd"] + self.supplies)
|
||||||
|
self.dummy_col_insts.append(self.add_inst(name="dummy_col_right",
|
||||||
|
mod=self.row_cap_right))
|
||||||
|
self.connect_inst(["dummy_right_" + bl for bl in self.row_cap_right.all_bitline_names] + ["gnd"] + self.replica_array_wordline_names + ["gnd"] + self.supplies)
|
||||||
|
|
|
||||||
|
|
@ -81,9 +81,9 @@ class sky130_replica_column(sky130_bitcell_base_array):
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
|
|
||||||
self.create_all_bitline_names()
|
self.create_all_bitline_names()
|
||||||
self.create_all_wordline_names(self.row_size+2)
|
#self.create_all_wordline_names(self.row_size+2)
|
||||||
# +2 to add fake wl pins for colends
|
# +2 to add fake wl pins for colends
|
||||||
|
self.create_all_wordline_names(self.row_size+1, 1)
|
||||||
self.add_pin_list(self.all_bitline_names, "OUTPUT")
|
self.add_pin_list(self.all_bitline_names, "OUTPUT")
|
||||||
self.add_pin_list(self.all_wordline_names, "INPUT")
|
self.add_pin_list(self.all_wordline_names, "INPUT")
|
||||||
|
|
||||||
|
|
@ -92,28 +92,21 @@ class sky130_replica_column(sky130_bitcell_base_array):
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1")
|
self.replica_cell = factory.create(module_type="replica_bitcell_1port", version="opt1")
|
||||||
self.add_mod(self.replica_cell)
|
|
||||||
self.cell = self.replica_cell
|
self.cell = self.replica_cell
|
||||||
self.replica_cell2 = factory.create(module_type="replica_bitcell_1port", version="opt1a")
|
self.replica_cell2 = factory.create(module_type="replica_bitcell_1port", version="opt1a")
|
||||||
self.add_mod(self.replica_cell2)
|
|
||||||
|
|
||||||
self.dummy_cell = factory.create(module_type="dummy_bitcell_1port", version="opt1")
|
self.dummy_cell = factory.create(module_type="dummy_bitcell_1port", version="opt1")
|
||||||
self.dummy_cell2 = factory.create(module_type="dummy_bitcell_1port", version="opt1")
|
self.dummy_cell2 = factory.create(module_type="dummy_bitcell_1port", version="opt1")
|
||||||
|
|
||||||
self.strap1 = factory.create(module_type="internal", version="wlstrap")
|
self.strap1 = factory.create(module_type="internal", version="wlstrap")
|
||||||
self.add_mod(self.strap1)
|
|
||||||
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
self.strap2 = factory.create(module_type="internal", version="wlstrap_p")
|
||||||
self.add_mod(self.strap2)
|
self.strap3 = factory.create(module_type="internal", version="wlstrapa_p")
|
||||||
|
|
||||||
self.colend = factory.create(module_type="col_cap", version="colend")
|
self.colend = factory.create(module_type="col_cap", version="colend")
|
||||||
self.edge_cell = self.colend
|
self.edge_cell = self.colend
|
||||||
self.add_mod(self.colend)
|
|
||||||
self.colenda = factory.create(module_type="col_cap", version="colenda")
|
self.colenda = factory.create(module_type="col_cap", version="colenda")
|
||||||
self.add_mod(self.colenda)
|
|
||||||
self.colend_p_cent = factory.create(module_type="col_cap", version="colend_p_cent")
|
self.colend_p_cent = factory.create(module_type="col_cap", version="colend_p_cent")
|
||||||
self.add_mod(self.colend_p_cent)
|
|
||||||
self.colenda_p_cent = factory.create(module_type="col_cap", version="colenda_p_cent")
|
self.colenda_p_cent = factory.create(module_type="col_cap", version="colenda_p_cent")
|
||||||
self.add_mod(self.colenda_p_cent)
|
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
self.cell_inst = {}
|
self.cell_inst = {}
|
||||||
|
|
@ -132,33 +125,33 @@ class sky130_replica_column(sky130_bitcell_base_array):
|
||||||
self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell)
|
self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell)
|
||||||
self.connect_inst(self.get_bitcell_pins(row, 0))
|
self.connect_inst(self.get_bitcell_pins(row, 0))
|
||||||
row_layout.append(self.strap2)
|
row_layout.append(self.strap2)
|
||||||
self.add_inst(name=name + "_strap", mod=self.strap2)
|
self.add_inst(name=name + "_strap_p", mod=self.strap2)
|
||||||
self.connect_inst(self.get_strap_pins(row, 0))
|
self.connect_inst(self.get_strap_pins(row, 0, name + "_strap_p"))
|
||||||
alternate_bitcell = 1
|
alternate_bitcell = 1
|
||||||
|
|
||||||
else:
|
else:
|
||||||
row_layout.append(self.replica_cell2)
|
row_layout.append(self.replica_cell2)
|
||||||
self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell2)
|
self.cell_inst[row]=self.add_inst(name=name, mod=self.replica_cell2)
|
||||||
self.connect_inst(self.get_bitcell_pins(row, 0))
|
self.connect_inst(self.get_bitcell_pins(row, 0))
|
||||||
row_layout.append(self.strap2)
|
row_layout.append(self.strap3)
|
||||||
self.add_inst(name=name + "_strap", mod=self.strap2)
|
self.add_inst(name=name + "_strap", mod=self.strap3)
|
||||||
self.connect_inst(self.get_strap_pins(row, 0))
|
self.connect_inst(self.get_strap_pins(row, 0))
|
||||||
alternate_bitcell = 0
|
alternate_bitcell = 0
|
||||||
|
|
||||||
elif (row == 0):
|
elif (row == 0):
|
||||||
row_layout.append(self.colend)
|
row_layout.append(self.colend)
|
||||||
self.cell_inst[row]=self.add_inst(name=name, mod=self.colend)
|
self.cell_inst[row]=self.add_inst(name=name, mod=self.colend)
|
||||||
self.connect_inst(self.get_col_cap_p_pins(row, 0))
|
self.connect_inst(self.get_col_cap_pins(row, 0))
|
||||||
row_layout.append(self.colend_p_cent)
|
row_layout.append(self.colend_p_cent)
|
||||||
self.add_inst(name=name + "_cap", mod=self.colend_p_cent)
|
self.add_inst(name=name + "_cap", mod=self.colend_p_cent)
|
||||||
self.connect_inst(self.get_col_cap_pins(row, 0))
|
self.connect_inst(self.get_col_cap_p_pins(row, 0))
|
||||||
elif (row == self.total_size - 1):
|
elif (row == self.total_size - 1):
|
||||||
row_layout.append(self.colenda)
|
row_layout.append(self.colenda)
|
||||||
self.cell_inst[row]=self.add_inst(name=name, mod=self.colenda)
|
self.cell_inst[row]=self.add_inst(name=name, mod=self.colenda)
|
||||||
self.connect_inst(self.get_col_cap_p_pins(row, 0))
|
self.connect_inst(self.get_col_cap_pins(row, 0))
|
||||||
row_layout.append(self.colenda_p_cent)
|
row_layout.append(self.colenda_p_cent)
|
||||||
self.add_inst(name=name + "_cap", mod=self.colenda_p_cent)
|
self.add_inst(name=name + "_cap", mod=self.colenda_p_cent)
|
||||||
self.connect_inst(self.get_col_cap_pins(row, 0))
|
self.connect_inst(self.get_col_cap_p_pins(row, 0))
|
||||||
|
|
||||||
self.array_layout.append(row_layout)
|
self.array_layout.append(row_layout)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,24 +51,16 @@ class sky130_row_cap_array(sky130_bitcell_base_array):
|
||||||
""" Add the modules used in this design """
|
""" Add the modules used in this design """
|
||||||
if self.column_offset == 0:
|
if self.column_offset == 0:
|
||||||
self.top_corner = factory.create(module_type="corner", location="ul")
|
self.top_corner = factory.create(module_type="corner", location="ul")
|
||||||
self.add_mod(self.top_corner)
|
|
||||||
self.bottom_corner =factory.create(module_type="corner", location="ll")
|
self.bottom_corner =factory.create(module_type="corner", location="ll")
|
||||||
self.add_mod(self.bottom_corner)
|
|
||||||
self.rowend1 = factory.create(module_type="row_cap", version="rowend_replica")
|
self.rowend1 = factory.create(module_type="row_cap", version="rowend_replica")
|
||||||
self.add_mod(self.rowend1)
|
|
||||||
self.rowend2 = factory.create(module_type="row_cap", version="rowenda_replica")
|
self.rowend2 = factory.create(module_type="row_cap", version="rowenda_replica")
|
||||||
self.add_mod(self.rowend2)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.top_corner = factory.create(module_type="corner", location="ur")
|
self.top_corner = factory.create(module_type="corner", location="ur")
|
||||||
self.add_mod(self.top_corner)
|
|
||||||
self.bottom_corner = factory.create(module_type="corner", location="lr")
|
self.bottom_corner = factory.create(module_type="corner", location="lr")
|
||||||
self.add_mod(self.bottom_corner)
|
|
||||||
|
|
||||||
self.rowend1 = factory.create(module_type="row_cap", version="rowend")
|
self.rowend1 = factory.create(module_type="row_cap", version="rowend")
|
||||||
self.add_mod(self.rowend1)
|
|
||||||
self.rowend2 = factory.create(module_type="row_cap", version="rowenda")
|
self.rowend2 = factory.create(module_type="row_cap", version="rowenda")
|
||||||
self.add_mod(self.rowend2)
|
|
||||||
|
|
||||||
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
self.cell = factory.create(module_type=OPTS.bitcell, version="opt1")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ cell_properties.bitcell_2port.port_map = {'bl0': 'BL0',
|
||||||
'gnd': 'GND'}
|
'gnd': 'GND'}
|
||||||
|
|
||||||
cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl'],
|
cell_properties.col_cap_1port_bitcell = cell(['br', 'vdd', 'gnd', 'bl'],
|
||||||
['INPUT', 'INPUT', 'GROUND', 'POWER'],
|
['INPUT', 'POWER', 'GROUND', 'INPUT'],
|
||||||
{'bl': 'BL0',
|
{'bl': 'BL0',
|
||||||
'br': 'BL1',
|
'br': 'BL1',
|
||||||
'vdd': 'VPWR',
|
'vdd': 'VPWR',
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue