mirror of https://github.com/VLSIDA/OpenRAM.git
OpenRAM 1.1.6
This commit is contained in:
commit
b4f5dc4c6e
|
|
@ -36,6 +36,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
else:
|
else:
|
||||||
self.lvs_file = self.sp_file
|
self.lvs_file = self.sp_file
|
||||||
|
|
||||||
|
self.drc_errors = "skipped"
|
||||||
|
self.lvs_errors = "skipped"
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
hierarchy_spice.spice.__init__(self, name)
|
hierarchy_spice.spice.__init__(self, name)
|
||||||
hierarchy_layout.layout.__init__(self, name)
|
hierarchy_layout.layout.__init__(self, name)
|
||||||
|
|
@ -58,41 +61,37 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
# No layout to check
|
# No layout to check
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
return ("skipped", "skipped")
|
return
|
||||||
# Unit tests will check themselves.
|
# Unit tests will check themselves.
|
||||||
if not force_check and OPTS.is_unit_test:
|
elif not force_check and OPTS.is_unit_test:
|
||||||
return ("skipped", "skipped")
|
return
|
||||||
if not force_check and not OPTS.check_lvsdrc:
|
elif not force_check and not OPTS.check_lvsdrc:
|
||||||
return ("skipped", "skipped")
|
return
|
||||||
# Do not run if disabled in options.
|
# Do not run if disabled in options.
|
||||||
if (OPTS.inline_lvsdrc or force_check or final_verification):
|
elif (OPTS.inline_lvsdrc or force_check or final_verification):
|
||||||
|
|
||||||
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.lvs_write(tempspice)
|
self.lvs_write(tempspice)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
# Final verification option does not allow nets to be connected by label.
|
# Final verification option does not allow nets to be connected by label.
|
||||||
num_drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
|
self.drc_errors = verify.run_drc(self.name, tempgds, extract=True, final_verification=final_verification)
|
||||||
num_lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
self.lvs_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
|
||||||
|
|
||||||
# force_check is used to determine decoder height and other things, so we shouldn't fail
|
# force_check is used to determine decoder height and other things, so we shouldn't fail
|
||||||
# if that flag is set
|
# if that flag is set
|
||||||
if OPTS.inline_lvsdrc and not force_check:
|
if OPTS.inline_lvsdrc and not force_check:
|
||||||
debug.check(num_drc_errors == 0,
|
debug.check(self.drc_errors == 0,
|
||||||
"DRC failed for {0} with {1} error(s)".format(self.name,
|
"DRC failed for {0} with {1} error(s)".format(self.name,
|
||||||
num_drc_errors))
|
self.drc_errors))
|
||||||
debug.check(num_lvs_errors == 0,
|
debug.check(self.lvs_errors == 0,
|
||||||
"LVS failed for {0} with {1} errors(s)".format(self.name,
|
"LVS failed for {0} with {1} errors(s)".format(self.name,
|
||||||
num_lvs_errors))
|
self.lvs_errors))
|
||||||
|
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
return (num_drc_errors, num_lvs_errors)
|
|
||||||
else:
|
|
||||||
return ("skipped", "skipped")
|
|
||||||
|
|
||||||
def DRC(self, final_verification=False):
|
def DRC(self, final_verification=False):
|
||||||
"""Checks DRC for a module"""
|
"""Checks DRC for a module"""
|
||||||
import verify
|
import verify
|
||||||
|
|
@ -102,9 +101,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
# No layout to check
|
# No layout to check
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
return "skipped"
|
return
|
||||||
|
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.gds_write(tempgds)
|
self.gds_write(tempgds)
|
||||||
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
|
num_errors = verify.run_drc(self.name, tempgds, final_verification=final_verification)
|
||||||
|
|
@ -115,10 +113,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
if OPTS.purge_temp:
|
if OPTS.purge_temp:
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
return num_errors
|
|
||||||
else:
|
|
||||||
return "skipped"
|
|
||||||
|
|
||||||
def LVS(self, final_verification=False):
|
def LVS(self, final_verification=False):
|
||||||
"""Checks LVS for a module"""
|
"""Checks LVS for a module"""
|
||||||
import verify
|
import verify
|
||||||
|
|
@ -128,9 +122,8 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
|
|
||||||
# No layout to check
|
# No layout to check
|
||||||
if OPTS.netlist_only:
|
if OPTS.netlist_only:
|
||||||
return "skipped"
|
return
|
||||||
|
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
||||||
if (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)):
|
|
||||||
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name)
|
||||||
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
|
||||||
self.lvs_write(tempspice)
|
self.lvs_write(tempspice)
|
||||||
|
|
@ -143,10 +136,6 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
|
||||||
os.remove(tempspice)
|
os.remove(tempspice)
|
||||||
os.remove(tempgds)
|
os.remove(tempgds)
|
||||||
|
|
||||||
return num_errors
|
|
||||||
else:
|
|
||||||
return "skipped"
|
|
||||||
|
|
||||||
def init_graph_params(self):
|
def init_graph_params(self):
|
||||||
"""Initializes parameters relevant to the graph creation"""
|
"""Initializes parameters relevant to the graph creation"""
|
||||||
# Only initializes a set for checking instances which should not be added
|
# Only initializes a set for checking instances which should not be added
|
||||||
|
|
|
||||||
|
|
@ -658,11 +658,7 @@ class lib:
|
||||||
|
|
||||||
# information of checks
|
# information of checks
|
||||||
# run it only the first time
|
# run it only the first time
|
||||||
try:
|
datasheet.write("{0},{1},".format(self.sram.drc_errors, self.sram.lvs_errors))
|
||||||
datasheet.write("{0},{1},".format(self.drc_errors, self.lvs_errors))
|
|
||||||
except AttributeError:
|
|
||||||
(self.drc_errors, self.lvs_errors) = self.sram.DRC_LVS(final_verification=True)
|
|
||||||
datasheet.write("{0},{1},".format(self.drc_errors, self.lvs_errors))
|
|
||||||
|
|
||||||
# write area
|
# write area
|
||||||
datasheet.write(str(self.sram.width * self.sram.height) + ',')
|
datasheet.write(str(self.sram.width * self.sram.height) + ',')
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
word_size = 4
|
||||||
|
num_words = 64
|
||||||
|
words_per_row = 2
|
||||||
|
|
||||||
|
num_rw_ports = 1
|
||||||
|
num_r_ports = 0
|
||||||
|
num_w_ports = 0
|
||||||
|
|
||||||
|
tech_name = "scn4m_subm"
|
||||||
|
nominal_corners_only = False
|
||||||
|
process_corners = ["TT"]
|
||||||
|
supply_voltages = [5.0]
|
||||||
|
temperatures = [25]
|
||||||
|
|
||||||
|
# route_supplies = True
|
||||||
|
check_lvsdrc = True
|
||||||
|
|
||||||
|
output_path = "temp"
|
||||||
|
output_name = "sram_1rw_{0}_{1}_{2}".format(word_size,
|
||||||
|
num_words,
|
||||||
|
tech_name)
|
||||||
|
|
@ -54,7 +54,10 @@ from sram_config import sram_config
|
||||||
c = sram_config(word_size=OPTS.word_size,
|
c = sram_config(word_size=OPTS.word_size,
|
||||||
num_words=OPTS.num_words,
|
num_words=OPTS.num_words,
|
||||||
write_size=OPTS.write_size,
|
write_size=OPTS.write_size,
|
||||||
num_spare_rows=OPTS.num_spare_rows)
|
num_banks=OPTS.num_banks,
|
||||||
|
words_per_row=OPTS.words_per_row,
|
||||||
|
num_spare_rows=OPTS.num_spare_rows,
|
||||||
|
num_spare_cols=OPTS.num_spare_cols)
|
||||||
debug.print_raw("Words per row: {}".format(c.words_per_row))
|
debug.print_raw("Words per row: {}".format(c.words_per_row))
|
||||||
|
|
||||||
output_extensions = ["lvs", "sp", "v", "lib", "py", "html", "log"]
|
output_extensions = ["lvs", "sp", "v", "lib", "py", "html", "log"]
|
||||||
|
|
|
||||||
|
|
@ -44,8 +44,9 @@ class options(optparse.Values):
|
||||||
# word_size = 0
|
# word_size = 0
|
||||||
# You can manually specify banks, but it is better to auto-detect it.
|
# You can manually specify banks, but it is better to auto-detect it.
|
||||||
num_banks = 1
|
num_banks = 1
|
||||||
|
words_per_row = None
|
||||||
num_spare_rows = 0
|
num_spare_rows = 0
|
||||||
# num_spare_cols = 0
|
num_spare_cols = 0
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# Optimization options
|
# Optimization options
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,6 @@ from vector import vector
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
|
|
||||||
if(OPTS.tech_name == "sky130"):
|
|
||||||
from tech import nmos_bins, pmos_bins
|
|
||||||
|
|
||||||
|
|
||||||
class pinv_dec(pinv.pinv):
|
class pinv_dec(pinv.pinv):
|
||||||
"""
|
"""
|
||||||
This is another version of pinv but with layout for the decoder.
|
This is another version of pinv but with layout for the decoder.
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,6 @@ from vector import vector
|
||||||
from sram_factory import factory
|
from sram_factory import factory
|
||||||
import contact
|
import contact
|
||||||
import logical_effort
|
import logical_effort
|
||||||
import os
|
|
||||||
from globals import OPTS
|
from globals import OPTS
|
||||||
from pgate import pgate
|
from pgate import pgate
|
||||||
|
|
||||||
|
|
@ -120,24 +119,23 @@ class ptx(design.design):
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
pin_list = ["D", "G", "S", "B"]
|
pin_list = ["D", "G", "S", "B"]
|
||||||
if self.tx_type == "nmos":
|
if self.tx_type == "nmos":
|
||||||
body_dir = 'GROUND'
|
body_dir = "GROUND"
|
||||||
else:
|
else:
|
||||||
# Assumed that the check for either pmos or nmos is done elsewhere.
|
body_dir = "POWER"
|
||||||
body_dir = 'POWER'
|
dir_list = ["INOUT", "INPUT", "INOUT", body_dir]
|
||||||
dir_list = ['INOUT', 'INPUT', 'INOUT', body_dir]
|
|
||||||
self.add_pin_list(pin_list, dir_list)
|
self.add_pin_list(pin_list, dir_list)
|
||||||
|
|
||||||
# Just make a guess since these will actually
|
# Just make a guess since these will actually
|
||||||
# be decided in the layout later.
|
# be decided in the layout later.
|
||||||
area_sd = 2.5 * self.poly_width * self.tx_width
|
area_sd = 2.5 * self.poly_width * self.tx_width
|
||||||
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
|
||||||
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
|
if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
|
||||||
# sky130 simulation cannot use the mult parameter in simulation
|
# sky130 simulation cannot use the mult parameter in simulation
|
||||||
(self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width)
|
(self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width)
|
||||||
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
|
||||||
self.mults,
|
self.mults,
|
||||||
self.tx_width,
|
self.tx_width,
|
||||||
drc("minwidth_poly"))
|
drc("minwidth_poly"))
|
||||||
# Perimeters are in microns
|
# Perimeters are in microns
|
||||||
# Area is in u since it is microns square
|
# Area is in u since it is microns square
|
||||||
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
|
area_str = "pd={0:.2f} ps={0:.2f} as={1:.2f}u ad={1:.2f}u".format(perimeter_sd,
|
||||||
|
|
@ -152,7 +150,7 @@ class ptx(design.design):
|
||||||
self.spice_device = main_str + area_str
|
self.spice_device = main_str + area_str
|
||||||
self.spice.append("\n* ptx " + self.spice_device)
|
self.spice.append("\n* ptx " + self.spice_device)
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130" and OPTS.lvs_exe[0] == "calibre":
|
if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
|
||||||
# sky130 requires mult parameter too
|
# sky130 requires mult parameter too
|
||||||
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
|
self.lvs_device = "M{{0}} {{1}} {0} m={1} w={2} l={3} mult={1}".format(spice[self.tx_type],
|
||||||
self.mults,
|
self.mults,
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@ class single_level_column_mux(pgate.pgate):
|
||||||
return "br"
|
return "br"
|
||||||
|
|
||||||
def create_netlist(self):
|
def create_netlist(self):
|
||||||
self.add_modules()
|
|
||||||
self.add_pins()
|
self.add_pins()
|
||||||
self.add_ptx()
|
self.add_ptx()
|
||||||
|
|
||||||
|
|
@ -54,6 +53,9 @@ class single_level_column_mux(pgate.pgate):
|
||||||
self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer))
|
self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer))
|
||||||
self.pin_width = getattr(self, "{}_width".format(self.pin_layer))
|
self.pin_width = getattr(self, "{}_width".format(self.pin_layer))
|
||||||
self.pin_height = 2 * self.pin_width
|
self.pin_height = 2 * self.pin_width
|
||||||
|
|
||||||
|
self.place_ptx()
|
||||||
|
|
||||||
self.width = self.bitcell.width
|
self.width = self.bitcell.width
|
||||||
self.height = self.nmos_upper.uy() + self.pin_height
|
self.height = self.nmos_upper.uy() + self.pin_height
|
||||||
|
|
||||||
|
|
@ -62,7 +64,7 @@ class single_level_column_mux(pgate.pgate):
|
||||||
self.connect_bitlines()
|
self.connect_bitlines()
|
||||||
self.add_pn_wells()
|
self.add_pn_wells()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_ptx(self):
|
||||||
self.bitcell = factory.create(module_type="bitcell")
|
self.bitcell = factory.create(module_type="bitcell")
|
||||||
|
|
||||||
# Adds nmos_lower,nmos_upper to the module
|
# Adds nmos_lower,nmos_upper to the module
|
||||||
|
|
@ -71,6 +73,16 @@ class single_level_column_mux(pgate.pgate):
|
||||||
width=self.ptx_width)
|
width=self.ptx_width)
|
||||||
self.add_mod(self.nmos)
|
self.add_mod(self.nmos)
|
||||||
|
|
||||||
|
# Space it in the center
|
||||||
|
self.nmos_lower = self.add_inst(name="mux_tx1",
|
||||||
|
mod=self.nmos)
|
||||||
|
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
|
||||||
|
|
||||||
|
# This aligns it directly above the other tx with gates abutting
|
||||||
|
self.nmos_upper = self.add_inst(name="mux_tx2",
|
||||||
|
mod=self.nmos)
|
||||||
|
self.connect_inst(["br", "sel", "br_out", "gnd"])
|
||||||
|
|
||||||
def add_pins(self):
|
def add_pins(self):
|
||||||
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
||||||
|
|
||||||
|
|
@ -100,24 +112,18 @@ class single_level_column_mux(pgate.pgate):
|
||||||
offset=br_pos,
|
offset=br_pos,
|
||||||
height=self.pin_height)
|
height=self.pin_height)
|
||||||
|
|
||||||
def add_ptx(self):
|
def place_ptx(self):
|
||||||
""" Create the two pass gate NMOS transistors to switch the bitlines"""
|
""" Create the two pass gate NMOS transistors to switch the bitlines"""
|
||||||
|
|
||||||
# Space it in the center
|
# Space it in the center
|
||||||
nmos_lower_position = self.nmos.active_offset.scale(0, 1) \
|
nmos_lower_position = self.nmos.active_offset.scale(0, 1) \
|
||||||
+ vector(0.5 * self.bitcell.width- 0.5 * self.nmos.active_width, 0)
|
+ vector(0.5 * self.bitcell.width- 0.5 * self.nmos.active_width, 0)
|
||||||
self.nmos_lower = self.add_inst(name="mux_tx1",
|
self.nmos_lower.place(nmos_lower_position)
|
||||||
mod=self.nmos,
|
|
||||||
offset=nmos_lower_position)
|
|
||||||
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
|
|
||||||
|
|
||||||
# This aligns it directly above the other tx with gates abutting
|
# This aligns it directly above the other tx with gates abutting
|
||||||
nmos_upper_position = nmos_lower_position \
|
nmos_upper_position = nmos_lower_position \
|
||||||
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
|
+ vector(0, self.nmos.active_height + max(self.active_space, self.poly_space))
|
||||||
self.nmos_upper = self.add_inst(name="mux_tx2",
|
self.nmos_upper.place(nmos_upper_position)
|
||||||
mod=self.nmos,
|
|
||||||
offset=nmos_upper_position)
|
|
||||||
self.connect_inst(["br", "sel", "br_out", "gnd"])
|
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if OPTS.tech_name == "sky130":
|
||||||
self.add_implants()
|
self.add_implants()
|
||||||
|
|
|
||||||
|
|
@ -129,7 +129,7 @@ class sram_base(design, verilog, lef):
|
||||||
|
|
||||||
start_time = datetime.datetime.now()
|
start_time = datetime.datetime.now()
|
||||||
# We only enable final verification if we have routed the design
|
# We only enable final verification if we have routed the design
|
||||||
self.DRC_LVS(final_verification=OPTS.route_supplies)
|
self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=True)
|
||||||
if not OPTS.is_unit_test:
|
if not OPTS.is_unit_test:
|
||||||
print_time("Verification", datetime.datetime.now(), start_time)
|
print_time("Verification", datetime.datetime.now(), start_time)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from sram_factory import factory
|
||||||
class sram_config:
|
class sram_config:
|
||||||
""" This is a structure that is used to hold the SRAM configuration options. """
|
""" This is a structure that is used to hold the SRAM configuration options. """
|
||||||
|
|
||||||
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=None):
|
def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=0):
|
||||||
self.word_size = word_size
|
self.word_size = word_size
|
||||||
self.num_words = num_words
|
self.num_words = num_words
|
||||||
self.write_size = write_size
|
self.write_size = write_size
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,15 @@ if not OPTS.check_lvsdrc:
|
||||||
OPTS.drc_exe = None
|
OPTS.drc_exe = None
|
||||||
OPTS.lvs_exe = None
|
OPTS.lvs_exe = None
|
||||||
OPTS.pex_exe = None
|
OPTS.pex_exe = None
|
||||||
|
if OPTS.tech_name == "sky130":
|
||||||
|
OPTS.magic_exe = None
|
||||||
else:
|
else:
|
||||||
debug.info(1, "Finding DRC/LVS/PEX tools.")
|
debug.info(1, "Finding DRC/LVS/PEX tools.")
|
||||||
OPTS.drc_exe = get_tool("DRC", ["calibre", "assura", "magic"], drc_name)
|
OPTS.drc_exe = get_tool("DRC", ["calibre", "assura", "magic"], drc_name)
|
||||||
OPTS.lvs_exe = get_tool("LVS", ["calibre", "assura", "netgen"], lvs_name)
|
OPTS.lvs_exe = get_tool("LVS", ["calibre", "assura", "netgen"], lvs_name)
|
||||||
OPTS.pex_exe = get_tool("PEX", ["calibre", "magic"], pex_name)
|
OPTS.pex_exe = get_tool("PEX", ["calibre", "magic"], pex_name)
|
||||||
if OPTS.tech_name == "sky130":
|
if OPTS.tech_name == "sky130":
|
||||||
OPTS.magic_exe = get_tool("GDS", ["magic"], None)
|
OPTS.magic_exe = get_tool("GDS", ["magic"])
|
||||||
|
|
||||||
if not OPTS.drc_exe:
|
if not OPTS.drc_exe:
|
||||||
from .none import run_drc, print_drc_stats
|
from .none import run_drc, print_drc_stats
|
||||||
|
|
@ -71,7 +73,7 @@ else:
|
||||||
debug.warning("Did not find a supported PEX tool.")
|
debug.warning("Did not find a supported PEX tool.")
|
||||||
|
|
||||||
if OPTS.tech_name == "sky130":
|
if OPTS.tech_name == "sky130":
|
||||||
if "magic"==OPTS.magic_exe[0]:
|
if OPTS.magic_exe and "magic"==OPTS.magic_exe[0]:
|
||||||
from .magic import filter_gds
|
from .magic import filter_gds
|
||||||
else:
|
else:
|
||||||
debug.warning("Did not find Magic.")
|
debug.warning("Did not find Magic.")
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue