diff --git a/compiler/calibre.py b/compiler/calibre.py index 990047fa..806ad521 100644 --- a/compiler/calibre.py +++ b/compiler/calibre.py @@ -97,11 +97,13 @@ def run_drc(name, gds_name): # run drc cwd = os.getcwd() os.chdir(OPTS.openram_temp) - errfile = "%s%s.drc.err" % (OPTS.openram_temp, name) - outfile = "%s%s.drc.out" % (OPTS.openram_temp, name) + errfile = "{0}{1}.drc.err".format(OPTS.openram_temp, name) + outfile = "{0}{1}.drc.out".format(OPTS.openram_temp, name) - cmd = "{0} -gui -drc {1}drc_runset -batch 2> {2} 1> {3}".format( - OPTS.calibre_exe, OPTS.openram_temp, errfile, outfile) + cmd = "{0} -gui -drc {1}drc_runset -batch 2> {2} 1> {3}".format(OPTS.drc_exe, + OPTS.openram_temp, + errfile, + outfile) debug.info(1, cmd) os.system(cmd) os.chdir(cwd) @@ -172,12 +174,14 @@ def run_lvs(name, gds_name, sp_name): # run LVS cwd = os.getcwd() os.chdir(OPTS.openram_temp) - errfile = "%s%s.lvs.err" % (OPTS.openram_temp, name) - outfile = "%s%s.lvs.out" % (OPTS.openram_temp, name) + errfile = "{0}{1}.lvs.err".format(OPTS.openram_temp, name) + outfile = "{0}{1}.lvs.out".format(OPTS.openram_temp, name) - cmd = "calibre -gui -lvs %slvs_runset -batch 2> %s 1> %s" % ( - OPTS.openram_temp, errfile, outfile) - debug.info(2, cmd) + cmd = "{0} -gui -lvs {1}lvs_runset -batch 2> {2} 1> {3}".format(OPTS.lvs_exe, + OPTS.openram_temp, + errfile, + outfile) + debug.info(1, cmd) os.system(cmd) os.chdir(cwd) @@ -283,7 +287,7 @@ def run_pex(name, gds_name, sp_name, output=None): errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) - cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.calibre_exe, + cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, OPTS.openram_temp, errfile, outfile) diff --git a/compiler/design.py b/compiler/design.py index 9faf39f3..15096de0 100644 --- a/compiler/design.py +++ b/compiler/design.py @@ -1,7 +1,7 @@ import hierarchy_layout import hierarchy_spice import globals -import calibre +import verify import debug import os @@ -56,8 +56,8 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): tempgds = OPTS.openram_temp + "/temp.gds" self.sp_write(tempspice) self.gds_write(tempgds) - debug.check(calibre.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) - debug.check(calibre.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) + debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) + debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) os.remove(tempspice) os.remove(tempgds) @@ -66,7 +66,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): if OPTS.check_lvsdrc: tempgds = OPTS.openram_temp + "/temp.gds" self.gds_write(tempgds) - debug.check(calibre.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) + debug.check(verify.run_drc(self.name, tempgds) == 0,"DRC failed for {0}".format(self.name)) os.remove(tempgds) def LVS(self): @@ -76,7 +76,7 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): tempgds = OPTS.openram_temp + "/temp.gds" self.sp_write(tempspice) self.gds_write(tempgds) - debug.check(calibre.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) + debug.check(verify.run_lvs(self.name, tempgds, tempspice) == 0,"LVS failed for {0}".format(self.name)) os.remove(tempspice) os.remove(tempgds) diff --git a/compiler/globals.py b/compiler/globals.py index 04150d05..d0a0e683 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -115,8 +115,12 @@ def init_openram(config_file): set_spice() - set_calibre() + set_drc() + set_lvs() + + set_pex() + def read_config(config_file): global OPTS @@ -154,30 +158,69 @@ def read_config(config_file): debug.error("Unable to make output directory.",-1) +def find_exe(check_exe): + """ Check if the binary exists in the path and return the full path. """ + # Check if the preferred spice option exists in the path + for path in os.environ["PATH"].split(os.pathsep): + exe = os.path.join(path, check_exe) + # if it is found, then break and use first version + if is_exe(exe): + return exe + return None -def set_calibre(): - debug.info(2,"Finding calibre...") + +def set_drc(): + debug.info(2,"Finding DRC tool...") global OPTS - # check if calibre is installed, if so, we should be running LVS/DRC on - # everything. if not OPTS.check_lvsdrc: - # over-ride the check LVS/DRC option - debug.info(0,"Over-riding LVS/DRC. Not performing LVS/DRC.") + debug.info(1,"LVS/DRC/PEX disabled.") + return else: - # see if calibre is in the path (extend to other tools later) - for path in os.environ["PATH"].split(os.pathsep): - OPTS.calibre_exe = os.path.join(path, "calibre") - # if it is found, do inline LVS/DRC - if is_exe(OPTS.calibre_exe): - OPTS.check_lvsdrc = True - debug.info(1, "Using calibre: " + OPTS.calibre_exe) - break - else: - # otherwise, give warning and procede - debug.warning("Calibre not found. Not performing LVS/DRC.") - OPTS.check_lvsdrc = False + import tech + if tech.drc_version != "": + OPTS.drc_exe=find_exe(tech.drc_version) + if OPTS.drc_exe==None: + debug.warning("{0} not found. Unable to perform DRC.".format(tech.drc_version)) + OPTS.check_lvsdrc = False + else: + debug.info(1, "Using DRC: " + OPTS.drc_exe) + +def set_lvs(): + debug.info(2,"Finding LVS tool...") + global OPTS + + if not OPTS.check_lvsdrc: + debug.info(1,"LVS/DRC/PEX disabled.") + return + else: + import tech + if tech.lvs_version != "": + OPTS.lvs_exe=find_exe(tech.lvs_version) + if OPTS.lvs_exe==None: + debug.warning("{0} not found. Unable to perform LVS.".format(tech.lvs_version)) + OPTS.check_lvsdrc = False + else: + debug.info(1, "Using LVS: " + OPTS.lvs_exe) + +def set_pex(): + debug.info(2,"Finding PEX tool...") + global OPTS + + if not OPTS.check_lvsdrc: + debug.info(1,"LVS/DRC/PEX disabled.") + return + else: + import tech + if tech.pex_version != "": + OPTS.pex_exe=find_exe(tech.pex_version) + if OPTS.pex_exe==None: + debug.warning("{0} not found. Unable to perform PEX.".format(tech.pex_version)) + OPTS.check_lvsdrc = False + else: + debug.info(1, "Using PEX: " + OPTS.pex_exe) + def end_openram(): """ Clean up openram for a proper exit """ cleanup_paths() @@ -234,16 +277,6 @@ def setup_paths(): -def find_spice(check_exe): - # Check if the preferred spice option exists in the path - for path in os.environ["PATH"].split(os.pathsep): - spice_exe = os.path.join(path, check_exe) - # if it is found, then break and use first version - if is_exe(spice_exe): - OPTS.spice_exe = spice_exe - return True - return False - def set_spice(): debug.info(2,"Finding spice...") global OPTS @@ -252,13 +285,15 @@ def set_spice(): debug.info(1,"Using analytical delay models (no characterization)") return else: - spice_preferences = ["xa", "hspice", "ngspice", "ngspice.exe"] if OPTS.spice_version != "": - if not find_spice(OPTS.spice_version): + OPTS.spice_exe=find_exe(OPTS.spice_version) + if OPTS.spice_exe==None: debug.error("{0} not found. Unable to perform characterization.".format(OPTS.spice_version),1) else: + spice_preferences = ["xa", "hspice", "ngspice", "ngspice.exe"] for spice_name in spice_preferences: - if find_spice(spice_name): + OPTS.spice_exe = find_exe(spice_name) + if OPTS.spice_exe!=None: OPTS.spice_version=spice_name debug.info(1, "Using spice: " + OPTS.spice_exe) break diff --git a/compiler/magic.py b/compiler/magic.py new file mode 100644 index 00000000..4c61fbfc --- /dev/null +++ b/compiler/magic.py @@ -0,0 +1,306 @@ +""" +This is a DRC/LVS/PEX interface file for magic + netgen. + +1. magic can perform drc with the following: +#!/bin/sh +magic -dnull -noconsole << EOF +tech load SCN3ME_SUBM.30 +** import gds file +load $1.mag -force +drc count +drc why +quit -noprompt +EOF + +2. magic can perform extraction with the following: +#!/bin/sh +rm -f $1.ext +rm -f $1.spice +magic -dnull -noconsole << EOF +tech load SCN3ME_SUBM.30 +** import gds file +load $1.mag -force +extract +ext2spice scale off +ext2spice +quit -noprompt +EOF + +3. netgen can perform LVS with: +#!/bin/sh +netgen -noconsole < 0: + debug.error("%-25s\tGeometries: %d\tChecks: %d\tErrors: %d" % + (name, geometries, rulechecks, errors)) + else: + debug.info(1, "%-25s\tGeometries: %d\tChecks: %d\tErrors: %d" % + (name, geometries, rulechecks, errors)) + + return errors + + +def run_lvs(name, gds_name, sp_name): + """Run LVS check on a given top-level name which is + implemented in gds_name and sp_name. """ + + debug.error("LVS using magic+netgen not implemented.",-1) + + OPTS = globals.get_opts() + from tech import drc + lvs_rules = drc["lvs_rules"] + lvs_runset = { + 'lvsRulesFile': lvs_rules, + 'lvsRunDir': OPTS.openram_temp, + 'lvsLayoutPaths': gds_name, + 'lvsLayoutPrimary': name, + 'lvsSourcePath': sp_name, + 'lvsSourcePrimary': name, + 'lvsSourceSystem': 'SPICE', + 'lvsSpiceFile': OPTS.openram_temp + "extracted.sp", + 'lvsPowerNames': 'vdd', + 'lvsGroundNames': 'gnd', + 'lvsIncludeSVRFCmds': 1, + 'lvsSVRFCmds': '{VIRTUAL CONNECT NAME VDD? GND? ?}', + 'lvsIgnorePorts': 1, + 'lvsERCDatabase': OPTS.openram_temp + name + ".erc.results", + 'lvsERCSummaryFile': OPTS.openram_temp + name + ".erc.summary", + 'lvsReportFile': OPTS.openram_temp + name + ".lvs.report", + 'lvsMaskDBFile': OPTS.openram_temp + name + ".maskdb", + 'cmnFDILayerMapFile': drc["layer_map"], + 'cmnFDIUseLayerMap': 1, + 'cmnVConnectNames': 'vdd, gnd', + #'cmnVConnectNamesState' : 'ALL', #connects all nets with the same name + } + + # write the runset file + f = open(OPTS.openram_temp + "lvs_runset", "w") + for k in sorted(lvs_runset.iterkeys()): + f.write("*%s: %s\n" % (k, lvs_runset[k])) + f.close() + + # run LVS + cwd = os.getcwd() + os.chdir(OPTS.openram_temp) + errfile = "{0}{1}.lvs.err".format(OPTS.openram_temp, name) + outfile = "{0}{1}.lvs.out".format(OPTS.openram_temp, name) + + cmd = "{0} -gui -lvs {1}lvs_runset -batch 2> {2} 1> {3}".format(OPTS.lvs_exe, + OPTS.openram_temp, + errfile, + outfile) + debug.info(1, cmd) + os.system(cmd) + os.chdir(cwd) + + # check the result for these lines in the summary: + f = open(lvs_runset['lvsReportFile'], "r") + results = f.readlines() + f.close() + + # NOT COMPARED + # CORRECT + # INCORRECT + test = re.compile("# CORRECT #") + correct = filter(test.search, results) + test = re.compile("NOT COMPARED") + notcompared = filter(test.search, results) + test = re.compile("# INCORRECT #") + incorrect = filter(test.search, results) + + # Errors begin with "Error:" + test = re.compile("\s+Error:") + errors = filter(test.search, results) + for e in errors: + debug.error(e.strip("\n")) + + summary_errors = len(notcompared) + len(incorrect) + len(errors) + + # also check the extraction summary file + f = open(lvs_runset['lvsReportFile'] + ".ext", "r") + results = f.readlines() + f.close() + + test = re.compile("ERROR:") + exterrors = filter(test.search, results) + for e in exterrors: + debug.error(e.strip("\n")) + + test = re.compile("WARNING:") + extwarnings = filter(test.search, results) + for e in extwarnings: + debug.warning(e.strip("\n")) + + # MRG - 9/26/17 - Change this to exclude warnings because of + # multiple labels on different pins in column mux. + ext_errors = len(exterrors) + ext_warnings = len(extwarnings) + + # also check the output file + f = open(outfile, "r") + results = f.readlines() + f.close() + + # Errors begin with "ERROR:" + test = re.compile("ERROR:") + stdouterrors = filter(test.search, results) + for e in stdouterrors: + debug.error(e.strip("\n")) + + out_errors = len(stdouterrors) + + total_errors = summary_errors + out_errors + ext_errors + return total_errors + + +def run_pex(name, gds_name, sp_name, output=None): + """Run pex on a given top-level name which is + implemented in gds_name and sp_name. """ + + debug.error("PEX using magic not implemented.",-1) + + OPTS = globals.get_opts() + from tech import drc + if output == None: + output = name + ".pex.netlist" + + # check if lvs report has been done + # if not run drc and lvs + if not os.path.isfile(name + ".lvs.report"): + run_drc(name, gds_name) + run_lvs(name, gds_name, sp_name) + + pex_rules = drc["xrc_rules"] + pex_runset = { + 'pexRulesFile': pex_rules, + 'pexRunDir': OPTS.openram_temp, + 'pexLayoutPaths': gds_name, + 'pexLayoutPrimary': name, + #'pexSourcePath' : OPTS.openram_temp+"extracted.sp", + 'pexSourcePath': sp_name, + 'pexSourcePrimary': name, + 'pexReportFile': name + ".lvs.report", + 'pexPexNetlistFile': output, + 'pexPexReportFile': name + ".pex.report", + 'pexMaskDBFile': name + ".maskdb", + 'cmnFDIDEFLayoutPath': name + ".def", + } + + # write the runset file + f = open(OPTS.openram_temp + "pex_runset", "w") + for k in sorted(pex_runset.iterkeys()): + f.write("*{0}: {1}\n".format(k, pex_runset[k])) + f.close() + + # run pex + cwd = os.getcwd() + os.chdir(OPTS.openram_temp) + errfile = "{0}{1}.pex.err".format(OPTS.openram_temp, name) + outfile = "{0}{1}.pex.out".format(OPTS.openram_temp, name) + + cmd = "{0} -gui -pex {1}pex_runset -batch 2> {2} 1> {3}".format(OPTS.pex_exe, + OPTS.openram_temp, + errfile, + outfile) + debug.info(2, cmd) + os.system(cmd) + os.chdir(cwd) + + # also check the output file + f = open(outfile, "r") + results = f.readlines() + f.close() + + # Errors begin with "ERROR:" + test = re.compile("ERROR:") + stdouterrors = filter(test.search, results) + for e in stdouterrors: + debug.error(e.strip("\n")) + + out_errors = len(stdouterrors) + + assert(os.path.isfile(output)) + #correct_port(name, output, sp_name) + + return out_errors + diff --git a/compiler/nand_3.py b/compiler/nand_3.py index 23256ef3..25b35ffd 100644 --- a/compiler/nand_3.py +++ b/compiler/nand_3.py @@ -36,7 +36,7 @@ class nand_3(design.design): self.add_pins() self.create_layout() - self.DRC_LVS() + #self.DRC_LVS() def add_pins(self): """ add pics for this module """ diff --git a/compiler/openram.py b/compiler/openram.py index d2b103fc..ed1f06f9 100755 --- a/compiler/openram.py +++ b/compiler/openram.py @@ -10,12 +10,6 @@ a Liberty (.lib) file for timing analysis/optimization """ -__author__ = "Matthew Guthaus (mrg@ucsc.edu) and numerous others" -__version__ = "$Revision: 0.9 $" -__copyright__ = "Copyright (c) 2015 UCSC and OSU" -__license__ = "This is not currently licensed for use outside of UCSC's VLSI-DA and OSU's VLSI group." - - import sys,os import datetime import re @@ -72,17 +66,18 @@ print("Output files are " + OPTS.output_name + ".(sp|gds|v|lib|lef)") print("Technology: {0}".format(OPTS.tech_name)) print("Word size: {0}\nWords: {1}\nBanks: {2}".format(word_size,num_words,num_banks)) +if not OPTS.check_lvsdrc: + print("DRC/LVS/PEX checking is disabled.") if OPTS.analytical_delay: print("Using analytical delay models (no characterization)") else: print("Performing simulation-based characterization with {}".format(OPTS.spice_version)) - -if OPTS.trim_netlist: - print("Trimming netlist to speed up characterization (sacrificing some accuracy).") + if OPTS.trim_netlist: + print("Trimming netlist to speed up characterization (sacrificing some accuracy).") # only start importing modules after we have the config file -import calibre +import verify import sram start_time = datetime.datetime.now() @@ -111,7 +106,7 @@ last_time=print_time("Spice writing", datetime.datetime.now(), last_time) sram_file = spname if OPTS.use_pex: sram_file = OPTS.output_path + "temp_pex.sp" - calibre.run_pex(s.name, gdsname, spname, output=sram_file) + verify.run_pex(s.name, gdsname, spname, output=sram_file) # Characterize the design import lib diff --git a/compiler/options.py b/compiler/options.py index e1e723e5..d4ec0de5 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -22,8 +22,10 @@ class options(optparse.Values): spice_version = "" # Should we print out the banner at startup print_banner = True - # The Calibre executable being used which is derived from the user PATH. - calibre_exe = "" + # The DRC/LVS/PEX executable being used which is derived from the user PATH. + drc_exe = "" + lvs_exe = "" + pex_exe = "" # The spice executable being used which is derived from the user PATH. spice_exe = "" # Run with extracted parasitics diff --git a/compiler/verify.py b/compiler/verify.py new file mode 100644 index 00000000..927f753e --- /dev/null +++ b/compiler/verify.py @@ -0,0 +1,35 @@ +""" +This is a module that will import the correct DRC/LVS/PEX +module based on what tools are found. It is a layer of indirection +to enable multiple verification tool support. + +Each DRC/LVS/PEX tool should implement the functions run_drc, run_lvs, and +run_pex, repsectively. If there is an error, they should abort and report the errors. +If not, OpenRAM will continue as if nothing happened! +""" + +import debug +import tech + +if tech.drc_version=="calibre": + from calibre import run_drc +elif tech.drc_version=="magic": + from magic import run_drc +else: + debug.warning("Did not find a supported DRC tool.") + +if tech.lvs_version=="calibre": + from calibre import run_lvs +elif tech.lvs_version=="netgen": + from magic import run_lvs +else: + debug.warning("Did not find a supported LVS tool.") + + +if tech.pex_version=="calibre": + from calibre import run_pex +elif tech.pex_version=="magic": + from magic import run_pex +else: + debug.warning("Did not find a supported PEX tool.") + diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 53308bcb..c8ae78b2 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -1,7 +1,7 @@ import os """ -File containing the process technology parameters. +File containing the process technology parameters for FreePDK 45nm. """ info = {} @@ -17,9 +17,13 @@ GDS["unit"] = (0.0005,1e-9) # default label zoom GDS["zoom"] = 0.05 -##################################################################################################### -##GDS Layer Map###################################################################################### -##################################################################################################### +drc_version = "calibre" +lvs_version = "calibre" +pex_version = "calibre" + +################################################### +##GDS Layer Map +################################################### # create the GDS layer map # FIXME: parse the gds layer map from the cadence map? @@ -56,13 +60,13 @@ layer["metal10"] = 29 layer["text"] = 239 layer["boundary"]= 239 -##################################################################################################### -##END GDS Layer Map################################################################################## -##################################################################################################### +################################################### +##END GDS Layer Map +################################################### -##################################################################################################### -##DRC/LVS Rules Setup################################################################################ -##################################################################################################### +################################################### +##DRC/LVS Rules Setup +################################################### #technology parameter parameter={} @@ -243,13 +247,13 @@ drc["metal10_to_metal10"] = 0.14 drc["metal10_extend_via9"] = 0 drc["metal10_enclosure_via9"] = 0 -##################################################################################################### -##END DRC/LVS Rules################################################################################## -##################################################################################################### +################################################### +##END DRC/LVS Rules +################################################### -##################################################################################################### -##Spice Simulation Parameters######################################################################## -##################################################################################################### +################################################### +##Spice Simulation Parameters +################################################### #spice info spice = {} @@ -298,3 +302,9 @@ spice["msflop_setup"] = 9 # DFF setup time in ps spice["msflop_hold"] = 1 # DFF hold time in ps spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load + + +################################################### +##END Spice Simulation Parameters +################################################### + diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index 40eb4c78..a0d6544e 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -1,8 +1,9 @@ import os """ -Class containing the process technology parameters. +File containing the process technology parameters for SCMOS 3me, subm, 180nm. """ + info={} info["name"]="scn3me_subm" info["body_tie_down"] = 0 @@ -16,9 +17,14 @@ GDS["unit"]=(0.001,1e-6) # default label zoom GDS["zoom"] = 0.5 -##################################################################################################### -##GDS Layer Map###################################################################################### -##################################################################################################### +drc_version = "magic" +lvs_version = "netgen" +pex_version = "magic" + + +################################################### +##GDS Layer Map +################################################### # create the GDS layer map layer={} @@ -41,13 +47,13 @@ layer["metal3"] = 62 layer["text"] = 83 layer["boundary"] = 83 -##################################################################################################### -##END GDS Layer Map################################################################################## -##################################################################################################### +################################################### +##END GDS Layer Map +################################################### -##################################################################################################### -##DRC/LVS Rules Setup################################################################################ -##################################################################################################### +################################################### +##DRC/LVS Rules Setup +################################################### #technology parameter parameter={} @@ -163,13 +169,13 @@ drc["metal3_extend_via2"] = 0.6 drc["metal3_enclosure_via2"] = 0.6 drc["minarea_metal3"] = 0 -##################################################################################################### -##END DRC/LVS Rules################################################################################## -##################################################################################################### +################################################### +##END DRC/LVS Rules +################################################### -##################################################################################################### -##Spice Simulation Parameters######################################################################## -##################################################################################################### +################################################### +##Spice Simulation Parameters +################################################### # spice model info spice={} @@ -218,3 +224,7 @@ spice["msflop_hold"] = 1 # DFF hold time in ps spice["msflop_delay"] = 20.5 # DFF Clk-to-q delay in ps spice["msflop_slew"] = 13.1 # DFF output slew in ps w/ no load + +################################################### +##END Spice Simulation Parameters +###################################################