Merge remote-tracking branch 'private/drclvs' into dev

This commit is contained in:
mrg 2020-11-12 16:01:07 -08:00
commit 662d4ea724
9 changed files with 124 additions and 152 deletions

View File

@ -73,11 +73,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
elif (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)
self.lvs_write(tempspice) self.lvs_write(tempspice)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
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.
self.drc_errors = verify.run_drc(self.cell_name, tempgds, extract=True, final_verification=final_verification) self.drc_errors = verify.run_drc(self.cell_name, tempgds, tempspice, extract=True, final_verification=final_verification)
self.lvs_errors = verify.run_lvs(self.cell_name, tempgds, tempspice, final_verification=final_verification) self.lvs_errors = verify.run_lvs(self.cell_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
@ -105,9 +105,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only: if OPTS.netlist_only:
return return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): elif (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.cell_name) tempspice = "{0}{1}.sp".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, self.cell_name)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_drc(self.cell_name, tempgds, final_verification=final_verification) num_errors = verify.run_drc(self.cell_name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0, debug.check(num_errors == 0,
"DRC failed for {0} with {1} error(s)".format(self.cell_name, "DRC failed for {0} with {1} error(s)".format(self.cell_name,
num_errors)) num_errors))
@ -126,9 +128,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout):
if OPTS.netlist_only: if OPTS.netlist_only:
return return
elif (not OPTS.is_unit_test and OPTS.check_lvsdrc and (OPTS.inline_lvsdrc or final_verification)): elif (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.cell_name) tempspice = "{0}{1}.sp".format(OPTS.openram_temp, self.cell_name)
tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name)
self.lvs_write(tempspice) self.lvs_write(tempspice)
tempgds = "{0}{1}.gds".format(OPTS.openram_temp, self.name)
self.gds_write(tempgds) self.gds_write(tempgds)
num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification)
debug.check(num_errors == 0, debug.check(num_errors == 0,

View File

@ -296,6 +296,18 @@ class spice():
sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name, sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name,
" ".join(self.pins))) " ".join(self.pins)))
# write a PININFO line
pin_info = "*.PININFO"
for pin in self.pins:
if self.pin_type[pin] == "INPUT":
pin_info += " {0}:I".format(pin)
elif self.pin_type[pin] == "OUTPUT":
pin_info += " {0}:O".format(pin)
else:
pin_info += " {0}:B".format(pin)
sp.write(pin_info + "\n")
# Also write pins as comments
for pin in self.pins: for pin in self.pins:
sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin])) sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin]))

View File

@ -5,7 +5,6 @@
# #
from bitcell_base_array import bitcell_base_array from bitcell_base_array import bitcell_base_array
from sram_factory import factory from sram_factory import factory
from tech import cell_properties as props
from globals import OPTS from globals import OPTS
@ -77,15 +76,17 @@ class dummy_array(bitcell_base_array):
for col in range(self.column_size): for col in range(self.column_size):
for port in self.all_ports: for port in self.all_ports:
bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port])
self.add_rect(layer=bl_pin.layer, self.add_layout_pin(text="bl_{0}_{1}".format(port, col),
offset=bl_pin.ll().scale(1, 0), layer=bl_pin.layer,
width=bl_pin.width(), offset=bl_pin.ll().scale(1, 0),
height=self.height) width=bl_pin.width(),
height=self.height)
br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1])
self.add_rect(layer=br_pin.layer, self.add_layout_pin(text="br_{0}_{1}".format(port, col),
offset=br_pin.ll().scale(1, 0), layer=br_pin.layer,
width=br_pin.width(), offset=br_pin.ll().scale(1, 0),
height=self.height) width=br_pin.width(),
height=self.height)
wl_names = self.cell.get_all_wl_names() wl_names = self.cell.get_all_wl_names()
for row in range(self.row_size): for row in range(self.row_size):

View File

@ -1,69 +0,0 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2019 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os,re
#sys.path.append(os.getenv("OPENRAM_HOME"))
import globals
from globals import OPTS
import debug
class library_drc_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
globals.init_openram(config_file)
import verify
(gds_dir, allnames) = setup_files()
drc_errors = 0
debug.info(1, "\nPerforming DRC on: " + ", ".join(allnames))
for f in allnames:
gds_name = "{0}/{1}.gds".format(gds_dir, f)
if not os.path.isfile(gds_name):
drc_errors += 1
debug.error("Missing GDS file: {}".format(gds_name))
drc_errors += verify.run_drc(f, gds_name)
# fails if there are any DRC errors on any cells
self.assertEqual(drc_errors, 0)
globals.end_openram()
def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib"
files = os.listdir(gds_dir)
nametest = re.compile("\.gds$", re.IGNORECASE)
gds_files = list(filter(nametest.search, files))
tempnames = gds_files
# remove the .gds and .sp suffixes
for i in range(len(tempnames)):
gds_files[i] = re.sub('\.gds$', '', tempnames[i])
try:
from tech import blackbox_cells
nameset = list(set(tempnames) - set(blackbox_cells))
except ImportError:
# remove duplicate base names
nameset = set(tempnames)
allnames = list(nameset)
return (gds_dir, allnames)
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = globals.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())

