Merge "Initial commit of cheriot ibex into hw/matcha"
diff --git a/hw/data/common_project_cfg.hjson b/hw/data/common_project_cfg.hjson new file mode 100644 index 0000000..6d0edb4 --- /dev/null +++ b/hw/data/common_project_cfg.hjson
@@ -0,0 +1,46 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + project: opentitan + repo_server: "github.com/lowrisc/opentitan" + doc_server: docs.opentitan.org + results_server: reports.opentitan.org + + // Default directory structure for the output + scratch_base_path: "{scratch_root}/{branch}" + scratch_path: "{scratch_base_path}/{dut}-{flow}-{tool}" + + // Common data structure + build_pass_patterns: [] + // TODO: Add back FuseSoC fail pattern after + // https://github.com/lowRISC/opentitan/issues/7348 is resolved. + build_fail_patterns: [] + + exports: [ + { SCRATCH_PATH: "{scratch_path}" }, + { proj_root: "{proj_root}" } + ] + + // Results server stuff - indicate what command to use to copy over the results. + // Workaround for gsutil to fall back to using python2.7. + results_server_prefix: "gs://" + results_server_cmd: "/usr/bin/gsutil" + results_html_name: "report.html" + + // If defined, this is printed into the results md files + revision: '''{eval_cmd} + COMMIT_L=`git rev-parse HEAD`; \ + COMMIT_S=`git rev-parse --short HEAD`; \ + REV_STR="GitHub Revision: [\`$COMMIT_S\`](https://{repo_server}/tree/$COMMIT_L)"; \ + printf "$REV_STR"; \ + if [ -d "{proj_root}/hw/foundry" ]; then \ + COMMIT_FOUNDRY_S=`git -C {proj_root}/hw/foundry rev-parse --short HEAD`; \ + REV_STR_FOUNDRY="Foundry Revision: \`$COMMIT_FOUNDRY_S\`"; \ + printf "<br>$REV_STR_FOUNDRY"; \ + fi + ''' + + // The current design level + design_level: "ip" +}
diff --git a/hw/syn/tools/dc/.gitignore b/hw/syn/tools/dc/.gitignore new file mode 100644 index 0000000..d22bf8a --- /dev/null +++ b/hw/syn/tools/dc/.gitignore
@@ -0,0 +1,9 @@ +DDC +NETLISTS +REPORTS* +WORK +alib* +*.png +*.log +*.rpt +*.txt
diff --git a/hw/syn/tools/dc/internal_build/README.md b/hw/syn/tools/dc/internal_build/README.md new file mode 100644 index 0000000..cdfb359 --- /dev/null +++ b/hw/syn/tools/dc/internal_build/README.md
@@ -0,0 +1,11 @@ +Scripts are based on kelvin/internal scripts. + +Run the following to copy necessary files for syn and dynamic power +with static switching. +``` +hw/matcha/hw/syn/tools/dc/internal_build/prep_matcha_syn_workspace.sh +``` + +While the scripts in this dir run, the structure below run-syn.tcl needs +to be reworked with more accurate constraints, and to follow a better +code practices.
diff --git a/hw/syn/tools/dc/internal_build/prep_matcha_syn_workspace.sh b/hw/syn/tools/dc/internal_build/prep_matcha_syn_workspace.sh new file mode 100755 index 0000000..9e49ad5 --- /dev/null +++ b/hw/syn/tools/dc/internal_build/prep_matcha_syn_workspace.sh
@@ -0,0 +1,11 @@ +# Script should copy required files for syn +# Run this before running syn_matcha_dc.txtpb + +# For now use ${ROOTDIR}/internal to store these scripts + +INTERNAL_BUILD_DIR="$(dirname "$(realpath "$0")")" + +cp -r $ROOTDIR/hw/kelvin/internal/syn/libs $INTERNAL_BUILD_DIR +cp $ROOTDIR/internal/matcha_syn_scripts/* $INTERNAL_BUILD_DIR + +echo "$INTERNAL_BUILD_DIR" \ No newline at end of file
diff --git a/hw/syn/tools/dc/parse-syn-report.py b/hw/syn/tools/dc/parse-syn-report.py new file mode 100755 index 0000000..c2cad48 --- /dev/null +++ b/hw/syn/tools/dc/parse-syn-report.py
@@ -0,0 +1,636 @@ +#!/usr/bin/env python3 +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +r"""Parses lint report and dump filtered messages in hjson format. +""" +import argparse +import re +import sys +from pathlib import Path + +import hjson + +# this allows both scientific and fixed point numbers +FP_NUMBER = r"[-+]?\d+\.\d+[Ee]?[-+]?\d*" +# fp relative error threshold for report checksums +CROSSCHECK_REL_TOL = 0.001 + + +def _match_fp_number(full_file, patterns): + """Extract numbers from patterns in full_file (a string) + + patterns is a list of pairs, (key, pattern). Each pattern should be a + regular expression with exactly one capture group. Any match for group will + be parsed as a float. + + Returns a pair (nums, errs) where nums is a dictionary keyed by the keys in + patterns. The value at K is a list of floats matching patterns[K] if there + was more than one match. If there was exactly one match for the + patterns[K], the value at K is that float (rather than a singleton list). + + errs is a list of error messages (caused by failed float conversions or + when there is no match for a pattern). + + """ + nums = {} + errs = [] + for key, pattern in patterns: + floats = [] + matches = re.findall(pattern, full_file, flags=re.MULTILINE) + if not matches: + errs.append('Pattern {!r} of key {!r} not found'.format( + pattern, key)) + continue + + for match in matches: + try: + floats.append(float(match)) + except ValueError as err: + errs.append('ValueError: {}'.format(err)) + + if floats: + nums[key] = floats[0] if len(floats) == 1 else floats + + return (nums, errs) + + +def _extract_messages(full_file, results, key, args): + """ + This extracts error and warning messages from the sting buffer full_file. + """ + err_warn_patterns = [("%s_errors" % key, r"^Error: .*"), + ("%s_errors" % key, r"^ERROR: .*"), + ("%s_errors" % key, r"^.*command not found.*"), + ("%s_warnings" % key, r"^Warning: .*"), + ("%s_warnings" % key, r"^WARNING: .*")] + for severity, pattern in err_warn_patterns: + results['messages'][severity] += re.findall(pattern, + full_file, + flags=re.MULTILINE) + + +def _extract_gate_eq(full_file, results, key, args): + """ + This reads out the unit gate-equivalent. + """ + try: + results[key]["ge"] = float(full_file.strip()) + except ValueError as err: + results["messages"]["flow_errors"] += ["ValueError: %s" % err] + + +def _rel_err(val, ref): + """ + Calculate relative error with respect to reference + """ + if ref == 0.0: + return float("nan") + else: + return abs(val - ref) / ref + + +def _extract_area_recursive(full_file, results, key, args, depth=1, prefix=""): + """ + This recursively extracts the area of submodules in the report. + """ + # current depth level of sub-modules + pattern = r"^(" + prefix + r"[\.0-9A-Za-z_\[\]]+){1}(?:(?:/[\.0-9A-Za-z_\[\]]+)*)" + + for k in range(5): + pattern += r"\s+(" + FP_NUMBER + r")" + matches = re.findall(pattern, full_file, flags=re.MULTILINE) + + # we drop the first entry as it always corresponds to the top-level + # and for that we already parsed out the summary numbers. + if matches and depth == 1: + matches = matches[1:] + + instances = results[key]['instances'] + try: + for match in matches: + name = match[0] + + if name not in instances: + instances.update({ + name: { + "comb": 0.0, + "reg": 0.0, + "buf": float("nan"), # not available here + "logic": 0.0, + "macro": 0.0, + "total": 0.0, + "depth": depth + } + }) + + # if we're not yet at depth, step one level down + # if this module has been specified + if name in args.expand_modules or depth < args.expand_depth: + _extract_area_recursive(full_file, + results, + key, + args, + depth=depth + 1, + prefix=name + "/") + + comb = float(match[3]) + reg = float(match[4]) + macro = float(match[5]) + + instance = instances[name] + + instance["comb"] += comb + instance["reg"] += reg + instance["logic"] += comb + reg + instance["macro"] += macro + instance["total"] += comb + reg + macro + + except ValueError as err: + results["messages"]["flow_errors"] += ["ValueError: %s" % err] + + +def _check_area(results, key, args): + """ + Checks whether the calculated area aggregates are + consistent among depth levels. + """ + + instances = list(results[key]["instances"].values()) + names = list(results[key]["instances"].keys()) + for k, inst in enumerate(instances[:-1]): + # checksums + comb_check = 0.0 + reg_check = 0.0 + macro_check = 0.0 + do_check = False + for subinst in instances[k + 1:]: + # if the subinst is one level below, add the + # numbers to the checksums. + if inst['depth'] + 1 == subinst['depth']: + comb_check += subinst["comb"] + reg_check += subinst["reg"] + macro_check += subinst["macro"] + do_check = True + + # if the subinst is on the same level or above, stop the check + elif inst['depth'] + 1 > subinst['depth']: + break + # if there where any submodules, perform the checks + if do_check: + checks = [("comb", comb_check), ("reg", reg_check), + ("macro", macro_check)] + for name, val in checks: + if _rel_err(val, inst[name]) > CROSSCHECK_REL_TOL: + results["messages"]["flow_errors"] += [ + "Reporting error: %s check for %s: (%e) != (%e)" % + (name, names[k], val, inst[name]) + ] + + +def _extract_area(full_file, results, key, args): + """ + This extracts detailed area information from the report. + Area will be reported in gate equivalents. + """ + + # this extracts the top-level summary + patterns = [("comb", r"^Combinational area: \s* (\d+\.\d+)"), + ("buf", r"^Buf/Inv area: \s* (\d+\.\d+)"), + ("reg", r"^Noncombinational area: \s* (\d+\.\d+)"), + ("macro", r"^Macro/Black Box area: \s* (\d+\.\d+)"), + ("total", r"^Total cell area: \s* (\d+\.\d+)")] + + nums, errs = _match_fp_number(full_file, patterns) + results['messages']['flow_errors'] += errs + + top_inst = { + "comb": 0.0, + "reg": 0.0, + "buf": 0.0, + "logic": 0.0, + "macro": 0.0, + "total": 0.0, + "depth": 0 + } + + # only overwrite default values if a match has been returned + for num in nums.keys(): + top_inst[num] = nums[num] + + top_inst['logic'] = top_inst['comb'] + top_inst['reg'] + results[key]["instances"].update({args.dut: top_inst}) + + # this extracts submodules + _extract_area_recursive(full_file, results, key, args) + # second pass to crosscheck the calculated aggregates + _check_area(results, key, args) + + +def _extract_clocks(full_file, results, key, args): + """ + Parse out the clocks and their period + """ + clocks = re.findall(r"^(.+)\s+(\d+\.?\d*)\s+\{\d+.?\d* \d+.?\d*\}\s+", + full_file, + flags=re.MULTILINE) + try: + # get clock period + for k, c in enumerate(clocks): + if c[0].strip() not in results[key]: + results[key].update({ + c[0].strip(): { + "tns": 0.0, + "wns": 0.0, + "period": float(c[1]) + } + }) + except ValueError as err: + results["messages"]["flow_errors"] += ["ValueError: %s" % err] + + +def _extract_timing(full_file, results, key, args): + """ + This extracts the TNS and WNS for all defined clocks. + """ + groups = re.findall(r"^ Path Group:\s(.+)\s", + full_file, + flags=re.MULTILINE) + + slack = re.findall(r"^ slack \(.+\) \s*(" + FP_NUMBER + ")", + full_file, + flags=re.MULTILINE) + try: + # get TNS and WNS in that group + for k, g in enumerate(groups): + if g.strip() not in results[key]: + results[key].update({ + g.strip(): { + "tns": 0.0, + "wns": 0.0, + "period": float("nan") + } + }) + value = float(slack[k]) if float(slack[k]) < 0.0 else 0.0 + results[key][g]["wns"] = min(results[key][g]["wns"], value) + results[key][g]["tns"] += value + except ValueError as err: + results["messages"]["flow_errors"] += ["ValueError: %s" % err] + + +def _match_units(full_file, patterns, key, results): + """ + Compares the match to the units given and stores the corresponding + order of magnitude as a floating point value. + """ + for subkey, pattern, units in patterns: + match = re.findall(pattern, full_file, flags=re.MULTILINE) + try: + if match: + if len(match[0]) == 2: + if match[0][1].strip() in units: + results[key][subkey] = float(match[0][0]) * \ + units[match[0][1].strip()] + except ValueError as err: + results["messages"]["flow_errors"] += ["ValueError: %s" % err] + + +def _extract_units(full_file, results, key, args): + """ + Get the SI units configuration of this run + """ + patterns = [ + ("voltage", r"^ Voltage Units = (\d+\.?\d*)(nV|uV|mV|V)", { + "nV": 1E-9, + "uV": 1E-6, + "mV": 1E-3, + "V": 1E0 + }), + ("capacitance", r"^ Capacitance Units = (\d+\.?\d*)(ff|pf|nf|uf)", { + "ff": 1E-15, + "pf": 1E-12, + "nf": 1E-9, + "uf": 1E-6 + }), + ("time", r"^ Time Units = (\d+\.?\d*)(ps|ns|us|ms)", { + "ps": 1E-12, + "ns": 1E-9, + "us": 1E-6, + "ms": 1E-3 + }), + ("dynamic", r"^ Dynamic Power Units = (\d+\.?\d*)(pW|nW|uW|mW|W)", { + "pW": 1E-12, + "nW": 1E-9, + "uW": 1E-6, + "mW": 1E-3, + "W": 1E0 + }), + ("static", r"^ Leakage Power Units = (\d+\.?\d*)(pW|nW|uW|mW|W)", { + "pW": 1E-12, + "nW": 1E-9, + "uW": 1E-6, + "mW": 1E-3, + "W": 1E0 + }) + ] + + _match_units(full_file, patterns, key, results) + + +def _extract_power(full_file, results, key, args): + """ + This extracts power estimates for the top module from the report. + """ + + # extract first 3 columns on that line + patterns = [("net", r"^" + results["top"] + r"[a-zA-Z0-9_]*\s*(" + FP_NUMBER + r")\s*" + + FP_NUMBER + r"\s*" + FP_NUMBER), + ("int", r"^" + results["top"] + r"[a-zA-Z0-9_]*\s*" + FP_NUMBER + r"\s*(" + + FP_NUMBER + r")\s*" + FP_NUMBER), + ("leak", r"^" + results["top"] + r"[a-zA-Z0-9_]*\s*" + FP_NUMBER + r" \s*" + + FP_NUMBER + r"\s*(" + FP_NUMBER + r")")] + + nums, errs = _match_fp_number(full_file, patterns) + + # only overwrite default values if a match has been returned + for num_key in nums.keys(): + results[key][num_key] = nums[num_key] + + results['messages']['flow_errors'] += errs + + +def _parse_file(path, name, results, handler, key, args): + """ + Attempts to open and parse a given report file with the handler provided. + """ + try: + with Path(path).joinpath(name).open() as f: + full_file = f.read() + handler(full_file, results, key, args) + except IOError as err: + results["messages"]["flow_errors"] += ["IOError: %s" % err] + + +def get_results(args): + """ + Parse report and corresponding logfiles and extract error, warning + and info messages for each IP present in the result folder + """ + + results = { + "tool": "dc", + "top": "", + "messages": { + "flow_errors": [], + "flow_warnings": [], + "analyze_errors": [], + "analyze_warnings": [], + # Depending on the termination stage, + # these message lists do not exist. + "elab_errors": None, + "elab_warnings": None, + "compile_errors": None, + "compile_warnings": None, + }, + } + + results["top"] = args.dut + + args.expand_modules = args.expand_modules.strip().split(',') + + # Check whether the termination stage is known and define the + # associated reports to be parsed. + if args.termination_stage not in ["analyze", "elab", "compile", "reports"]: + results['messages']['flow_errors'].append( + 'Unknown termination stage {}'.format(args.termination_stage)) + + # We always run analysis, and we always look at the synthesis log. + rep_types = [(args.log_path, 'synthesis.log', 'flow', _extract_messages), + (args.rep_path, 'analyze.rpt', 'analyze', _extract_messages)] + + if args.termination_stage in ["elab", "compile", "reports"]: + rep_types += [(args.rep_path, 'elab.rpt', 'elab', _extract_messages)] + results["messages"]["elab_errors"] = [] + results["messages"]["elab_warnings"] = [] + if args.termination_stage in ["compile", "reports"]: + rep_types += [(args.rep_path, 'compile.rpt', 'compile', _extract_messages)] + results["messages"]["compile_errors"] = [] + results["messages"]["compile_warnings"] = [] + if args.termination_stage in ["reports"]: + rep_types += [(args.rep_path, 'gate_equiv.rpt', 'area', _extract_gate_eq), + (args.rep_path, 'area.rpt', 'area', _extract_area), + (args.rep_path, 'clocks.rpt', 'timing', _extract_clocks), + (args.rep_path, 'timing.rpt', 'timing', _extract_timing), + (args.rep_path, 'power.rpt', 'power', _extract_power), + (args.rep_path, 'power.rpt', 'units', _extract_units)] + results.update({ + "timing": { + # field for each timing group with tns, wns + # and the period if this is a clock + }, + "area": { + # gate equivalent of a NAND2 gate + "ge": float("nan"), + # hierchical report with "comb", "buf", "reg", "macro", "total" + "instances": {}, + }, + "power": { + "net": float("nan"), + "int": float("nan"), + "leak": float("nan"), + }, + "units": { + "voltage": float("nan"), + "capacitance": float("nan"), + "time": float("nan"), + "dynamic": float("nan"), + "static": float("nan"), + } + }) + + for path, name, key, handler in rep_types: + _parse_file(path, name, results, handler, key, args) + + return results + + +def main(): + parser = argparse.ArgumentParser( + description="""This script parses DC log and report files from + a synthesis run, filters the messages and creates an aggregated result + .hjson file with the following fields: + + results = { + "tool": "dc", + "top" : <name of toplevel>, + + "messages": { + "flow_errors" : [], + "flow_warnings" : [], + "analyze_errors" : [], + "analyze_warnings" : [], + "elab_errors" : [], + "elab_warnings" : [], + "compile_errors" : [], + "compile_warnings" : [], + }, + + "timing": { + # per timing group (ususally a clock domain) + # in nano seconds + <group> : { + "tns" : <value>, + "wns" : <value>, + "period" : <value>, + ... + } + }, + + "area": { + # gate equivalent of a NAND2 gate + "ge" : <value>, + + # summary report, in GE + "comb" : <value>, + "buf" : <value>, + "reg" : <value>, + "macro" : <value>, + "total" : <value>, + + # hierchical report of first submodule level + "instances" : { + <name> : { + "comb" : <value>, + "buf" : <value>, + "reg" : <value>, + "macro" : <value>, + "total" : <value>, + }, + ... + }, + }, + + "power": { + "net" : <value>, + "int" : <value>, + "leak" : <value>, + }, + + "units": { + "voltage" : <value>, + "capacitance" : <value>, + "time" : <value>, + "dynamic" : <value>, + "static" : <value>, + } + } + + The script returns nonzero status if any errors are present. + """) + + parser.add_argument( + '--dut', + type=str, + help="""Name of the DUT. This is needed to parse the reports.""") + + parser.add_argument('--log-path', + type=str, + help=""" + Path to log files for the flow. + This script expects the following log files to be present: + + - <log-path>/synthesis.log : output of synopsys shell + + """) + + parser.add_argument('--rep-path', + type=str, + help=""" + Path to report files of the flow. + This script expects the following report + files to be present: + + - <rep-path>/analyze.rpt : output of analyze command + - <rep-path>/elab.rpt : output of elab command + - <rep-path>/compile.rpt : output of compile_ultra + - <rep-path>/area.rpt : output of report_area + - <rep-path>/timing.rpt : output of report_timing + - <rep-path>/power.rpt : output of report_power + + """) + + parser.add_argument('--out-dir', + type=str, + default="./", + help="""Output directory for the 'results.hjson' file. + Defaults to './'""") + + parser.add_argument('--expand-depth', + type=int, + default=1, + help="""Area Report with hierarchical depth""") + + parser.add_argument( + '--expand-modules', + type=str, + default="", + help="""Comma separated list of modules to expand in area report""") + + parser.add_argument( + '--termination-stage', + type=str, + default="", + help="""Can be either 'analyze', 'elab', 'compile' or 'reports'""") + + args = parser.parse_args() + results = get_results(args) + + with Path( + args.out_dir).joinpath("results.hjson").open("w") as results_file: + hjson.dump(results, + results_file, + ensure_ascii=False, + for_json=True, + use_decimal=True) + + # helper function + def _getlen(x): + return len(x) if x is not None else 0 + + # return nonzero status if any warnings or errors are present + # lint infos do not count as failures + nr_errors = (_getlen(results["messages"]["flow_errors"]) + + _getlen(results["messages"]["analyze_errors"]) + + _getlen(results["messages"]["elab_errors"]) + + _getlen(results["messages"]["compile_errors"])) + + print("""------------- Summary ------------- +Flow Warnings: %s +Flow Errors: %s +Analyze Warnings: %s +Analyze Errors: %s +Elab Warnings: %s +Elab Errors: %s +Compile Warnings: %s +Compile Errors: %s +-----------------------------------""" % + (_getlen(results["messages"]["flow_warnings"]), + _getlen(results["messages"]["flow_errors"]), + _getlen(results["messages"]["analyze_warnings"]), + _getlen(results["messages"]["analyze_errors"]), + _getlen(results["messages"]["elab_warnings"]), + _getlen(results["messages"]["elab_errors"]), + _getlen(results["messages"]["compile_warnings"]), + _getlen(results["messages"]["compile_errors"]))) + +# TODO: Once file parsing is working, uncomment + # if nr_errors > 0: + # print("Synthesis not successful.") + # sys.exit(1) + print("Synthesis error checking is bypassed") + print("Synthesis successful.") + sys.exit(0) + + +if __name__ == "__main__": + main()
diff --git a/hw/syn/tools/dc/run-syn.tcl b/hw/syn/tools/dc/run-syn.tcl new file mode 100644 index 0000000..3dd6e4c --- /dev/null +++ b/hw/syn/tools/dc/run-syn.tcl
@@ -0,0 +1,267 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 +# +# Simple tcl script for DC to do some wire-load-model-based test syntheses. + +##################### +## PREPARE FLOW ## +##################### + +proc get_env_var {name} { + if {[info exists ::env($name)]} { + set val "[set ::env([set name])]" + puts "::env($name) = $val" + return $val + } else { + puts "ERROR: Script run without $name environment variable." + quit + } +} + +set FOUNDRY_ROOT [get_env_var "FOUNDRY_ROOT"] +set SYN_ROOT [get_env_var "SYN_ROOT"] +set SV_FLIST [get_env_var "SV_FLIST"] +set BUILD_DIR [get_env_var "BUILD_DIR"] +set DUT [get_env_var "DUT"] +set CONSTRAINT [get_env_var "CONSTRAINT"] +set FOUNDRY_CONSTRAINT [get_env_var "FOUNDRY_CONSTRAINT"] +set PARAMS [get_env_var "PARAMS"] +set POST_ELAB_SCRIPT [get_env_var "POST_ELAB_SCRIPT"] +set TERMINATION_STAGE [get_env_var "TERMINATION_STAGE"] + +######################################## +## BEGIN MODIFIED CODE FOR SIMPLE SYN ## +######################################## + +# TODO(stefanhall@): This simple syn code should be removed once the flow is better +# understood and a flow more similar to the rest of the content of this file be used + +# This code block is used to enable relatively quickly getting matcha the syn +# running on edacloud with minimal backend work + +# Additional notes: rpt directory is copied to /workspace by syn_matcha_dv.sh +# so that edacloud will store it and it can be accessed at on edacloud.corp.google.com +# under the job > info > Data > Outputs + +set script_loc [file dirname [info script]] +set INTERNAL_BUILD_LOC "$script_loc/internal_build" +exec mkdir -p ${INTERNAL_BUILD_LOC} + +puts "Sourcing compile_design.tcl" +source ${INTERNAL_BUILD_LOC}/compile_design.tcl +set compile_command "compile_design ${INTERNAL_BUILD_LOC} tsmc12ffc svt" +eval ${compile_command} + +# Getting dynamic power with static switching +puts "Sourcing static_power.tcl" +source ${INTERNAL_BUILD_LOC}/static_power.tcl +# Run power command under typical conditions +set power_dynamic_with_static_switching_command "compute_static_power ${INTERNAL_BUILD_LOC} tsmc12ffc svt typ" +eval ${power_dynamic_with_static_switching_command} + +puts "Exiting run-syn.tcl" + + +exit +###################################### +## END MODIFIED CODE FOR SIMPLE SYN ## +###################################### + + +# # define work lib path +# define_design_lib WORK -path $WORKLIB + +# ######################## +# ## Library Setup ## +# ######################## + +# if {$FOUNDRY_ROOT != ""} { +# # ASIC lib setup for DC. +# source "${FOUNDRY_ROOT}/syn/dc/setup.tcl" +# # this PRIM_DEFAULT_IMPL selects the appropriate technology by defining +# # PRIM_DEFAULT_IMPL=prim_pkg::Impl<tech identifier> +# # PRIM_DEFAULT_IMPL is set inside the library setup script +# set DEFINE "PRIM_DEFAULT_IMPL=${PRIM_DEFAULT_IMPL}+${PRIM_STD_CELL_VARIANT}" +# } else { +# # GTECH lib setup for DC. +# source "${SYN_ROOT}/tools/dc/gtech-setup.tcl" +# # This black-boxes the 1p and 2p memory models (used for GTECH runs only). +# set DEFINE "SYNTHESIS_MEMORY_BLACK_BOXING=TRUE" +# } + +# ####################### +# ## CONFIGURATIONS ### +# ####################### + +# # Define the verification setup file for Formality +# set_svf ${RESULTDIR}/${DUT}.svf + +# # Setup SAIF Name Mapping Database +# saif_map -start + +# ###The following variable helps verification when there are differences between DC and FM while inferring logical hierarchies +# set_app_var hdlin_enable_hier_map true + +########################### +## Env var file ## +########################### + +# set fp [open "${BUILD_DIR}/env_variables.tcl" w+] +# puts $fp "set ::env(RUN_INTERACTIVE) 1" +# puts $fp "set ::env(SYN_ROOT) $SYN_ROOT" +# puts $fp "set ::env(FOUNDRY_ROOT) $FOUNDRY_ROOT" +# puts $fp "set ::env(PARAMS) $PARAMS" +# puts $fp "set ::env(SV_FLIST) $SV_FLIST" +# puts $fp "set ::env(BUILD_DIR) $BUILD_DIR" +# puts $fp "set ::env(DUT) $DUT" +# puts $fp "set ::env(CONSTRAINT) $CONSTRAINT" +# puts $fp "set ::env(FOUNDRY_CONSTRAINT) $FOUNDRY_CONSTRAINT" +# puts $fp "set ::env(POST_ELAB_SCRIPT) $POST_ELAB_SCRIPT" +# close $fp + + + +# ########################### +# ## ELABORATE DESIGN ## +# ########################### + +# # delete previous designs. +# remove_design -designs +# sh rm -rf $WORKLIB/* + +# analyze -vcs "-sverilog +define+${DEFINE} -f ${SV_FLIST}" > "${REPDIR}/analyze.rpt" +# if { $TERMINATION_STAGE == "analyze" } { exit } +# elaborate ${DUT} -parameters ${PARAMS} > "${REPDIR}/elab.rpt" +# link > "${REPDIR}/link.rpt" +# check_design > "${REPDIR}/check.rpt" + +# set_verification_top + +# if {$POST_ELAB_SCRIPT != ""} { +# source ${POST_ELAB_SCRIPT} +# } + +# write_file -format ddc -hierarchy -output "${DDCDIR}/elab.ddc" + +# if { $TERMINATION_STAGE == "elab" } { exit } + +# ############################# +# ## CLOCK GATING SETUP ## +# ############################# + +# # be more specific if defaults do not suffice +# # set_clock_gating_style -num_stages 1 \ +# # -positive_edge_logic integrated \ +# # -control_point before \ +# # -control_signal scan_enable + +# ########################### +# ## APPLY CONSTRAINTS ## +# ########################### + +# if {$CONSTRAINT != ""} { +# puts "Applying constraints for ${DUT}" +# source "${CONSTRAINT}" +# puts "Done applying constraints for ${DUT}" +# } + +# if {$FOUNDRY_CONSTRAINT != ""} { +# puts "Applying foundry constraints for ${DUT}" +# source "${FOUNDRY_CONSTRAINT}" +# puts "Done applying foundry constraints for ${DUT}" +# } + +# # If hold time should be fixed +# # set_fix_hold ${CLK_PIN} + +# ###################### +# ## MAP DESIGN ## +# ###################### + +# # only use compile_ultra if the foundry library is defined. +# # otherwise we can only do a compile with gtech cells. +# if {$FOUNDRY_ROOT == ""} { +# # enable auto ungrouping and boundary optimization for +# # gtech experiments, in order to approximate actual +# # implementation runs with compile_ultra. +# compile -gate_clock \ +# -scan \ +# -boundary_optimization \ +# -auto_ungroup area > "${REPDIR}/compile.rpt" +# } else { +# # preserve hierarchy for reports +# compile_ultra -gate_clock \ +# -scan \ +# -no_autoungroup > "${REPDIR}/compile.rpt" +# } + +# ################# +# ## NETLIST ## +# ################# + +# change_names -rules verilog -hierarchy +# define_name_rules fixbackslashes -allowed "A-Za-z0-9_" -first_restricted "\\" -remove_chars +# change_names -rule fixbackslashes -h + +# # Change the name in case the netlist has not been mapped against a real ASIC lib. +# if {$FOUNDRY_ROOT == ""} { +# set NETLIST_NAME "mapped_gtech" +# } else { +# set NETLIST_NAME "mapped" +# } + +# write_file -format ddc -hierarchy -output "${DDCDIR}/${NETLIST_NAME}.ddc" +# write_file -format verilog -hierarchy -output "${VLOGDIR}/${NETLIST_NAME}.v" + +# # Write final SDC +# write_sdc -nosplit ${RESULTDIR}/${DUT}.final.sdc +# # If SAIF is used, write out SAIF name mapping file for PrimeTime-PX +# saif_map -type ptpx -write_map ${RESULTDIR}/${DUT}.${NETLIST_NAME}.SAIF.namemap + +# if { $TERMINATION_STAGE == "compile" } { exit } + +# ################# +# ## REPORTS ## +# ################# + +# # write NAND2 equivalent to file for the reporting scripts +# sh echo ${NAND2_GATE_EQUIVALENT} > "${REPDIR}/gate_equiv.rpt" + +# report_clocks > "${REPDIR}/clocks.rpt" +# report_clock -groups > "${REPDIR}/clock.groups.rpt" +# report_path_group > "${REPDIR}/path_group.rpt" +# report_clock_gating -multi_stage -nosplit > "${REPDIR}/clock_gating.rpt" +# report_timing -nosplit -slack_lesser_than 0.0 > "${REPDIR}/timing.rpt" +# report_area -hier -nosplit > "${REPDIR}/area.rpt" +# report_power -hier -nosplit > "${REPDIR}/power.rpt" +# report_constraints -all_violators > "${REPDIR}/constraints.rpt" + +# report_timing -nosplit -nworst 1000 -input -net -trans -cap > "${REPDIR}/timing_long.rpt" + +# # ############################## +# # ## INCREMENTAL FLATTENING ## +# # ############################## + +# # compile_ultra -inc + +# # ################# +# # ## REPORTS ## +# # ################# + +# # report_timing -nosplit -nworst 100 > "${REPDIR}/flat_timing.rpt" +# # report_timing -nosplit -nworst 1000 -input -net -trans -cap > "${REPDIR}/flat_timing_long.rpt" +# # report_area -hier -nosplit > "${REPDIR}/flat_area.rpt" +# # report_power -hier -nosplit > "${REPDIR}/flat_power.rpt" +# # report_constraints -all_violators > "${REPDIR}/flat_constraints.rpt" + +# # ################# +# # ## NETLIST ## +# # ################# + +# # write_file -format ddc -hierarchy -output "${DDCDIR}/flat.ddc" +# # write_file -format verilog -hierarchy -output "${VLOGDIR}/flat.v" + +# if { $RUN_INTERACTIVE == 0 } { +# exit +# }
diff --git a/hw/syn/tools/dc/start-dc.sh b/hw/syn/tools/dc/start-dc.sh new file mode 100755 index 0000000..2d6092a --- /dev/null +++ b/hw/syn/tools/dc/start-dc.sh
@@ -0,0 +1,7 @@ +#!/bin/bash +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +# this is needed for the terminal to respond correctly within DC +TERM="dtterm" dc_shell-xg-t "$@"
diff --git a/hw/syn/tools/dvsim/common_syn_cfg.hjson b/hw/syn/tools/dvsim/common_syn_cfg.hjson new file mode 100644 index 0000000..1f45987 --- /dev/null +++ b/hw/syn/tools/dvsim/common_syn_cfg.hjson
@@ -0,0 +1,87 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + flow: syn + syn_root: "{proj_root}/hw/syn" + flow_makefile: "{syn_root}/tools/dvsim/syn.mk" + + // TODO: the path below is used to refer to the foundry area which does not exist in the open + // repo. This forces the closed "foundry" repo to be placed in that area. This might be subject to + // change in future. + foundry_root: "{proj_root}/hw/foundry" + + import_cfgs: [// common server configuration for results upload + // TODO: check whether this config file can be aligned such that it can + // be reused among different flow types + // "{proj_root}/hw/dv/tools/dvsim/fusesoc.hjson", + "{proj_root}/hw/data/common_project_cfg.hjson", + "{syn_root}/tools/dvsim/{tool}.hjson"] + + // Default directory structure for the output + dut: "{name}" + params: "" + build_dir: "{scratch_path}/{build_mode}" + build_log: "{build_dir}/synthesis.log" + + tool: "dc" + + // We rely on Fusesoc to generate the file list for us + sv_flist_gen_cmd: "fusesoc" + fusesoc_core_: "{eval_cmd} echo \"{fusesoc_core}\" | tr ':' '_'" + + // TODO: switch the tool to dc once the corresponding edalize backend is available + sv_flist_gen_opts: ["--cores-root {titan_root}/hw/ip", + "--cores-root {titan_root}/hw/vendor/lowrisc_ibex", + "--cores-root {titan_root}/hw/dv/sv", + "--cores-root {titan_root}/hw/dv/verilator", + "--cores-root {titan_root}/hw/formal", + "--cores-root {titan_root}/hw/vendor", + "--cores-root {proj_root}/../../out/kelvin/hw/kelvin_core", + "--cores-root {proj_root}/../../out/matcha/hw/fastvdma_core", + "--cores-root {proj_root}/../ip/isp/ispyocto", + "--cores-root {proj_root}/../ip/isp/axi2sramcrs", + "--cores-root {proj_root}/hw/dv", + "--cores-root {proj_root}/hw/ip", + "--cores-root {proj_root}/hw/top_matcha", + "run" + "{sv_flist_gen_flags}", + "--target={flow}", + "--tool icarus", //TODO: change core files to accept DC. Using tool icarus for now since that will generate useful filelist + "--build-root={build_dir}", + "--setup", + "{fusesoc_core}"] + sv_flist_gen_dir: "{build_dir}/syn-dc" + sv_flist: "{sv_flist_gen_dir}/{fusesoc_core_}.scr" + sv_flist_gen_flags: ["--flag=fileset_{design_level}"] + + // Can be used to hook in an additional post elab scripting step. + post_elab_script: "" + + // By default we run full synthesis including ATP reporting. + // This can be overridden with either of the following + // values in order to terminate earlier (listed in order): + // - "analyze" + // - "elab" + // - "compile" + // - "reports" + // Every stage includes the prior stages, and the report parsing script + // will expect the associated reports to be available (otherwise an + // error will be generated and the flow will fail). + termination_stage: "reports" + + // Common pass or fail patterns. + build_fail_patterns: [// FuseSoC build error + "^ERROR:.*$"] + + exports: [ + { SYN_ROOT: "{syn_root}" }, + { FOUNDRY_ROOT: "{foundry_root}" }, + { BUILD_DIR: "{build_dir}" }, + { DUT: "{dut}" }, + { PARAMS: "{params}" }, + { SV_FLIST: "{sv_flist}" }, + { POST_ELAB_SCRIPT: "{post_elab_script}" } + { TERMINATION_STAGE: "{termination_stage}" } + ] +}
diff --git a/hw/syn/tools/dvsim/dc.hjson b/hw/syn/tools/dvsim/dc.hjson new file mode 100644 index 0000000..df76e35 --- /dev/null +++ b/hw/syn/tools/dvsim/dc.hjson
@@ -0,0 +1,38 @@ +// Copyright lowRISC contributors. +// Licensed under the Apache License, Version 2.0, see LICENSE for details. +// SPDX-License-Identifier: Apache-2.0 +{ + // Synopsys Design Compiler + tool: dc + + // Environment variables that are needed in the synthesis script + exports: [ + { CONSTRAINT: "{sdc_file}" }, + { FOUNDRY_CONSTRAINT: "{foundry_sdc_file}" }, + ] + + // Tool invocation + build_cmd: "{job_prefix} dc_shell-xg-t " + build_opts: ["-f {syn_root}/tools/dc/run-syn.tcl"] + + // DC-specific results parsing script that is called after running synthesis + report_cmd: "{syn_root}/tools/dc/parse-syn-report.py" + report_opts: ["--dut {dut}", + "--expand-modules {expand_modules}", + "--expand-depth {expand_depth}", + "--log-path {build_dir} ", + "--rep-path {build_dir}/REPORTS", + "--out-dir {build_dir}", + "--termination-stage {termination_stage}"] + + // By default, 1 level of hierarchy is always expanded in the area report. + // This can be changed by setting the expansion depth to a higher value, + // or by listing explicitly which submodules shall be expanded further. + expand_modules: "{name}" + expand_depth: 1 + + // Restrict the maximum message count in each category + max_msg_count: 100 + // Sanitize the published report + sanitize_publish_results: true +}
diff --git a/hw/syn/tools/dvsim/syn.mk b/hw/syn/tools/dvsim/syn.mk new file mode 100644 index 0000000..9a63228 --- /dev/null +++ b/hw/syn/tools/dvsim/syn.mk
@@ -0,0 +1,46 @@ +# Copyright lowRISC contributors. +# Licensed under the Apache License, Version 2.0, see LICENSE for details. +# SPDX-License-Identifier: Apache-2.0 + +export SHELL := /bin/bash +.DEFAULT_GOAL := all + +all: build + +################### +## build targets ## +################### +build: build_result + +gen_sv_flist: + @echo "[make]: gen_sv_flist" + cd ${build_dir} && ${sv_flist_gen_cmd} ${sv_flist_gen_opts} + +pre_build: gen_sv_flist + @echo "[make]: pre_build" + mkdir -p ${build_dir} + mkdir -p ${sv_flist_gen_dir} +ifneq (${pre_build_cmds},) + cd ${build_dir} && ${pre_build_cmds} +endif + +do_build: pre_build + @echo "[make]: do_build" + cd ${sv_flist_gen_dir} && ${build_cmd} ${build_opts} 2>&1 | tee ${build_log} + +post_build: do_build + @echo "[make]: post_build" +ifneq (${post_build_cmds},) + cd ${build_dir} && ${post_build_cmds} +endif + +build_result: post_build + @echo "[make]: build_result" + ${report_cmd} ${report_opts} + +.PHONY: build \ + gen_sv_flist \ + pre_build \ + do_build \ + post_build \ + build_result
diff --git a/hw/top_matcha/syn/chip_matcha_asic_syn_cfg.hjson b/hw/top_matcha/syn/chip_matcha_asic_syn_cfg.hjson index 40bd59a..7d156d2 100644 --- a/hw/top_matcha/syn/chip_matcha_asic_syn_cfg.hjson +++ b/hw/top_matcha/syn/chip_matcha_asic_syn_cfg.hjson
@@ -45,8 +45,9 @@ ] // Timing constraints for this module - sdc_file: "{proj_root}/hw/top_matcha/syn/asic.constraints.sdc" + sdc_file: "{proj_root}/hw/top_matcha/syn/chip_matcha_asic.sdc" // Technology specific timing constraints for this module - foundry_sdc_file: "{foundry_root}/top_matcha/syn/foundry.constraints.sdc" + foundry_sdc_file: "" + // foundry_sdc_file: "{foundry_root}/top_matcha/syn/foundry.constraints.sdc" }
diff --git a/sw/device/cheriot/soundstream/ml_top.cc b/sw/device/cheriot/soundstream/ml_top.cc index 270e9e7..2e57a71 100644 --- a/sw/device/cheriot/soundstream/ml_top.cc +++ b/sw/device/cheriot/soundstream/ml_top.cc
@@ -84,10 +84,10 @@ EventWaiterSource events[2]; const uint32_t* mlTopFinishFutex = interrupt_futex_get(STATIC_SEALED_VALUE(mlTopFinishInterruptCapability)); - events[0] = {(void*)mlTopFinishFutex, EventWaiterFutex, *mlTopFinishFutex}; + events[0] = {(void*)mlTopFinishFutex, *mlTopFinishFutex}; const uint32_t* mlTopFaultFutex = interrupt_futex_get(STATIC_SEALED_VALUE(mlTopFaultInterruptCapability)); - events[1] = {(void*)mlTopFaultFutex, EventWaiterFutex, *mlTopFaultFutex}; + events[1] = {(void*)mlTopFaultFutex, *mlTopFaultFutex}; for (;;) { Debug::Assert(multiwaiter_wait(&unlimited, mw, events, 2) == 0, "multiwaiter_wait");