dual port rba lvs clean again with cell library changes

This commit is contained in:
Jesse Cirimelli-Low 2026-04-14 14:48:26 -07:00
parent b6d98c44d5
commit 515591a422
12 changed files with 116 additions and 62 deletions

View File

@ -19,8 +19,8 @@ class bitcell_array(bitcell_base_array):
Creates a rows x cols array of memory cells. Creates a rows x cols array of memory cells.
Assumes bit-lines and word lines are connected by abutment. Assumes bit-lines and word lines are connected by abutment.
""" """
def __init__(self, rows, cols, column_offset=0, name="", left_rbl=None, right_rbl=None): def __init__(self, rows, cols, column_offset=0, row_offset=0, name="", left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols))
@ -59,18 +59,21 @@ class bitcell_array(bitcell_base_array):
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
r = self.row_offset
c = self.column_offset
self.cell_inst={} self.cell_inst={}
if self.cell.mirror.y: if self.cell.mirror.y:
core_block = [[0 for x in range(2)] for y in range(2)] core_block = [[0 for x in range(2)] for y in range(2)]
core_block[0][0] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True) core_block[(0 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(0+c)%2}", mod=self.cell, is_bitcell=True, mirror='XY')
core_block[1][0] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX') core_block[(0 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(1+c)%2}", mod=self.cell, is_bitcell=True, mirror='MX')
core_block[0][1] = geometry.instance("core_0_1", mod=self.cell, is_bitcell=True, mirror='MY') core_block[(1 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(0+c)%2}", mod=self.cell, is_bitcell=True, mirror='MY')
core_block[1][1] = geometry.instance("core_1_1", mod=self.cell, is_bitcell=True, mirror='XY') core_block[(1 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.cell, is_bitcell=True, mirror='')
else: else:
core_block = [[0 for x in range(1)] for y in range(2)] core_block = [[0 for x in range(1)] for y in range(2)]
core_block[0][0] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True) core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.cell, is_bitcell=True)
core_block[1][0] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX') core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
print(r, c)
print(core_block)
self.pattern = pattern(self, "bitcell_array", core_block, num_rows=self.row_size, num_cols=self.column_size,name_template="bit_r{0}_c{1}") self.pattern = pattern(self, "bitcell_array", core_block, num_rows=self.row_size, num_cols=self.column_size,name_template="bit_r{0}_c{1}")
self.pattern.connect_array() self.pattern.connect_array()

View File

@ -16,14 +16,14 @@ class bitcell_base_array(design):
""" """
Abstract base class for bitcell-arrays -- bitcell, dummy, replica Abstract base class for bitcell-arrays -- bitcell, dummy, replica
""" """
def __init__(self, name, rows, cols, column_offset): def __init__(self, name, rows, cols, column_offset, row_offset):
super().__init__(name) super().__init__(name)
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols)) debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
self.column_size = cols self.column_size = cols
self.row_size = rows self.row_size = rows
self.column_offset = column_offset self.column_offset = column_offset
self.row_offset = row_offset
# Bitcell for port names only # Bitcell for port names only
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
@ -170,6 +170,18 @@ class bitcell_base_array(design):
power_name = 'vdd' power_name = 'vdd'
ground_name = 'gnd' ground_name = 'gnd'
if vdd_found == False or gnd_found == False:
for inst in self.insts:
if 'VDD' in inst.mod.get_pin_names():
vdd_found = True
power_name = 'VDD'
if 'GND' in inst.mod.get_pin_names():
gnd_found = True
ground_name = 'GND'
if vdd_found is False or gnd_found is False: if vdd_found is False or gnd_found is False:
from openram.tech import cell_properties from openram.tech import cell_properties
try: try:

View File

@ -20,7 +20,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
sides of a bitcell array. sides of a bitcell array.
""" """
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""): def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
super().__init__(name, rows, cols, column_offset=0) super().__init__(name, rows, cols, column_offset=0, row_offset=0)
debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name, debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name,
rows, rows,
cols, cols,

View File

