diff --git a/.github/scripts/parse_rpt.py b/.github/scripts/parse_rpt.py index 71ca1e180..5ae66f197 100644 --- a/.github/scripts/parse_rpt.py +++ b/.github/scripts/parse_rpt.py @@ -1,33 +1,112 @@ +""" +This script performs checks on generated files and reports for different generators based on workflow parameters. + +The `_generator_is` variable is a dictionary with keys and values indicating information about the workflow being run. +Values for each key are determined by how this script is called by the .yml files in .github/workflows. + +The `cryo_library` variable is used to determine which library (sky130hd_cryo, sky130hs_cryo, sky130hvl_cryo) the workflow is targeting. + +1. DRC and LVS Filename Declaration: + This section declares possible DRC and LVS filenames for different generators. + The first condition checks for sky130hd_temp and sky130hvl_ldo, while the elif condition checks for various cryo libraries. + +2. DRC Check: + - Checks if the content in the generated DRC report file matches the template DRC report file stored in .github/scripts/expected_drc_reports/. + - If the number of lines in the DRC report files for temp-sense-gen and cryo-gen is greater than 3, it indicates non-zero errors in the make process. + +3. LVS Check: + - Checks if the LVS report generated by the cryo-gen make has the word 'failed' in the last line, raising an error if found. + - Conducts a search for the word 'failed' in the LVS reports for ldo-gen and temp-sense-gen, raising a ValueError if found. + +4. Result File Check: + - Calls the check_gen_files() function from generators/common/check_gen_files.py. + - Checks if various files (.v, .sdc, .cdl, .sp, .spice, etc.) have been generated for the required generators. + - Takes input parameters: the test.json filename, the dictionary of possible generators, and the cryo_library. +""" + import sys +import json +import os +import re, subprocess +sys.path.append(os.path.join(os.path.dirname(__file__), '..')) +from common.check_gen_files import check_gen_files sys.stdout.flush() -if len(sys.argv) == 1 or sys.argv[1] == "sky130hvl_ldo": +cryo_library = "" +_generator_is = { + 'sky130hvl_ldo': 0, + 'sky130hd_temp': 0, + 'sky130XX_cryo': 0 +} + +if len(sys.argv) == 1: + _generator_is['sky130hd_temp'] = 1 +elif len(sys.argv) > 1: + if sys.argv[1] == 'sky130hvl_ldo': + _generator_is['sky130hvl_ldo'] = 1 + else: + _generator_is['sky130XX_cryo'] = 1 + +if _generator_is['sky130XX_cryo']: + # check which cryo-gen library's workflow is being run + dir_path = r'flow/reports' + lib = os.listdir(dir_path) + cryo_library = str(lib[0]) + +## DRC and LVS Filename Declaration +if _generator_is['sky130hd_temp'] or _generator_is['sky130hvl_ldo']: drc_filename = "work/6_final_drc.rpt" lvs_filename = "work/6_final_lvs.rpt" -else: - drc_filename = "work/"+sys.argv[1]+"/6_final_drc.rpt" - lvs_filename = "work/"+sys.argv[1]+"/6_final_lvs.rpt" +elif len(sys.argv) > 1 and sys.argv[1] == cryo_library: + drc_filename = "flow/reports/" + sys.argv[1] + "/cryo/6_final_drc.rpt" + lvs_filename = "flow/reports/" + sys.argv[1] + "/cryo/6_final_lvs.rpt" + -if len(sys.argv) > 1 and sys.argv[1] == "sky130hvl_ldo": - with open(drc_filename, 'r') as f1, open("../../../.github/scripts/expected_drc_reports/expected_ldo_drc.rpt", 'r') as f2: +## DRC check +if _generator_is['sky130hvl_ldo']: + expected_ldo_rpt_filename = "../../../.github/scripts/expected_drc_reports/expected_ldo_drc.rpt" + with open(drc_filename) as f1, open(expected_ldo_rpt_filename) as f2: content1 = f1.readlines() content2 = f2.readlines() - if content1 == content1: + if content1 == content2: print("DRC is clean!") else: raise ValueError("DRC failed!") - elif sum(1 for line in open(drc_filename)) > 3: raise ValueError("DRC failed!") else: print("DRC is clean!") -with open(lvs_filename) as f: - f1 = f.read() - - if "failed" in f1: +## LVS Check +if len(sys.argv) > 1 and sys.argv[1] == cryo_library: + lvs_line = subprocess.check_output(["tail", "-1", lvs_filename]).decode( + sys.stdout.encoding + ) + regex = r"failed" + match = re.search(regex, lvs_line) + + if match != None: raise ValueError("LVS failed!") else: print("LVS is clean!") +else: + with open(lvs_filename) as f: + f1 = f.read() + + if "failed" in f1: + raise ValueError("LVS failed!") + else: + print("LVS is clean!") + +## Result File Check +if _generator_is['sky130hvl_ldo']: + json_filename = "spec.json" +else: + json_filename = "test.json" + +if check_gen_files(json_filename, _generator_is, cryo_library): + print("Flow check is clean!") +else: + print("Flow check failed!") diff --git a/openfasoc/generators/PMU-gen/tools/parse_rpt.py b/openfasoc/generators/PMU-gen/tools/parse_rpt.py index 7384eb979..1eb96c06e 100755 --- a/openfasoc/generators/PMU-gen/tools/parse_rpt.py +++ b/openfasoc/generators/PMU-gen/tools/parse_rpt.py @@ -22,3 +22,4 @@ raise ValueError("LVS failed!") else: print("LVS is clean!") +print("Generator check is clean!") diff --git a/openfasoc/generators/common/__init__.py b/openfasoc/generators/common/__init__.py index c1ca2645e..f7ed95929 100644 --- a/openfasoc/generators/common/__init__.py +++ b/openfasoc/generators/common/__init__.py @@ -7,6 +7,9 @@ 2. `COMMON_PLATFORMS_PREFIX_MAP` (dict): This is a dictionary of common platforms (currently sky130) and their cell naming prefixes. - `common.simulation` 1. `run_simulations()`: Used to run SPICE testbenches with multiple parameters. - +- `common.check_gen_files` + 1. `check_gen_files(parameters: json_filename, is_tempsense)`: Used to check if the various files that should be generated by the flow are present in their required directories. +- `common.check_gen_extensions` + 1. Stores the extensions of the files generated by the flow. See individual function documentation for more information on a particular function. """ \ No newline at end of file diff --git a/openfasoc/generators/common/check_gen_files.py b/openfasoc/generators/common/check_gen_files.py new file mode 100644 index 000000000..9673c5f14 --- /dev/null +++ b/openfasoc/generators/common/check_gen_files.py @@ -0,0 +1,64 @@ +""" +This script is used to check for the presence of the required non-report files that each generator creates. It gets +the module_name (str) from the .json file present in the generator top-level folder. + +Args: + json_filename (str): String containing the name of the .json filename for each generator + _generator_is (dict): Dictionary containing key-value pairs that signify which generator's flow results are being checked + cryo_library (str): String containing which cryo-gen library (sky130hs, sky130hd, sky130hvl) is being checked for +Uses: + work_dir (str): String containing the directory in which to check files + data (str): String containing data from the .json file + module_name (str): String containing the name of module that the check is being done for (eg. tempsenseInst_error) + extension_file_path (str): Contains the extensions of the files which each generator produces for the flows +Returns: + 1: if all checks are successful +Raises: + ValueError: If any of the various checks go wrong (.csv file checks for temp-sense, flow generated files for all generators) +""" + +import json +import os + +def check_gen_files(json_filename, _generator_is, cryo_library) -> int: + with open(json_filename) as file: + data = json.load(file) + + # print('Found .json config file...') + + module_name = data.get("module_name", "default") + + if _generator_is['sky130XX_cryo']: + work_dir = "./work/" + cryo_library + "/" + else: + work_dir = "./work/" + + if (os.path.exists(work_dir) == 0): + raise ValueError("work directory does not exist!") + else: + filename = work_dir + module_name + extension_file_path = "./tools/check_gen_extensions" + + if os.path.exists(extension_file_path): + with open(extension_file_path) as f: + + for extension in f: + file = "".join([filename, extension.strip()]) + if (os.path.exists(file) == 0): + raise ValueError(file + " does not exist!") + else: + print("checking flow results with possibly stale list of extensions...") + extensions = [".sdc", ".gds", ".def", ".spice", ".v", "_pex.spice"] + for extension in extensions: + file = "".join([filename, extension]) + + if (os.path.exists(file) == 0): + raise ValueError(file + " does not exist!") + # print("Found necessary work result files!") + if _generator_is['sky130hd_temp']: + for file in ("error_within_x.csv", "golden_error_opt.csv", "search_result.csv"): + if os.path.exists(file) == 0: + raise ValueError(file + " does not exist!") + + #print("Found generated .csv files!") + return 1 diff --git a/openfasoc/generators/cryo-gen/tools/check_gen_extensions b/openfasoc/generators/cryo-gen/tools/check_gen_extensions new file mode 100644 index 000000000..499a23dfe --- /dev/null +++ b/openfasoc/generators/cryo-gen/tools/check_gen_extensions @@ -0,0 +1,8 @@ +.gds +.spice +.v +.cdl +_sim.spice +_pex.spice +.sdc +.def diff --git a/openfasoc/generators/cryo-gen/tools/parse_rpt.py b/openfasoc/generators/cryo-gen/tools/parse_rpt.py index 7384eb979..e05f6bc06 100644 --- a/openfasoc/generators/cryo-gen/tools/parse_rpt.py +++ b/openfasoc/generators/cryo-gen/tools/parse_rpt.py @@ -1,8 +1,21 @@ import re import subprocess -import sys +import sys, os -drc_filename = "flow/reports/sky130hd/cyro/6_final_drc.rpt" +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) +from common.check_gen_files import check_gen_files + +_generator_is = { + 'sky130hvl_ldo': 0, + 'sky130hd_temp': 0, + 'sky130XX_cryo': 1 +} + +dir_path = r'flow/reports' +lib = os.listdir(dir_path) +cryo_library = str(lib[0]) + +drc_filename = "flow/reports/" + cryo_library + "/cryo/6_final_drc.rpt" num_lines = sum(1 for line in open(drc_filename)) if num_lines > 3: @@ -10,7 +23,7 @@ else: print("DRC is clean!") -lvs_filename = "flow/reports/sky130hd/cyro/6_final_lvs.rpt" +lvs_filename = "flow/reports/" + cryo_library + "/cryo/6_final_lvs.rpt" lvs_line = subprocess.check_output(["tail", "-1", lvs_filename]).decode( sys.stdout.encoding ) @@ -22,3 +35,10 @@ raise ValueError("LVS failed!") else: print("LVS is clean!") + +json_filename = "test.json" + +if check_gen_files(json_filename, _generator_is, cryo_library): + print("Flow check is clean!") +else: + print("Flow check failed!") diff --git a/openfasoc/generators/dcdc-gen/tools/parse_rpt.py b/openfasoc/generators/dcdc-gen/tools/parse_rpt.py index 7384eb979..1eb96c06e 100755 --- a/openfasoc/generators/dcdc-gen/tools/parse_rpt.py +++ b/openfasoc/generators/dcdc-gen/tools/parse_rpt.py @@ -22,3 +22,4 @@ raise ValueError("LVS failed!") else: print("LVS is clean!") +print("Generator check is clean!") diff --git a/openfasoc/generators/ldo-gen/tools/check_gen_extensions b/openfasoc/generators/ldo-gen/tools/check_gen_extensions new file mode 100644 index 000000000..93a7f6b57 --- /dev/null +++ b/openfasoc/generators/ldo-gen/tools/check_gen_extensions @@ -0,0 +1,6 @@ +.gds +.spice +.v +_pex.spice +.sdc +.def \ No newline at end of file diff --git a/openfasoc/generators/scpa-gen/tools/parse_rpt.py b/openfasoc/generators/scpa-gen/tools/parse_rpt.py index de68aaaa9..31f20ff03 100644 --- a/openfasoc/generators/scpa-gen/tools/parse_rpt.py +++ b/openfasoc/generators/scpa-gen/tools/parse_rpt.py @@ -6,16 +6,4 @@ else: print("DRC is clean!") - -# LVS Bypassed - -# lvs_filename = "flow/reports/sky130hd/tempsense/6_final_lvs.rpt" -# lvs_line = subprocess.check_output(['tail', '-1', lvs_filename]).decode(sys.stdout.encoding) - -# regex = r"failed" -# match = re.search(regex, lvs_line) - -# if match != None: -# raise ValueError("LVS failed!") -# else: -# print("LVS is clean!") +print("Generator check is clean!") diff --git a/openfasoc/generators/temp-sense-gen/Makefile b/openfasoc/generators/temp-sense-gen/Makefile index 1c2cf3806..872a0bb65 100644 --- a/openfasoc/generators/temp-sense-gen/Makefile +++ b/openfasoc/generators/temp-sense-gen/Makefile @@ -47,7 +47,6 @@ sky130hd_temp_verilog: sky130hd_temp: @python3 tools/temp-sense-gen.py --specfile test.json --outputDir ./work $(inv) $(ninv) $(head) $(nhead) --prepex $(sim_pex) --platform sky130hd --mode macro @python3 tools/parse_rpt.py - @tools/verify_op.sh @@echo "==================================================================================" @@echo "Thank you for using OpenFASOC" @@echo "For more info, please read the latest documentation on openfasoc.readthedocs.io" @@ -58,7 +57,6 @@ sky130hd_temp_full: # add --pex to also run pex simulations @python3 tools/temp-sense-gen.py --specfile test.json --outputDir ./work --platform sky130hd --mode full --prepex $(sim_pex) $(inv) $(ninv) $(head) $(nhead) @python3 tools/parse_rpt.py - @tools/verify_op.sh @@echo "==================================================================================" @@echo "Thank you for using OpenFASOC" @@echo "For more info, please read the latest documentation on openfasoc.readthedocs.io" diff --git a/openfasoc/generators/temp-sense-gen/tools/check_gen_extensions b/openfasoc/generators/temp-sense-gen/tools/check_gen_extensions new file mode 100644 index 000000000..93a7f6b57 --- /dev/null +++ b/openfasoc/generators/temp-sense-gen/tools/check_gen_extensions @@ -0,0 +1,6 @@ +.gds +.spice +.v +_pex.spice +.sdc +.def \ No newline at end of file diff --git a/openfasoc/generators/temp-sense-gen/tools/parse_rpt.py b/openfasoc/generators/temp-sense-gen/tools/parse_rpt.py index df5408bb7..b574d3c77 100644 --- a/openfasoc/generators/temp-sense-gen/tools/parse_rpt.py +++ b/openfasoc/generators/temp-sense-gen/tools/parse_rpt.py @@ -1,4 +1,15 @@ -drc_filename = "flow/reports/sky130hd/tempsense/6_final_drc.rpt" +import os, sys + +sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..')) +from common.check_gen_files import check_gen_files + +_generator_is = { + 'sky130hvl_ldo': 0, + 'sky130hd_temp': 1, + 'sky130XX_cryo': 0 +} + +drc_filename = "work/6_final_drc.rpt" num_lines = sum(1 for line in open(drc_filename)) if num_lines > 3: @@ -7,7 +18,7 @@ print("DRC is clean!") -lvs_filename = "flow/reports/sky130hd/tempsense/6_final_lvs.rpt" +lvs_filename = "work/6_final_lvs.rpt" with open(lvs_filename) as f: f1 = f.read() @@ -16,3 +27,10 @@ raise ValueError("LVS failed!") else: print("LVS is clean!") + +json_filename = "test.json" + +if check_gen_files(json_filename, _generator_is, " "): + print("Flow check is clean!") +else: + print("Flow check failed!") diff --git a/openfasoc/generators/temp-sense-gen/tools/verify_op.sh b/openfasoc/generators/temp-sense-gen/tools/verify_op.sh deleted file mode 100755 index 2d3470f43..000000000 --- a/openfasoc/generators/temp-sense-gen/tools/verify_op.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash - -for file in error_within_x.csv golden_error_opt.csv search_result.csv -do - if ! [ -e $file ] - then - echo "[ERROR] $file is not created" - fi -done - -module_name=$(grep "module_name" test.json | cut -d "\"" -f 4) - -if [ -e work ] -then - cd work - for file in $module_name.def $module_name.gds $module_name\_pex.spice $module_name.spice $module_name.v $module_name.sdc - do - if ! [ -e $file ] - then - echo "[ERROR] $file is not created" - fi - done -else - echo "[ERROR] Work directory not created" -fi