From f358de78bb714d11859d147b7e9dc3984adf4e61 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 3 Apr 2020 13:39:54 -0700 Subject: [PATCH] Add optional lvs_lib netlists for LVS usage (sp_lib is for simulation) --- compiler/base/hierarchy_design.py | 12 +++++-- compiler/base/hierarchy_spice.py | 47 +++++++++++++++++++++++---- compiler/sram/sram_base.py | 4 +-- compiler/tests/02_library_lvs_test.py | 4 ++- 4 files changed, 55 insertions(+), 12 deletions(-) diff --git a/compiler/base/hierarchy_design.py b/compiler/base/hierarchy_design.py index 82682b71..bb57ae3e 100644 --- a/compiler/base/hierarchy_design.py +++ b/compiler/base/hierarchy_design.py @@ -24,6 +24,14 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): self.gds_file = OPTS.openram_tech + "gds_lib/" + name + ".gds" self.sp_file = OPTS.openram_tech + "sp_lib/" + name + ".sp" + # If we have a separate lvs directory, then all the lvs files + # should be in there (all or nothing!) + lvs_dir = OPTS.openram_tech + "lvs_lib/" + if os.path.exists(lvs_dir): + self.lvs_file = lvs_dir + name + ".sp" + else: + self.lvs_file = self.sp_file + self.name = name hierarchy_spice.spice.__init__(self, name) hierarchy_layout.layout.__init__(self, name) @@ -56,7 +64,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): tempspice = "{0}/{1}.sp".format(OPTS.openram_temp, self.name) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) - self.sp_write(tempspice) + self.lvs_write(tempspice) self.gds_write(tempgds) # 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) @@ -114,7 +122,7 @@ class hierarchy_design(hierarchy_spice.spice, hierarchy_layout.layout): 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) tempgds = "{0}/{1}.gds".format(OPTS.openram_temp, self.name) - self.sp_write(tempspice) + self.lvs_write(tempspice) 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/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index ee8844c2..b69888e4 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -43,7 +43,7 @@ class spice(): # Keep track of any comments to add the the spice try: self.commments - except NameError: + except AttributeError: self.comments = [] self.sp_read() @@ -57,7 +57,7 @@ class spice(): try: self.commments - except NameError: + except AttributeError: self.comments = [] self.comments.append(comment) @@ -210,6 +210,24 @@ class spice(): else: self.spice = [] + # We don't define self.lvs and will use self.spice if dynamically created + # or they are the same file + if self.lvs_file!=self.sp_file and os.path.isfile(self.lvs_file): + debug.info(3, "opening {0}".format(self.lvs_file)) + f = open(self.lvs_file) + self.lvs = f.readlines() + for i in range(len(self.lvs)): + self.lvs[i] = self.lvs[i].rstrip(" \n") + f.close() + + # pins and subckt should be the same + # find the correct subckt line in the file + subckt = re.compile("^.subckt {}".format(self.name), re.IGNORECASE) + subckt_line = list(filter(subckt.search, self.lvs))[0] + # parses line into ports and remove subckt + lvs_pins = subckt_line.split(" ")[2:] + debug.check(lvs_pins == self.pins, "LVS and spice file pin mismatch.", -1) + def check_net_in_spice(self, net_name): """Checks if a net name exists in the current. Intended to be check nets in hand-made cells.""" # Remove spaces and lower case then add spaces. @@ -239,16 +257,18 @@ class spice(): return True return False - def sp_write_file(self, sp, usedMODS): - """ Recursive spice subcircuit write; - Writes the spice subcircuit from the library or the dynamically generated one""" + def sp_write_file(self, sp, usedMODS, lvs_netlist=False): + """ + Recursive spice subcircuit write; + Writes the spice subcircuit from the library or the dynamically generated one + """ if not self.spice: # recursively write the modules for i in self.mods: if self.contains(i, usedMODS): continue usedMODS.append(i) - i.sp_write_file(sp, usedMODS) + i.sp_write_file(sp, usedMODS, lvs_netlist) if len(self.insts) == 0: return @@ -296,7 +316,10 @@ class spice(): # Including the file path makes the unit test fail for other users. # if os.path.isfile(self.sp_file): # sp.write("\n* {0}\n".format(self.sp_file)) - sp.write("\n".join(self.spice)) + if lvs_netlist: + sp.write("\n".join(self.lvs)) + else: + sp.write("\n".join(self.spice)) sp.write("\n") @@ -310,6 +333,16 @@ class spice(): del usedMODS spfile.close() + def lvs_write(self, spname): + """Writes the lvs to files""" + debug.info(3, "Writing to {0}".format(spname)) + spfile = open(spname, 'w') + spfile.write("*FIRST LINE IS A COMMENT\n") + usedMODS = list() + self.sp_write_file(spfile, usedMODS, True) + del usedMODS + spfile.close() + def analytical_delay(self, corner, slew, load=0.0): """Inform users undefined delay module while building new modules""" diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 563d128c..64e3f51b 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -574,11 +574,11 @@ class sram_base(design, verilog, lef): sp.write("* Data bits: {}\n".format(self.word_size)) sp.write("* Banks: {}\n".format(self.num_banks)) sp.write("* Column mux: {}:1\n".format(self.words_per_row)) - sp.write("**************************************************\n") + sp.write("**************************************************\n") # This causes unit test mismatch # sp.write("* Created: {0}\n".format(datetime.datetime.now())) # sp.write("* User: {0}\n".format(getpass.getuser())) - # sp.write(".global {0} {1}\n".format(spice["vdd_name"], + # sp.write(".global {0} {1}\n".format(spice["vdd_name"], # spice["gnd_name"])) usedMODS = list() self.sp_write_file(sp, usedMODS) diff --git a/compiler/tests/02_library_lvs_test.py b/compiler/tests/02_library_lvs_test.py index 35ac5d76..0acc8926 100755 --- a/compiler/tests/02_library_lvs_test.py +++ b/compiler/tests/02_library_lvs_test.py @@ -45,7 +45,9 @@ class library_lvs_test(openram_test): def setup_files(): gds_dir = OPTS.openram_tech + "/gds_lib" - sp_dir = OPTS.openram_tech + "/sp_lib" + sp_dir = OPTS.openram_tech + "/lvs_lib" + if not os.path.exists(sp_dir): + sp_dir = OPTS.openram_tech + "/sp_lib" files = os.listdir(gds_dir) nametest = re.compile("\.gds$", re.IGNORECASE) gds_files = list(filter(nametest.search, files))