View File

@ -36,13 +36,14 @@ class library_lvs_test(openram_test):
if not os.path.isfile(sp_name): if not os.path.isfile(sp_name):
lvs_errors += 1 lvs_errors += 1
debug.error("Missing SPICE file {}".format(sp_name)) debug.error("Missing SPICE file {}".format(sp_name))
drc_errors += verify.run_drc(name, gds_name) drc_errors += verify.run_drc(name, gds_name, sp_name)
lvs_errors += verify.run_lvs(f, gds_name, sp_name) lvs_errors += verify.run_lvs(f, gds_name, sp_name)
# fail if the error count is not zero # fail if the error count is not zero
self.assertEqual(drc_errors+lvs_errors, 0) self.assertEqual(drc_errors + lvs_errors, 0)
globals.end_openram() globals.end_openram()
def setup_files(): def setup_files():
gds_dir = OPTS.openram_tech + "/gds_lib" gds_dir = OPTS.openram_tech + "/gds_lib"
sp_dir = OPTS.openram_tech + "/lvs_lib" sp_dir = OPTS.openram_tech + "/lvs_lib"

View File

@ -25,7 +25,7 @@ class openram_test(unittest.TestCase):
w.gds_write(tempgds) w.gds_write(tempgds)
import verify import verify
result=verify.run_drc(w.name, tempgds) result=verify.run_drc(w.name, tempgds, None)
if result != 0: if result != 0:
self.fail("DRC failed: {}".format(w.name)) self.fail("DRC failed: {}".format(w.name))
@ -48,7 +48,7 @@ class openram_test(unittest.TestCase):
# Run both DRC and LVS even if DRC might fail # Run both DRC and LVS even if DRC might fail
# Magic can still extract despite DRC failing, so it might be ok in some techs # Magic can still extract despite DRC failing, so it might be ok in some techs
# if we ignore things like minimum metal area of pins # if we ignore things like minimum metal area of pins
drc_result=verify.run_drc(a.name, tempgds, extract=True, final_verification=final_verification) drc_result=verify.run_drc(a.name, tempgds, tempspice, extract=True, final_verification=final_verification)
# We can still run LVS even if DRC fails in Magic OR Calibre # We can still run LVS even if DRC fails in Magic OR Calibre
lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification) lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification)

View File

