mirror of https://github.com/VLSIDA/OpenRAM.git
dual port rba lvs clean again with cell library changes
This commit is contained in:
parent
b6d98c44d5
commit
515591a422
|
|
@ -19,8 +19,8 @@ class bitcell_array(bitcell_base_array):
|
|||
Creates a rows x cols array of memory cells.
|
||||
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):
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
|
||||
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, row_offset=row_offset, name=name)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, 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)
|
||||
|
||||
def create_instances(self):
|
||||
r = self.row_offset
|
||||
c = self.column_offset
|
||||
self.cell_inst={}
|
||||
if self.cell.mirror.y:
|
||||
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[1][0] = geometry.instance("core_1_0", 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][1] = geometry.instance("core_1_1", mod=self.cell, is_bitcell=True, mirror='XY')
|
||||
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[(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[(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 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.cell, is_bitcell=True, mirror='')
|
||||
else:
|
||||
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[1][0] = geometry.instance("core_1_0", mod=self.cell, is_bitcell=True, mirror='MX')
|
||||
|
||||
core_block = [[0 for x in range(1)] for y in range(2)]
|
||||
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 + 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.connect_array()
|
||||
|
|
|
|||
|
|
@ -16,14 +16,14 @@ class bitcell_base_array(design):
|
|||
"""
|
||||
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)
|
||||
debug.info(1, "Creating {0} {1} x {2}".format(self.name, rows, cols))
|
||||
|
||||
self.column_size = cols
|
||||
self.row_size = rows
|
||||
self.column_offset = column_offset
|
||||
|
||||
self.row_offset = row_offset
|
||||
# Bitcell for port names only
|
||||
self.cell = factory.create(module_type=OPTS.bitcell)
|
||||
|
||||
|
|
@ -170,6 +170,18 @@ class bitcell_base_array(design):
|
|||
|
||||
power_name = 'vdd'
|
||||
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:
|
||||
from openram.tech import cell_properties
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class capped_replica_bitcell_array(bitcell_base_array):
|
|||
sides of a bitcell array.
|
||||
"""
|
||||
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,
|
||||
rows,
|
||||
cols,
|
||||
|
|
|
|||
|
|
@ -8,12 +8,13 @@ from openram import OPTS
|
|||
from .bitcell_base_array import bitcell_base_array
|
||||
from openram.base import geometry
|
||||
from .pattern import pattern
|
||||
from math import ceil
|
||||
|
||||
class col_cap_array(bitcell_base_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)
|
||||
self.mirror = mirror
|
||||
self.location = location
|
||||
|
|
@ -38,28 +39,44 @@ class col_cap_array(bitcell_base_array):
|
|||
|
||||
def create_layout(self):
|
||||
|
||||
self.place_array("dummy_r{0}_c{1}", self.mirror)
|
||||
self.place_array()
|
||||
self.add_layout_pins()
|
||||
|
||||
self.height = self.dummy_cell.height
|
||||
self.width = self.column_size * self.cell.width
|
||||
#self.height = self.dummy_cell.height
|
||||
#self.width = self.column_size * self.cell.width
|
||||
|
||||
self.add_boundary()
|
||||
self.DRC_LVS()
|
||||
|
||||
def add_modules(self):
|
||||
""" Add the modules used in this design """
|
||||
self.dummy_cell = factory.create(module_type="col_cap_{}".format(OPTS.bitcell))
|
||||
self.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):
|
||||
""" 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))
|
||||
self.cell_inst={}
|
||||
if self.location == "top":
|
||||
bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="MY")]\
|
||||
+ [geometry.instance("01_colend", mod=self.colend, is_bitcell=True)]
|
||||
elif self.location == "bottom":
|
||||
bit_row = [geometry.instance("00_colend", mod=self.colend, is_bitcell=True, mirror="XY")]\
|
||||
+ [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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
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.row_offset = row_offset
|
||||
self.mirror = mirror
|
||||
|
|
@ -55,17 +55,20 @@ class dummy_array(bitcell_base_array):
|
|||
def create_instances(self):
|
||||
""" Create the module instances used in this design """
|
||||
self.cell_inst={}
|
||||
r = self.row_offset
|
||||
c = self.column_offset
|
||||
if self.cell.mirror.y:
|
||||
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[(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+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+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[(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[(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[(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 + r) % 2][(1+c) %2] = geometry.instance(f"core_{(1 + r)%2}_{(1+c)%2}", mod=self.dummy_cell, is_bitcell=True, mirror='')
|
||||
else:
|
||||
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.mirror) %2][(0+self.column_offset) %2] = geometry.instance("core_1_0", mod=self.dummy_cell, is_bitcell=True)
|
||||
|
||||
core_block = [[0 for x in range(1)] for y in range(2)]
|
||||
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[(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.connect_array()
|
||||
|
|
|
|||
|
|
@ -147,7 +147,6 @@ class pattern():
|
|||
|
||||
def connect_array(self) -> None:
|
||||
|
||||
#debug_array = [[None]*12 for _ in range(6)]
|
||||
row = 0
|
||||
col = 0
|
||||
for i in range(self.num_cores_y):
|
||||
|
|
@ -183,7 +182,7 @@ class pattern():
|
|||
y += inst.height
|
||||
if "Y" in inst.mirror:
|
||||
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)
|
||||
|
||||
def place_array(self):
|
||||
|
|
@ -193,7 +192,7 @@ class pattern():
|
|||
for row in range(self.row_max+1):
|
||||
x = 0
|
||||
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))
|
||||
x += inst.width
|
||||
y += inst.height
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
replica bitcell and dummy bitcell (BL/BR disconnected).
|
||||
"""
|
||||
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,
|
||||
rows,
|
||||
cols,
|
||||
|
|
@ -77,6 +77,7 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
# Bitcell array
|
||||
self.bitcell_array = factory.create(module_type="bitcell_array",
|
||||
column_offset=len(self.left_rbl),
|
||||
row_offset=len(self.left_rbl),
|
||||
cols=self.column_size,
|
||||
rows=self.row_size,
|
||||
left_rbl=self.left_rbl,
|
||||
|
|
@ -110,20 +111,17 @@ class replica_bitcell_array(bitcell_base_array):
|
|||
|
||||
for port in self.all_ports:
|
||||
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
|
||||
mirror = 0
|
||||
elif port in self.right_rbl:
|
||||
row_offset = self.row_size + len(self.left_rbl)
|
||||
else:
|
||||
continue
|
||||
row_offset = 0
|
||||
|
||||
self.dummy_rows[port] = factory.create(module_type="dummy_array",
|
||||
cols=self.column_size,
|
||||
rows=1,
|
||||
row_offset=row_offset,
|
||||
column_offset=len(self.left_rbl),
|
||||
mirror=mirror)
|
||||
column_offset=len(self.left_rbl))
|
||||
|
||||
def add_pins(self):
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ class replica_column(bitcell_base_array):
|
|||
self.row_start = rbl[0]
|
||||
# End of regular word line 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.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.
|
||||
# All other cells are dummies
|
||||
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)
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.replica_cell, is_bitcell=True, mirror='MX')
|
||||
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)
|
||||
else:
|
||||
core_block[row][0] = geometry.instance("rbc_{}".format(row), mod=self.dummy_cell, is_bitcell=True, mirror='MX')
|
||||
|
|
|
|||
|
|
@ -6,16 +6,19 @@
|
|||
from openram.sram_factory import factory
|
||||
from openram import OPTS
|
||||
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):
|
||||
"""
|
||||
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)
|
||||
self.mirror = mirror
|
||||
self.location = location
|
||||
self.row_offset = row_offset
|
||||
#self.no_instances = True
|
||||
self.create_netlist()
|
||||
if not OPTS.netlist_only:
|
||||
|
|
@ -33,7 +36,7 @@ class row_cap_array(bitcell_base_array):
|
|||
|
||||
def create_layout(self):
|
||||
|
||||
self.place_array("dummy_r{0}_c{1}", self.mirror)
|
||||
self.place_array()
|
||||
self.add_layout_pins()
|
||||
|
||||
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):
|
||||
""" 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)
|
||||
|
||||
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(0, 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))
|
||||
self.all_inst={}
|
||||
self.cell_inst={}
|
||||
|
||||
bit_block = []
|
||||
|
||||
if self.location == "left":
|
||||
#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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -26,3 +26,4 @@ num_sim_threads = 1
|
|||
#analytical_delay = False
|
||||
import os
|
||||
exec(open(os.path.join(os.path.dirname(__file__), 'sky130_sram_common.py')).read())
|
||||
#tech_file = "tech_custom_cell"
|
||||
|
|
@ -19,8 +19,8 @@ class sky130_bitcell_array(bitcell_array, sky130_bitcell_base_array):
|
|||
Creates a rows x cols array of memory cells.
|
||||
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):
|
||||
super().__init__(rows=rows, cols=cols, column_offset=column_offset, name=name)
|
||||
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, row_offset=row_offset, name=name)
|
||||
self.left_rbl = left_rbl
|
||||
self.right_rbl = right_rbl
|
||||
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ sys.path.append("{}/{}".format(dir_path,'tech_configs'))
|
|||
|
||||
if not hasattr(OPTS, 'tech_file'):
|
||||
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))
|
||||
|
|
|
|||
Loading…
Reference in New Issue