@ -8,12 +8,13 @@ from openram import OPTS
from .bitcell_base_array import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from openram.base import geometry from openram.base import geometry
from .pattern import pattern from .pattern import pattern
from math import ceil
class col_cap_array(bitcell_base_array): class col_cap_array(bitcell_base_array):
""" """
Generate a dummy row/column for the replica array. Generate a dummy row/column for the replica array.
""" """
def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name="",left_rbl=[],right_rbl=[]): def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name="",left_rbl=[],right_rbl=[]):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.mirror = mirror self.mirror = mirror
self.location = location self.location = location
@ -38,28 +39,44 @@ class col_cap_array(bitcell_base_array):
def create_layout(self): def create_layout(self):
self.place_array("dummy_r{0}_c{1}", self.mirror) self.place_array()
self.add_layout_pins() self.add_layout_pins()
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.colend = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
# def create_instances(self):
# """ Create the module instances used in this design """
# self.cell_inst = {}
# for col in range(self.column_size):
# for row in range(self.row_size):
# name = "bit_r{0}_c{1}".format(row, col)
# self.cell_inst[row, col]=self.add_inst(name=name,
# mod=self.dummy_cell)
# self.connect_inst(self.get_bitcell_pins(row, col))
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.cell_inst = {} self.cell_inst={}
for col in range(self.column_size): if self.location == "top":
for row in range(self.row_size): bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="MY")]\
name = "bit_r{0}_c{1}".format(row, col) + [geometry.instance("01_colend", mod=self.colend, is_bitcell=True)]
self.cell_inst[row, col]=self.add_inst(name=name, elif self.location == "bottom":
mod=self.dummy_cell) bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="XY")]\
self.connect_inst(self.get_bitcell_pins(row, col)) + [geometry.instance("01_colend", mod=self.colend, is_bitcell=True, mirror="MX")]
bit_row = pattern.rotate_list(bit_row, self.column_offset * 2)
bit_block = []
pattern.append_row_to_block(bit_block, bit_row)
self.pattern = pattern(self, "col_cap_array_" + self.location , bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="col_cap_array" + self.location + "_r{0}_c{1}")
self.pattern.connect_array()
def get_bitcell_pins(self, row, col): def get_bitcell_pins(self, row, col):
""" """

View File

@ -15,7 +15,7 @@ class dummy_array(bitcell_base_array):
""" """
def __init__(self, rows, cols, column_offset=0, row_offset=0 ,mirror=0, location="", name="", left_rbl=0, right_rbl=0): def __init__(self, rows, cols, column_offset=0, row_offset=0 ,mirror=0, location="", name="", left_rbl=0, right_rbl=0):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
self.location = location self.location = location
self.row_offset = row_offset self.row_offset = row_offset
self.mirror = mirror self.mirror = mirror
@ -55,17 +55,20 @@ class dummy_array(bitcell_base_array):
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.cell_inst={} self.cell_inst={}
r = self.row_offset
c = self.column_offset
if self.cell.mirror.y: if self.cell.mirror.y:
core_block = [[0 for x in range(2)] for y in range(2)] core_block = [[0 for x in range(2)] for y in range(2)]
core_block[(0+self.mirror) %2][(0+self.column_offset+self.row_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX') core_block[(0 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(0+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='XY')
core_block[(1+self.mirror) %2][(0+self.column_offset+self.row_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True) core_block[(0 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(0 + r)%2}_{(1+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
core_block[(0+self.mirror) %2][(1+self.column_offset+self.row_offset) %2] = geometry.instance("core_0_1", mod=self.dummy_cell, is_bitcell=True, mirror='XY') core_block[(1 + r) % 2][(0+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(0+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='MY')
core_block[(1+self.mirror) %2][(1+self.column_offset+self.row_offset) %2] = geometry.instance("core_1_1", mod=self.dummy_cell, is_bitcell=True, mirror='MY') core_block[(1 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='')
else: else:
core_block = [[0 for x in range(1)] for y in range(2)] core_block = [[0 for x in range(1)] for y in range(2)]
core_block[(1+self.mirror) %2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX') core_block[(0 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_0_0", mod=self.dummy_cell, is_bitcell=True)
core_block[(0+self.mirror) %2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True) core_block[(1 + self.row_offset) % 2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True, mirror='MX')
print(r, c)
print(core_block)
self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size, name_template="bit_r{0}_c{1}") self.pattern = pattern(self, "dummy_array", core_block, num_rows=self.row_size, num_cols=self.column_size, name_template="bit_r{0}_c{1}")
self.pattern.connect_array() self.pattern.connect_array()

View File

@ -147,7 +147,6 @@ class pattern():
def connect_array(self) -> None: def connect_array(self) -> None:
#debug_array = [[None]*12 for _ in range(6)]
row = 0 row = 0
col = 0 col = 0
for i in range(self.num_cores_y): for i in range(self.num_cores_y):
@ -183,7 +182,7 @@ class pattern():
y += inst.height y += inst.height
if "Y" in inst.mirror: if "Y" in inst.mirror:
x += inst.width x += inst.width
#print('placing inst {} at {}'.format(inst, offset)) print('placing inst {} at {}'.format(inst, offset))
inst.place((x, y), inst.mirror, inst.rotate) inst.place((x, y), inst.mirror, inst.rotate)
def place_array(self): def place_array(self):
@ -193,7 +192,7 @@ class pattern():
for row in range(self.row_max+1): for row in range(self.row_max+1):
x = 0 x = 0
for col in range(self.col_max+1): for col in range(self.col_max+1):
inst = self.parent_design.all_inst[self.row_max - row, col] inst = self.parent_design.all_inst[row, col]
self.place_inst(inst, (x, y)) self.place_inst(inst, (x, y))
x += inst.width x += inst.width
y += inst.height y += inst.height

View File

@ -25,7 +25,7 @@ class replica_bitcell_array(bitcell_base_array):
replica bitcell and dummy bitcell (BL/BR disconnected). replica bitcell and dummy bitcell (BL/BR disconnected).
""" """
def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""): def __init__(self, rows, cols, rbl=None, left_rbl=None, right_rbl=None, name=""):
super().__init__(name=name, rows=rows, cols=cols, column_offset=0) super().__init__(name=name, rows=rows, cols=cols, column_offset=0, row_offset=0)
debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name, debug.info(1, "Creating {0} {1} x {2} rbls: {3} left_rbl: {4} right_rbl: {5}".format(self.name,
rows, rows,
cols, cols,
@ -77,6 +77,7 @@ class replica_bitcell_array(bitcell_base_array):
# Bitcell array # Bitcell array
self.bitcell_array = factory.create(module_type="bitcell_array", self.bitcell_array = factory.create(module_type="bitcell_array",
column_offset=len(self.left_rbl), column_offset=len(self.left_rbl),
row_offset=len(self.left_rbl),
cols=self.column_size, cols=self.column_size,
rows=self.row_size, rows=self.row_size,
left_rbl=self.left_rbl, left_rbl=self.left_rbl,
@ -110,20 +111,17 @@ class replica_bitcell_array(bitcell_base_array):
for port in self.all_ports: for port in self.all_ports:
if port in self.left_rbl: if port in self.left_rbl:
row_offset = self.row_size
mirror = row_offset % 2 + 1
elif port in self.right_rbl:
row_offset = 0 row_offset = 0
mirror = 0 elif port in self.right_rbl:
row_offset = self.row_size + len(self.left_rbl)
else: else:
continue row_offset = 0
self.dummy_rows[port] = factory.create(module_type="dummy_array", self.dummy_rows[port] = factory.create(module_type="dummy_array",
cols=self.column_size, cols=self.column_size,
rows=1, rows=1,
row_offset=row_offset, row_offset=row_offset,
column_offset=len(self.left_rbl), column_offset=len(self.left_rbl))
mirror=mirror)
def add_pins(self): def add_pins(self):

View File

@ -30,7 +30,7 @@ class replica_column(bitcell_base_array):
self.row_start = rbl[0] self.row_start = rbl[0]
# End of regular word line rows # End of regular word line rows
self.row_end = self.row_start + rows self.row_end = self.row_start + rows
super().__init__(rows=self.row_size, cols=1, column_offset=column_offset, name=name) super().__init__(rows=self.row_size, cols=1, column_offset=column_offset, row_offset=0, name=name)
self.rows = rows self.rows = rows
self.left_rbl = rbl[0] self.left_rbl = rbl[0]
@ -95,12 +95,12 @@ class replica_column(bitcell_base_array):
# 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.
# All other cells are dummies # All other cells are dummies
if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end): if (row == self.replica_bit) or (row >= self.row_start and row < self.row_end):
if current_row % 2 == 1: if current_row % 2 == 0:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True) core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True)
else: else:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX') core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
else: else:
if current_row % 2 == 1: if current_row % 2 == 0:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True) core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True)
else: else:
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX') core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')

View File

@ -6,16 +6,19 @@
from openram.sram_factory import factory from openram.sram_factory import factory
from openram import OPTS from openram import OPTS
from .bitcell_base_array import bitcell_base_array from .bitcell_base_array import bitcell_base_array
from .pattern import pattern
from openram.base import geometry
from math import ceil
class row_cap_array(bitcell_base_array): class row_cap_array(bitcell_base_array):
""" """
Generate a dummy row/column for the replica array. Generate a dummy row/column for the replica array.
""" """
def __init__(self, rows, cols, column_offset=0, mirror=0, location="", name=""): def __init__(self, rows, cols, column_offset=0, row_offset=0, mirror=0, location="", name=""):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
self.mirror = mirror self.mirror = mirror
self.location = location self.location = location
self.row_offset = row_offset
#self.no_instances = True #self.no_instances = True
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
@ -33,7 +36,7 @@ class row_cap_array(bitcell_base_array):
def create_layout(self): def create_layout(self):
self.place_array("dummy_r{0}_c{1}", self.mirror) self.place_array()
self.add_layout_pins() self.add_layout_pins()
self.width = max([x.rx() for x in self.insts]) self.width = max([x.rx() for x in self.insts])
@ -44,19 +47,37 @@ class row_cap_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.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell)) self.row_cap = factory.create(module_type="row_cap_{}".format(OPTS.bitcell))
self.cell = factory.create(module_type=OPTS.bitcell) self.cell = factory.create(module_type=OPTS.bitcell)
def create_instances(self): def create_instances(self):
""" Create the module instances used in this design """ """ Create the module instances used in this design """
self.cell_inst = {} self.all_inst={}
for col in range(self.column_size): self.cell_inst={}
for row in range(0, self.row_size):
name = "bit_r{0}_c{1}".format(row, col) bit_block = []
self.cell_inst[row, col]=self.add_inst(name=name,
mod=self.dummy_cell) if self.location == "left":
self.connect_inst(self.get_bitcell_pins(row, col)) #top_corner = geometry.instance("row_cap_top_corner", mod=self.top_corner, is_bitcell=False, mirror="MY")
#bottom_corner = geometry.instance("row_cap_bottom_corner", mod=self.bottom_corner, is_bitcell=False, mirror="XY")
rowend = geometry.instance("row_cap_rowend", mod=self.row_cap, is_bitcell=True, mirror="")
rowend_m = geometry.instance("row_cap_rowend_m", mod=self.row_cap, is_bitcell=True, mirror="MX")
elif self.location == "right":
#top_corner = geometry.instance("row_cap_top_corner", mod=self.top_corner, is_bitcell=False)
#bottom_corner = geometry.instance("row_cap_bottom_corner", mod=self.bottom_corner, is_bitcell=False, mirror="MX")
rowend = geometry.instance("row_cap_rowend", mod=self.row_cap, is_bitcell=True, mirror="MY")
rowend_m = geometry.instance("row_cap_rowend_m", mod=self.row_cap, is_bitcell=True, mirror="XY")
#pattern.append_row_to_block(bit_block, [top_corner])
for row in range(0, self.row_size):
if row % 2 == 1:
pattern.append_row_to_block(bit_block, [rowend])
else:
pattern.append_row_to_block(bit_block, [rowend_m])
#pattern.append_row_to_block(bit_block, [bottom_corner])
self.pattern = pattern(self, "row_cap_array_" + self.location, bit_block, num_rows=self.row_size, num_cols=self.column_size, num_cores_x=ceil(self.column_size/2), num_cores_y=ceil(self.row_size/2), name_template="row_cap_array" + self.location + "_r{0}_c{1}")
self.pattern.connect_array_raw()
def get_bitcell_pins(self, row, col): def get_bitcell_pins(self, row, col):
""" """

View File

@ -26,3 +26,4 @@ num_sim_threads = 1
#analytical_delay = False #analytical_delay = False
import os import os
exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read()) exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read())
#tech_file = "tech_custom_cell"

View File

@ -19,8 +19,8 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array):
Creates a rows x cols array of memory cells. Creates a rows x cols array of memory cells.
Assumes bit-lines and word lines are connected by abutment. Assumes bit-lines and word lines are connected by abutment.
""" """
def __init__(self, rows, cols, column_offset=0, name="",left_rbl=None, right_rbl=None): def __init__(self, rows, cols, column_offset=0, row_offset=0, name="",left_rbl=None, right_rbl=None):
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name) super().__init__(rows=rows, cols=cols, column_offset=column_offset, row_offset=row_offset, name=name)
self.left_rbl = left_rbl self.left_rbl = left_rbl
self.right_rbl = right_rbl self.right_rbl = right_rbl

View File

@ -15,5 +15,5 @@ sys.path.append("{}/{}".format(dir_path,'tech_configs'))
if not hasattr(OPTS, 'tech_file'): if not hasattr(OPTS, 'tech_file'):
OPTS.tech_file = 'tech_cypress_cell' OPTS.tech_file = 'tech_cypress_cell'
#TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING #TODO: FIX THIS TERRIBLE HACK JUST FOR TESTING EXECUTING
exec('from {} import *'.format(OPTS.tech_file)) exec('from {} import *'.format(OPTS.tech_file))