@ -30,9 +30,13 @@ num_lvs_runs = 0
num_pex_runs = 0 num_pex_runs = 0
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None):
""" Write a Calibre runset file and script to run DRC """ """ Write a Calibre runset file and script to run DRC """
# the runset file contains all the options to run calibre # the runset file contains all the options to run calibre
if not output_path:
output_path = OPTS.openram_temp
from tech import drc from tech import drc
drc_rules = drc["drc_rules"] drc_rules = drc["drc_rules"]
@ -68,9 +72,12 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
return drc_runset return drc_runset
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
""" Write a Calibre runset file and script to run LVS """ """ Write a Calibre runset file and script to run LVS """
if not output_path:
output_path = OPTS.openram_temp
from tech import drc from tech import drc
lvs_rules = drc["lvs_rules"] lvs_rules = drc["lvs_rules"]
lvs_runset = { lvs_runset = {
@ -132,8 +139,12 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa
return lvs_runset return lvs_runset
def write_pex_script(cell_name, extract, output, final_verification, output_path): def write_pex_script(cell_name, extract, output, final_verification=False, output_path=None):
""" Write a pex script that can either just extract the netlist or the netlist+parasitics """ """ Write a pex script that can either just extract the netlist or the netlist+parasitics """
if not output_path:
output_path = OPTS.openram_temp
if output == None: if output == None:
output = cell_name + ".pex.sp" output = cell_name + ".pex.sp"
@ -142,7 +153,7 @@ def write_pex_script(cell_name, extract, output, final_verification, output_path
if not os.path.isfile(output_path + cell_name + ".lvs.report"): if not os.path.isfile(output_path + cell_name + ".lvs.report"):
gds_name = output_path +"/"+ cell_name + ".gds" gds_name = output_path +"/"+ cell_name + ".gds"
sp_name = output_path +"/"+ cell_name + ".sp" sp_name = output_path +"/"+ cell_name + ".sp"
run_drc(cell_name, gds_name) run_drc(cell_name, gds_name, sp_name)
run_lvs(cell_name, gds_name, sp_name) run_lvs(cell_name, gds_name, sp_name)
from tech import drc from tech import drc
@ -181,7 +192,7 @@ def write_pex_script(cell_name, extract, output, final_verification, output_path
return pex_runset return pex_runset
def run_drc(cell_name, gds_name, extract=False, final_verification=False): def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False):
"""Run DRC check on a given top-level name which is """Run DRC check on a given top-level name which is
implemented in gds_name.""" implemented in gds_name."""

View File

@ -66,7 +66,7 @@ num_pex_runs = 0
# (outfile, errfile, resultsfile) = run_script(cell_name, "filter") # (outfile, errfile, resultsfile) = run_script(cell_name, "filter")
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): def write_drc_script(cell_name, gds_name, extract, final_verification, output_path, sp_name=None):
""" Write a magic script to perform DRC and optionally extraction. """ """ Write a magic script to perform DRC and optionally extraction. """
global OPTS global OPTS
@ -102,35 +102,38 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
f.write("drc catchup\n") f.write("drc catchup\n")
f.write("drc count total\n") f.write("drc count total\n")
f.write("drc count\n") f.write("drc count\n")
f.write("port makeall\n") if not sp_name:
f.write("port makeall\n")
else:
f.write("readspice {}\n".format(sp_name))
if not extract: if not extract:
pre = "#" pre = "#"
else: else:
pre = "" pre = ""
if final_verification and OPTS.route_supplies: if final_verification and OPTS.route_supplies:
f.write(pre + "extract unique all\n".format(cell_name)) f.write(pre + "extract unique all\n")
# Hack to work around unit scales in SkyWater # Hack to work around unit scales in SkyWater
if OPTS.tech_name=="sky130": if OPTS.tech_name=="sky130":
f.write(pre + "extract style ngspice(si)\n") f.write(pre + "extract style ngspice(si)\n")
f.write(pre + "extract\n".format(cell_name)) f.write(pre + "extract\n")
# f.write(pre + "ext2spice hierarchy on\n") # f.write(pre + "ext2spice hierarchy on\n")
# f.write(pre + "ext2spice scale off\n") # f.write(pre + "ext2spice scale off\n")
# lvs exists in 8.2.79, but be backword compatible for now # lvs exists in 8.2.79, but be backword compatible for now
#f.write(pre+"ext2spice lvs\n") # f.write(pre + "ext2spice lvs\n")
f.write(pre+"ext2spice hierarchy on\n") f.write(pre + "ext2spice hierarchy on\n")
f.write(pre+"ext2spice format ngspice\n") f.write(pre + "ext2spice format ngspice\n")
f.write(pre+"ext2spice cthresh infinite\n") f.write(pre + "ext2spice cthresh infinite\n")
f.write(pre+"ext2spice rthresh infinite\n") f.write(pre + "ext2spice rthresh infinite\n")
f.write(pre+"ext2spice renumber off\n") f.write(pre + "ext2spice renumber off\n")
f.write(pre+"ext2spice scale off\n") f.write(pre + "ext2spice scale off\n")
f.write(pre+"ext2spice blackbox on\n") f.write(pre + "ext2spice blackbox on\n")
f.write(pre+"ext2spice subcircuit top on\n") f.write(pre + "ext2spice subcircuit top on\n")
f.write(pre+"ext2spice global off\n") f.write(pre + "ext2spice global off\n")
# Can choose hspice, ngspice, or spice3, # Can choose hspice, ngspice, or spice3,
# but they all seem compatible enough. # but they all seem compatible enough.
f.write(pre+"ext2spice format ngspice\n") f.write(pre + "ext2spice format ngspice\n")
f.write(pre+"ext2spice {}\n".format(cell_name)) f.write(pre + "ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n") f.write("quit -noprompt\n")
f.write("EOF\n") f.write("EOF\n")
@ -138,7 +141,7 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa
os.system("chmod u+x {}".format(run_file)) os.system("chmod u+x {}".format(run_file))
def run_drc(cell_name, gds_name, extract=True, final_verification=False): def run_drc(cell_name, gds_name, sp_name=None, extract=True, final_verification=False):
"""Run DRC check on a cell which is implemented in gds_name.""" """Run DRC check on a cell which is implemented in gds_name."""
global num_drc_runs global num_drc_runs
@ -148,7 +151,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'):
shutil.copy(gds_name, OPTS.openram_temp) shutil.copy(gds_name, OPTS.openram_temp)
write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp) write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp, sp_name=sp_name)
(outfile, errfile, resultsfile) = run_script(cell_name, "drc") (outfile, errfile, resultsfile) = run_script(cell_name, "drc")
@ -161,7 +164,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
try: try:
f = open(outfile, "r") f = open(outfile, "r")
except FileNotFoundError: except FileNotFoundError:
debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile),1) debug.error("Unable to load DRC results file from {}. Is magic set up?".format(outfile), 1)
results = f.readlines() results = f.readlines()
f.close() f.close()
@ -172,7 +175,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
errors = int(re.split(": ", line)[1]) errors = int(re.split(": ", line)[1])
break break
else: else:
debug.error("Unable to find the total error line in Magic output.",1) debug.error("Unable to find the total error line in Magic output.", 1)
# always display this summary # always display this summary
@ -180,7 +183,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
if errors > 0: if errors > 0:
for line in results: for line in results:
if "error tiles" in line: if "error tiles" in line:
debug.info(1,line.rstrip("\n")) debug.info(1, line.rstrip("\n"))
debug.warning(result_str) debug.warning(result_str)
else: else:
debug.info(1, result_str) debug.info(1, result_str)
@ -188,11 +191,14 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False):
return errors return errors
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
""" Write a netgen script to perform LVS. """ """ Write a netgen script to perform LVS. """
global OPTS global OPTS
if not output_path:
output_path = OPTS.openram_temp
setup_file = "setup.tcl" setup_file = "setup.tcl"
full_setup_file = OPTS.openram_tech + "tech/" + setup_file full_setup_file = OPTS.openram_tech + "tech/" + setup_file
if os.path.exists(full_setup_file): if os.path.exists(full_setup_file):
@ -207,14 +213,14 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1])) f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
# f.write("readnet spice {0}.spice\n".format(cell_name)) # f.write("readnet spice {0}.spice\n".format(cell_name))
# f.write("readnet spice {0}\n".format(sp_name)) # f.write("readnet spice {0}\n".format(sp_name))
f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -json\n".format(cell_name, sp_name, setup_file)) f.write("lvs {{{0}.spice {0}}} {{{1} {0}}} {2} {0}.lvs.report -full -json\n".format(cell_name, sp_name, setup_file))
f.write("quit\n") f.write("quit\n")
f.write("EOF\n") f.write("EOF\n")
f.close() f.close()
os.system("chmod u+x {}".format(run_file)) os.system("chmod u+x {}".format(run_file))
def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
"""Run LVS check on a given top-level name which is """Run LVS check on a given top-level name which is
implemented in gds_name and sp_name. Final verification will implemented in gds_name and sp_name. Final verification will
ensure that there are no remaining virtual conections. """ ensure that there are no remaining virtual conections. """
@ -222,13 +228,16 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
global num_lvs_runs global num_lvs_runs
num_lvs_runs += 1 num_lvs_runs += 1
if not output_path:
output_path = OPTS.openram_temp
# Copy file to local dir if it isn't already # Copy file to local dir if it isn't already
if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): if os.path.dirname(gds_name) != output_path.rstrip('/'):
shutil.copy(gds_name, OPTS.openram_temp) shutil.copy(gds_name, output_path)
if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): if os.path.dirname(sp_name) != output_path.rstrip('/'):
shutil.copy(sp_name, OPTS.openram_temp) shutil.copy(sp_name, output_path)
write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp) write_lvs_script(cell_name, gds_name, sp_name, final_verification)
(outfile, errfile, resultsfile) = run_script(cell_name, "lvs") (outfile, errfile, resultsfile) = run_script(cell_name, "lvs")
@ -289,13 +298,20 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
return total_errors return total_errors
def run_pex(name, gds_name, sp_name, output=None, final_verification=False): def run_pex(name, gds_name, sp_name, output=None, final_verification=False, output_path=None):
"""Run pex on a given top-level name which is """Run pex on a given top-level name which is
implemented in gds_name and sp_name. """ implemented in gds_name and sp_name. """
global num_pex_runs global num_pex_runs
num_pex_runs += 1 num_pex_runs += 1
os.chdir(OPTS.openram_temp)
if not output_path:
output_path = OPTS.openram_temp
os.chdir(output_path)
if not output_path:
output_path = OPTS.openram_temp
if output == None: if output == None:
output = name + ".pex.netlist" output = name + ".pex.netlist"
@ -309,10 +325,10 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False):
# pex_fix did run the pex using a script while dev orignial method # pex_fix did run the pex using a script while dev orignial method
# use batch mode. # use batch mode.
# the dev old code using batch mode does not run and is split into functions # the dev old code using batch mode does not run and is split into functions
pex_runset = write_script_pex_rule(gds_name, name, output) pex_runset = write_script_pex_rule(gds_name, name, sp_name, output)
errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) errfile = "{0}{1}.pex.err".format(output_path, name)
outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) outfile = "{0}{1}.pex.out".format(output_path, name)
script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset,
errfile, errfile,
@ -387,7 +403,7 @@ def write_batch_pex_rule(gds_name, name, sp_name, output):
return file return file
def write_script_pex_rule(gds_name, cell_name, output): def write_script_pex_rule(gds_name, cell_name, sp_name, output):
global OPTS global OPTS
run_file = OPTS.openram_temp + "run_pex.sh" run_file = OPTS.openram_temp + "run_pex.sh"
f = open(run_file, "w") f = open(run_file, "w")
@ -399,26 +415,24 @@ def write_script_pex_rule(gds_name, cell_name, output):
f.write("load {}\n".format(cell_name)) f.write("load {}\n".format(cell_name))
f.write("select top cell\n") f.write("select top cell\n")
f.write("expand\n") f.write("expand\n")
f.write("port makeall\n") if not sp_name:
extract = True f.write("port makeall\n")
if not extract:
pre = "#"
else: else:
pre = "" f.write("readspice {}\n".format(sp_name))
f.write(pre + "extract\n") f.write("extract\n")
f.write(pre + "ext2sim labels on\n") f.write("ext2sim labels on\n")
f.write(pre + "ext2sim\n") f.write("ext2sim\n")
f.write(pre + "extresist simplify off\n") f.write("extresist simplify off\n")
f.write(pre + "extresist all\n") f.write("extresist all\n")
f.write(pre + "ext2spice hierarchy off\n") f.write("ext2spice hierarchy off\n")
f.write(pre + "ext2spice format ngspice\n") f.write("ext2spice format ngspice\n")
f.write(pre + "ext2spice renumber off\n") f.write("ext2spice renumber off\n")
f.write(pre + "ext2spice scale off\n") f.write("ext2spice scale off\n")
f.write(pre + "ext2spice blackbox on\n") f.write("ext2spice blackbox on\n")
f.write(pre + "ext2spice subcircuit top on\n") f.write("ext2spice subcircuit top on\n")
f.write(pre + "ext2spice global off\n") f.write("ext2spice global off\n")
f.write(pre + "ext2spice extresist on\n") f.write("ext2spice extresist on\n")
f.write(pre + "ext2spice {}\n".format(cell_name)) f.write("ext2spice {}\n".format(cell_name))
f.write("quit -noprompt\n") f.write("quit -noprompt\n")
f.write("eof\n") f.write("eof\n")
f.write("mv {0}.spice {1}\n".format(cell_name, output)) f.write("mv {0}.spice {1}\n".format(cell_name, output))

