From 31ae56ff39a9b4e39cdb5585dec9fd8b44f2e639 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 10 Nov 2020 16:45:00 -0800 Subject: [PATCH 1/8] Simplify to a single DRC/LVS library test. --- compiler/tests/01_library_drc_test.py | 69 ------------------- ...library_lvs_test.py => 01_library_test.py} | 5 +- 2 files changed, 3 insertions(+), 71 deletions(-) delete mode 100755 compiler/tests/01_library_drc_test.py rename compiler/tests/{02_library_lvs_test.py => 01_library_test.py} (95%) diff --git a/compiler/tests/01_library_drc_test.py b/compiler/tests/01_library_drc_test.py deleted file mode 100755 index 53d50386..00000000 --- a/compiler/tests/01_library_drc_test.py +++ /dev/null @@ -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()) - diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/01_library_test.py similarity index 95% rename from compiler/tests/02_library_lvs_test.py rename to compiler/tests/01_library_test.py index 353c1f88..dbd25f7c 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/01_library_test.py @@ -36,13 +36,14 @@ class library_lvs_test(openram_test): if not os.path.isfile(sp_name): lvs_errors += 1 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) # 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() + def setup_files(): gds_dir = OPTS.openram_tech + "/gds_lib" sp_dir = OPTS.openram_tech + "/lvs_lib" From 03dad01e4cefbaae4785243161bdab701e6a888e Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 10 Nov 2020 17:06:24 -0800 Subject: [PATCH 2/8] Use readspice to define ports from sp netlist in Magic extract. --- compiler/base/hierarchy_design.py | 14 ++-- compiler/tests/testutils.py | 2 +- compiler/verify/calibre.py | 21 ++++-- compiler/verify/magic.py | 115 ++++++++++++++++-------------- compiler/verify/none.py | 10 +-- 5 files changed, 93 insertions(+), 69 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 5404838a..17022424 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -73,11 +73,11 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): elif (OPTS.inline_lvsdrc or force_check or final_verification): tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name) - tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) self.lvs_write(tempspice) + tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) self.gds_write(tempgds) # 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) # 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: return 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) - 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, "DRC failed for {0} with {1} error(s)".format(self.cell_name, num_errors)) @@ -126,9 +128,9 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): if OPTS.netlist_only: return 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) - tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) + tempspice = "{0}{1}.sp".format(OPTS.openram_temp, self.cell_name) self.lvs_write(tempspice) + tempgds = "{0}{1}.gds".format(OPTS.openram_temp, self.name) self.gds_write(tempgds) num_errors = verify.run_lvs(self.name, tempgds, tempspice, final_verification=final_verification) debug.check(num_errors == 0, diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index e63b457d..cc76d0c0 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -48,7 +48,7 @@ class openram_test(unittest.TestCase): # 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 # 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 lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification) diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index d45cfe09..5e49e6e1 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -30,9 +30,13 @@ num_lvs_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 """ # the runset file contains all the options to run calibre + + if not output_path: + output_path = OPTS.openram_temp + from tech import drc 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 -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 """ + if not output_path: + output_path = OPTS.openram_temp + from tech import drc lvs_rules = drc["lvs_rules"] lvs_runset = { @@ -132,8 +139,12 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa 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 """ + + if not output_path: + output_path = OPTS.openram_temp + if output == None: 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"): gds_name = output_path +"/"+ cell_name + ".gds" 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) from tech import drc @@ -181,7 +192,7 @@ def write_pex_script(cell_name, extract, output, final_verification, output_path 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 implemented in gds_name.""" diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index c2f13cc4..9ab0333f 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -66,7 +66,7 @@ num_pex_runs = 0 # (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. """ 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 count total\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: pre = "#" else: pre = "" 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 if OPTS.tech_name=="sky130": 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 scale off\n") # lvs exists in 8.2.79, but be backword compatible for now - #f.write(pre+"ext2spice lvs\n") - f.write(pre+"ext2spice hierarchy on\n") - f.write(pre+"ext2spice format ngspice\n") - f.write(pre+"ext2spice cthresh infinite\n") - f.write(pre+"ext2spice rthresh infinite\n") - f.write(pre+"ext2spice renumber off\n") - f.write(pre+"ext2spice scale off\n") - f.write(pre+"ext2spice blackbox on\n") - f.write(pre+"ext2spice subcircuit top on\n") - f.write(pre+"ext2spice global off\n") + # f.write(pre + "ext2spice lvs\n") + f.write(pre + "ext2spice hierarchy on\n") + f.write(pre + "ext2spice format ngspice\n") + f.write(pre + "ext2spice cthresh infinite\n") + f.write(pre + "ext2spice rthresh infinite\n") + f.write(pre + "ext2spice renumber off\n") + f.write(pre + "ext2spice scale off\n") + f.write(pre + "ext2spice blackbox on\n") + f.write(pre + "ext2spice subcircuit top on\n") + f.write(pre + "ext2spice global off\n") # Can choose hspice, ngspice, or spice3, # but they all seem compatible enough. - f.write(pre+"ext2spice format ngspice\n") - f.write(pre+"ext2spice {}\n".format(cell_name)) + f.write(pre + "ext2spice format ngspice\n") + f.write(pre + "ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\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)) -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.""" 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('/'): 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") @@ -161,7 +164,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): try: f = open(outfile, "r") 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() f.close() @@ -172,7 +175,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): errors = int(re.split(": ", line)[1]) break 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 @@ -180,7 +183,7 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): if errors > 0: for line in results: if "error tiles" in line: - debug.info(1,line.rstrip("\n")) + debug.info(1, line.rstrip("\n")) debug.warning(result_str) else: debug.info(1, result_str) @@ -188,11 +191,14 @@ def run_drc(cell_name, gds_name, extract=True, final_verification=False): 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. """ global OPTS + if not output_path: + output_path = OPTS.openram_temp + setup_file = "setup.tcl" full_setup_file = OPTS.openram_tech + "tech/" + setup_file if os.path.exists(full_setup_file): @@ -214,7 +220,7 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification, output_pa 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 implemented in gds_name and sp_name. Final verification will 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 num_lvs_runs += 1 + if not output_path: + output_path = OPTS.openram_temp + # Copy file to local dir if it isn't already - if os.path.dirname(gds_name)!=OPTS.openram_temp.rstrip('/'): - shutil.copy(gds_name, OPTS.openram_temp) - if os.path.dirname(sp_name)!=OPTS.openram_temp.rstrip('/'): - shutil.copy(sp_name, OPTS.openram_temp) + if os.path.dirname(gds_name) != output_path.rstrip('/'): + shutil.copy(gds_name, output_path) + if os.path.dirname(sp_name) != output_path.rstrip('/'): + 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") @@ -289,13 +298,17 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False): 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 implemented in gds_name and sp_name. """ global num_pex_runs num_pex_runs += 1 - os.chdir(OPTS.openram_temp) + + os.chdir(output_path) + + if not output_path: + output_path = OPTS.openram_temp if output == None: output = name + ".pex.netlist" @@ -311,8 +324,8 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False): # 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) - errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) - outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) + errfile = "{0}{1}.pex.err".format(output_path, name) + outfile = "{0}{1}.pex.out".format(output_path, name) script_cmd = "{0} 2> {1} 1> {2}".format(pex_runset, errfile, @@ -387,7 +400,7 @@ def write_batch_pex_rule(gds_name, name, sp_name, output): 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 run_file = OPTS.openram_temp + "run_pex.sh" f = open(run_file, "w") @@ -399,26 +412,24 @@ def write_script_pex_rule(gds_name, cell_name, output): f.write("load {}\n".format(cell_name)) f.write("select top cell\n") f.write("expand\n") - f.write("port makeall\n") - extract = True - if not extract: - pre = "#" + if not sp_name: + f.write("port makeall\n") else: - pre = "" - f.write(pre + "extract\n") - f.write(pre + "ext2sim labels on\n") - f.write(pre + "ext2sim\n") - f.write(pre + "extresist simplify off\n") - f.write(pre + "extresist all\n") - f.write(pre + "ext2spice hierarchy off\n") - f.write(pre + "ext2spice format ngspice\n") - f.write(pre + "ext2spice renumber off\n") - f.write(pre + "ext2spice scale off\n") - f.write(pre + "ext2spice blackbox on\n") - f.write(pre + "ext2spice subcircuit top on\n") - f.write(pre + "ext2spice global off\n") - f.write(pre + "ext2spice extresist on\n") - f.write(pre + "ext2spice {}\n".format(cell_name)) + f.write("readspice {}\n".format(sp_name)) + f.write("extract\n") + f.write("ext2sim labels on\n") + f.write("ext2sim\n") + f.write("extresist simplify off\n") + f.write("extresist all\n") + f.write("ext2spice hierarchy off\n") + f.write("ext2spice format ngspice\n") + f.write("ext2spice renumber off\n") + f.write("ext2spice scale off\n") + f.write("ext2spice blackbox on\n") + f.write("ext2spice subcircuit top on\n") + f.write("ext2spice global off\n") + f.write("ext2spice extresist on\n") + f.write("ext2spice {}\n".format(cell_name)) f.write("quit -noprompt\n") f.write("eof\n") f.write("mv {0}.spice {1}\n".format(cell_name, output)) diff --git a/compiler/verify/none.py b/compiler/verify/none.py index 28a5a47b..bd2fb722 100644 --- a/compiler/verify/none.py +++ b/compiler/verify/none.py @@ -17,11 +17,11 @@ lvs_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 -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 if not drc_warned: 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 -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 -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 if not lvs_warned: 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 -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 if not pex_warned: debug.error("PEX unable to run.", -1) From 537e862d4877e5aebcf17f0b58a08d4ca1d2bda7 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 10 Nov 2020 20:38:41 -0800 Subject: [PATCH 3/8] Add -full to LVS script --- compiler/verify/magic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 9ab0333f..97c9efb9 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -213,7 +213,7 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out 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}\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("EOF\n") f.close() From 63941a10e1cda830debb445693531c0e4980a935 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 12 Nov 2020 10:01:38 -0800 Subject: [PATCH 4/8] Add None as sp_file parameter to local_drc_check --- compiler/tests/testutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index cc76d0c0..d60dde40 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -25,7 +25,7 @@ class openram_test(unittest.TestCase): w.gds_write(tempgds) import verify - result=verify.run_drc(w.name, tempgds) + result=verify.run_drc(w.name, tempgds, None) if result != 0: self.fail("DRC failed: {}".format(w.name)) From 190234df58048a67da6c5603218f1957a633d1e4 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 12 Nov 2020 12:12:53 -0800 Subject: [PATCH 5/8] Add PININFO to outputs too --- compiler/base/hierarchy_spice.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index d971492e..7e09b970 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -296,6 +296,18 @@ class spice(): sp.write("\n.SUBCKT {0} {1}\n".format(self.cell_name, " ".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: sp.write("* {1:6}: {0} \n".format(pin, self.pin_type[pin])) From bdda7c4f5f7bfa7e5df0646493f5d01b671776be Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 12 Nov 2020 12:38:09 -0800 Subject: [PATCH 6/8] Add bl/br pins to dummy array --- compiler/modules/dummy_array.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/modules/dummy_array.py b/compiler/modules/dummy_array.py index 51b423ae..0a33e7cc 100644 --- a/compiler/modules/dummy_array.py +++ b/compiler/modules/dummy_array.py @@ -5,7 +5,6 @@ # from bitcell_base_array import bitcell_base_array from sram_factory import factory -from tech import cell_properties as props from globals import OPTS @@ -77,15 +76,17 @@ class dummy_array(bitcell_base_array): for col in range(self.column_size): for port in self.all_ports: bl_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port]) - self.add_rect(layer=bl_pin.layer, - offset=bl_pin.ll().scale(1, 0), - width=bl_pin.width(), - height=self.height) + self.add_layout_pin(text="bl_{0}_{1}".format(port, col), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1, 0), + width=bl_pin.width(), + height=self.height) br_pin = self.cell_inst[0, col].get_pin(bitline_names[2 * port + 1]) - self.add_rect(layer=br_pin.layer, - offset=br_pin.ll().scale(1, 0), - width=br_pin.width(), - height=self.height) + self.add_layout_pin(text="br_{0}_{1}".format(port, col), + layer=br_pin.layer, + offset=br_pin.ll().scale(1, 0), + width=br_pin.width(), + height=self.height) wl_names = self.cell.get_all_wl_names() for row in range(self.row_size): From 9eeab1463952310948838c56f5d9f5bf46ec823e Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 12 Nov 2020 14:33:42 -0800 Subject: [PATCH 7/8] Add comment before pininfo --- compiler/base/hierarchy_spice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 7e09b970..81676ec1 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -297,7 +297,7 @@ class spice(): " ".join(self.pins))) # write a PININFO line - pin_info = ".PININFO" + pin_info = "*.PININFO" for pin in self.pins: if self.pin_type[pin] == "INPUT": pin_info += " {0}:I".format(pin) From e6a7ecae84aea56fed390c801b02a306bdc3ca62 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 12 Nov 2020 14:43:57 -0800 Subject: [PATCH 8/8] Fix missing default path in pex --- compiler/verify/magic.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 97c9efb9..a8345a96 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -305,6 +305,9 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False, outp global num_pex_runs num_pex_runs += 1 + if not output_path: + output_path = OPTS.openram_temp + os.chdir(output_path) if not output_path: @@ -322,7 +325,7 @@ def run_pex(name, gds_name, sp_name, output=None, final_verification=False, outp # pex_fix did run the pex using a script while dev orignial method # use batch mode. # 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(output_path, name) outfile = "{0}{1}.pex.out".format(output_path, name)