diff --git a/compiler/options.py b/compiler/options.py index 6ecfa6ae..976595ad 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -110,6 +110,8 @@ class options(optparse.Values): drc_exe = None lvs_exe = None pex_exe = None + # For sky130, we need magic for filtering. + magic_exe = None # Should we print out the banner at startup print_banner = True diff --git a/compiler/verify/__init__.py b/compiler/verify/__init__.py index 59df42db..a28581d8 100644 --- a/compiler/verify/__init__.py +++ b/compiler/verify/__init__.py @@ -18,27 +18,27 @@ If not, OpenRAM will continue as if nothing happened! import os import debug from globals import OPTS -from globals import find_exe from globals import get_tool from tech import drc_name from tech import lvs_name from tech import pex_name -import sys -debug.info(1,"Initializing verify...") +debug.info(1, "Initializing verify...") if not OPTS.check_lvsdrc: - debug.info(1,"LVS/DRC/PEX disabled.") + debug.info(1, "LVS/DRC/PEX disabled.") OPTS.drc_exe = None OPTS.lvs_exe = None OPTS.pex_exe = None else: - debug.info(1, "Finding DRC/LVS/PEX tools.") - OPTS.drc_exe = get_tool("DRC", ["calibre","assura","magic"], drc_name) - OPTS.lvs_exe = get_tool("LVS", ["calibre","assura","netgen"], lvs_name) - OPTS.pex_exe = get_tool("PEX", ["calibre","magic"], pex_name) + debug.info(1, "Finding DRC/LVS/PEX tools.") + OPTS.drc_exe = get_tool("DRC", ["calibre", "assura", "magic"], drc_name) + OPTS.lvs_exe = get_tool("LVS", ["calibre", "assura", "netgen"], lvs_name) + OPTS.pex_exe = get_tool("PEX", ["calibre", "magic"], pex_name) + if OPTS.tech_name == "sky130": + OPTS.magic_exe = get_tool("GDS", ["magic"], None) -if OPTS.drc_exe == None: +if not OPTS.drc_exe: from .none import run_drc, print_drc_stats elif "calibre"==OPTS.drc_exe[0]: from .calibre import run_drc, print_drc_stats @@ -49,7 +49,7 @@ elif "magic"==OPTS.drc_exe[0]: else: debug.warning("Did not find a supported DRC tool.") -if OPTS.lvs_exe == None: +if not OPTS.lvs_exe: from .none import run_lvs, print_lvs_stats elif "calibre"==OPTS.lvs_exe[0]: from .calibre import run_lvs, print_lvs_stats @@ -61,7 +61,7 @@ else: debug.warning("Did not find a supported LVS tool.") -if OPTS.pex_exe == None: +if not OPTS.pex_exe: from .none import run_pex,print_pex_stats elif "calibre"==OPTS.pex_exe[0]: from .calibre import run_pex,print_pex_stats @@ -69,4 +69,10 @@ elif "magic"==OPTS.pex_exe[0]: from .magic import run_pex,print_pex_stats else: debug.warning("Did not find a supported PEX tool.") - + +if OPTS.tech_name == "sky130": + if "magic"==OPTS.magic_exe[0]: + from .magic import filter_gds + else: + debug.warning("Did not find Magic.") + diff --git a/compiler/verify/calibre.py b/compiler/verify/calibre.py index 8abca448..1b9d296e 100644 --- a/compiler/verify/calibre.py +++ b/compiler/verify/calibre.py @@ -20,16 +20,16 @@ Calibre means pointing the code to the proper DRC and LVS rule files. import os import shutil import re -import time import debug from globals import OPTS -from run_script import * +from run_script import run_script # Keep track of statistics num_drc_runs = 0 num_lvs_runs = 0 num_pex_runs = 0 + def write_calibre_drc_script(cell_name, extract, final_verification): """ Write a Calibre runset file and script to run DRC """ # the runset file contains all the options to run calibre @@ -67,6 +67,7 @@ def write_calibre_drc_script(cell_name, extract, final_verification): os.system("chmod u+x {}".format(run_file)) return drc_runset + def write_calibre_lvs_script(cell_name, final_verification): """ Write a Calibre runset file and script to run LVS """ @@ -80,7 +81,7 @@ def write_calibre_lvs_script(cell_name, final_verification): 'lvsSourcePath': cell_name + ".sp", 'lvsSourcePrimary': cell_name, 'lvsSourceSystem': 'SPICE', - 'lvsSpiceFile': "extracted.sp", + 'lvsSpiceFile': "{}.spice".format(cell_name), 'lvsPowerNames': 'vdd', 'lvsGroundNames': 'gnd', 'lvsIncludeSVRFCmds': 1, @@ -130,8 +131,9 @@ def write_calibre_lvs_script(cell_name, final_verification): return lvs_runset -def write_calibre_pex_script(cell_name, extract, output, final_verification): +def write_calibre_pex_script(cell_name, extract, output, final_verification): + """ Write a pex script that can either just extract the netlist or the netlist+parasitics """ if output == None: output = name + ".pex.netlist" @@ -150,10 +152,9 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): 'pexRunDir': OPTS.openram_temp, 'pexLayoutPaths': cell_name + ".gds", 'pexLayoutPrimary': cell_name, - #'pexSourcePath' : OPTS.openram_temp+"extracted.sp", 'pexSourcePath': cell_name + ".sp", 'pexSourcePrimary': cell_name, - 'pexReportFile': cell_name + ".lvs.report", + 'pexReportFile': cell_name + ".pex.report", 'pexPexNetlistFile': cell_name + ".pex.netlist", 'pexPexReportFile': cell_name + ".pex.report", 'pexMaskDBFile': cell_name + ".maskdb", @@ -179,6 +180,7 @@ def write_calibre_pex_script(cell_name, extract, output, final_verification): return pex_runset + def run_drc(cell_name, gds_name, extract=False, final_verification=False): """Run DRC check on a given top-level name which is implemented in gds_name.""" @@ -186,9 +188,15 @@ def run_drc(cell_name, gds_name, extract=False, final_verification=False): global num_drc_runs num_drc_runs += 1 - # 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) + # Filter the layouts through magic as a GDS filter for nsdm/psdm/nwell merging + if OPTS.tech_name == "sky130": + shutil.copy(gds_name, OPTS.openram_temp + "temp.gds") + from magic import filter_gds + filter_gds(cell_name, OPTS.openram_temp + "temp.gds", gds_name) + else: + # 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) drc_runset = write_calibre_drc_script(cell_name, extract, final_verification) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 59346ace..d19537a5 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -33,6 +33,31 @@ num_lvs_runs = 0 num_pex_runs = 0 +def filter_gds(cell_name, input_gds, output_gds): + """ Run the gds through magic for any layer processing """ + global OPTS + + run_file = OPTS.openram_temp + "run_filter.sh" + f = open(run_file, "w") + f.write("#!/bin/sh\n") + f.write("{} -dnull -noconsole << EOF\n".format(OPTS.magic_exe[1])) + f.write("gds polygon subcell true\n") + f.write("gds warning default\n") + f.write("gds read {}\n".format(input_gds)) + f.write("load {}\n".format(cell_name)) + f.write("cellname delete \\(UNNAMED\\)\n") + #f.write("writeall force\n") + f.write("select top cell\n") + f.write("gds write {}\n".format(output_gds)) + f.write("quit -noprompt\n") + f.write("EOF\n") + + f.close() + os.system("chmod u+x {}".format(run_file)) + + (outfile, errfile, resultsfile) = run_script(cell_name, "filter") + + def write_magic_script(cell_name, extract=False, final_verification=False): """ Write a magic script to perform DRC and optionally extraction. """