View File

@ -17,11 +17,11 @@ lvs_warned = False
pex_warned = False pex_warned = False
def write_drc_script(cell_name, gds_name, extract, final_verification, output_path): def write_drc_script(cell_name, gds_name, extract, final_verification=False, output_path=None):
pass pass
def run_drc(cell_name, gds_name, extract=False, final_verification=False): def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False, output_path=None):
global drc_warned global drc_warned
if not drc_warned: if not drc_warned:
debug.error("DRC unable to run.", -1) debug.error("DRC unable to run.", -1)
@ -30,11 +30,11 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False):
return 1 return 1
def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_path): def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
pass pass
def run_lvs(cell_name, gds_name, sp_name, final_verification=False): def run_lvs(cell_name, gds_name, sp_name, final_verification=False, output_path=None):
global lvs_warned global lvs_warned
if not lvs_warned: if not lvs_warned:
debug.error("LVS unable to run.", -1) debug.error("LVS unable to run.", -1)
@ -43,7 +43,7 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
return 1 return 1
def run_pex(name, gds_name, sp_name, output=None, final_verification=False): def run_pex(name, gds_name, sp_name, output=None, final_verification=False, output_path=None):
global pex_warned global pex_warned
if not pex_warned: if not pex_warned:
debug.error("PEX unable to run.", -1) debug.error("PEX unable to run.", -1)