From 658f794b12e9596cafbd6146779dd92c79c6be92 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 15 Nov 2017 12:07:10 -0800 Subject: [PATCH] Add draft of assura DRC/LVS --- compiler/assura.py | 170 ++++++++++++++++++++++++++++++++++++++++++++ compiler/globals.py | 4 +- compiler/verify.py | 4 ++ 3 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 compiler/assura.py diff --git a/compiler/assura.py b/compiler/assura.py new file mode 100644 index 00000000..a4f4a96d --- /dev/null +++ b/compiler/assura.py @@ -0,0 +1,170 @@ +""" +This is a DRC/LVS interface for Assura. It implements completely +independently two functions: run_drc and run_lvs, that perform these +functions in batch mode and will return true/false if the result +passes. All of the setup (the rules, temp dirs, etc.) should be +contained in this file. Replacing with another DRC/LVS tool involves +rewriting this code to work properly. Porting to a new technology in +Assura means pointing the code to the proper DRC and LVS rule files. + +LVS Notes: + +For some processes the FET models are sub-circuits. Meaning, the +first letter of their SPICE instantiation begins with 'X' not 'M'. +The former confuses Assura, however, so to get these sub-circuit models +to LVS properly, an empty sub-circuit must be inserted into the +LVS SPICE netlist. The sub-circuits are pointed to using the +drc["lvs_subcircuits"] variable, and additional options must be +inserted in the runset. +""" + + +import os +import re +import time +import debug +import globals + + +def run_drc(name, gds_name): + """Run DRC check on a given top-level name which is + implemented in gds_name.""" + OPTS = globals.get_opts() + + from tech import drc + + drc_rules = drc["drc_rules"] + drc_runset = OPTS.openram_temp + name + ".rsf" + drc_log_file = "%s%s.log" % (OPTS.openram_temp, name) + + # write the runset file + # the runset file contains all the options to run Assura + # different processes may require different options + f = open(drc_runset, "w") + f.write("avParameters(\n") + f.write(" ?flagDotShapes t\n") + f.write(" ?flagMalformed t\n") + f.write(" ?flagPathNonManhattanSeg all\n") + f.write(" ?flagPathShortSegments endOnlySmart\n") + f.write(" ?maintain45 nil\n") + f.write(" ?combineNearCollinearEdges nil\n") + f.write(")\n") + f.write("\n") + f.write("avParameters(\n") + f.write(" ?inputLayout ( \"gds2\" \"%s\" )\n" % (gds_name)) + f.write(" ?cellName \"%s\"\n" % (name)) + f.write(" ?workingDirectory \"%s\"\n" % (OPTS.openram_temp)) + f.write(" ?rulesFile \"%s\"\n" % (drc_rules)) + f.write(" ?set ( \"GridCheck\" )\n") + f.write(" ?avrpt t\n") + f.write(")\n") + f.close() + + # run drc + cwd = os.getcwd() + os.chdir(OPTS.openram_temp) + cmd = "assura {0} 2> {1} 1> {2}".format(drc_runset, drc_log_file, drc_log_file) + debug.info(1, cmd) + os.system(cmd) + os.chdir(cwd) + + # count and report errors + errors = 0 + try: + f = open(OPTS.openram_temp+name+".err", "r") + except: + debug.error("Unable to retrieve DRC results file.",1) + results = f.readlines() + f.close() + for line in results: + if re.match("Rule No.", line): + if re.search("# INFO:", line) == None: + errors = errors + 1 + debug.info(1, line) + + if errors > 0: + debug.error("Errors: %d" % (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. """ + OPTS = globals.get_opts() + + from tech import drc + + lvs_rules = drc["lvs_rules"] + lvs_runset = OPTS.openram_temp + name + ".rsf" + lvs_compare = drc["lvs_compare"] + lvs_bindings = drc["lvs_bindings"] + lvs_log_file = "{0}{1}.log".format(OPTS.openram_temp, name) + # Needed when FET models are sub-circuits + if drc.has_key("lvs_subcircuits"): + lvs_sub_file = drc["lvs_subcircuits"] + else: + lvs_sub_file = "" + + # write the runset file + # the runset file contains all the options to run Assura + # different processes may require different options + f = open(lvs_runset, "w") + f.write("avParameters(\n") + f.write(" ?inputLayout ( \"gds2\" \"{}\" )\n".format(gds_name)) + f.write(" ?cellName \"{}\"\n".format(name)) + f.write(" ?workingDirectory \"{}\"\n".format(OPTS.openram_temp)) + f.write(" ?rulesFile \"{}\"\n".format(lvs_rules)) + f.write(" ?autoGrid nil\n") + f.write(" ?avrpt t\n") + # The below options vary greatly between processes and cell-types + f.write(" ?set (\"NO_SUBC_IN_GRLOGIC\")\n") + f.write(")\n") + f.write("\n") + c = open(lvs_compare, "r") + lines = c.read() + c.close + f.write(lines) + f.write("\n") + f.write("avCompareRules(\n") + f.write(" schematic(\n") + # Needed when FET models are sub-circuits + if os.path.isfile(lvs_sub_file): + f.write(" genericDevice(emptySubckt)\n") + f.write(" netlist( spice \"{}\" )\n".format(lvs_sub_file)) + f.write(" netlist( spice \"{}\" )\n".format(sp_name)) + f.write(" )\n") + f.write(" layout(\n") + # Separate gnd shapes are sometimes not connected by metal, so this connects by name + # The use of this option is not recommended for final DRC + f.write(" joinNets( root \"gnd\" \"gnd*\" ) \n") + f.write(" )\n") + f.write(" bindingFile( \"{}\" )\n".format(lvs_bindings)) + f.write(")\n") + f.write("\n") + f.write("avLVS()\n") + f.close() + + # run lvs + cwd = os.getcwd() + os.chdir(OPTS.openram_temp) + cmd = "assura {0} 2> {1} 1> {2}".format(lvs_runset, lvs_log_file, lvs_log_file) + debug.info(1, cmd) + os.system(cmd) + os.chdir(cwd) + + errors = 0 + try: + f = open(OPTS.openram_temp+name+".csm", "r") + except: + debug.error("Unable to retrieve LVS results file.",1) + results = f.readlines() + f.close() + for line in results: + if re.search("errors", line): + errors = errors + 1 + debug.info(1, line) + elif re.search("Schematic and Layout", line): + debug.info(1, line) + + return errors diff --git a/compiler/globals.py b/compiler/globals.py index d0ef3159..a2931c4b 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -116,8 +116,8 @@ def init_openram(config_file): set_spice() global OPTS - OPTS.drc_exe = get_tool("DRC",["calibre","magic"]) - OPTS.lvs_exe = get_tool("LVS",["calibre","netgen"]) + OPTS.drc_exe = get_tool("DRC",["calibre","assura","magic"]) + OPTS.lvs_exe = get_tool("LVS",["calibre","assura","netgen"]) OPTS.pex_exe = get_tool("PEX",["calibre","magic"]) #set_drc() #set_lvs() diff --git a/compiler/verify.py b/compiler/verify.py index becc1478..7f930ce4 100644 --- a/compiler/verify.py +++ b/compiler/verify.py @@ -16,6 +16,8 @@ if OPTS.drc_exe == None: pass elif "calibre" in OPTS.drc_exe: from calibre import run_drc +elif "assura" in OPTS.drc_exe: + from assura import run_drc elif "magic" in OPTS.drc_exe: from magic import run_drc else: @@ -25,6 +27,8 @@ if OPTS.lvs_exe == None: pass elif "calibre" in OPTS.lvs_exe: from calibre import run_lvs +elif "assura" in OPTS.lvs_exe: + from assura import run_lvs elif "netgen" in OPTS.lvs_exe: from magic import run_lvs else: