diff --git a/flow/Makefile.py b/flow/Makefile.py deleted file mode 100644 index db66359669..0000000000 --- a/flow/Makefile.py +++ /dev/null @@ -1,130 +0,0 @@ -import argparse -import glob -import os -import re -import shutil -import sys - -import siliconcompiler - -mydir = os.path.dirname(__file__) -scdir = os.path.join(mydir, 'scripts', 'sc') -sys.path.append(os.path.join(scdir, 'util')) -import parse_config_mk - -def main(): - ''' - SiliconCompiler-based implementation of the OpenROAD build flow. - - This script mimics the Makefile-based build flow, running a series of TCL scripts and - minor pre/post-processing based on platform and design parameters defined in 'config.mk' files. - - This script orchestrates the process of parsing config files, configuring a siliconcompiler.Chip - object, and running the OpenROAD flow scripts. - The 'siliconcompiler' Python module must be installed for this script to work: - - pip3 install siliconcompiler - - To build a design, run this file with the -DESIGN_CONFIG parameter set to - the desired 'config.mk' file. Example: - - export SCPATH=./scripts/sc - python Makefile.py -DESIGN_CONFIG=./designs/nangate45/gcd/config.mk - - Results and artifacts will be stored under 'build/[design]/', and the final GDS can be viewed with: - - sc-show -design [design] - - The following modules implement helper functions for this process, all under the `scripts/sc` dir: - - * `flows/orflow.py`: Define the tasks which make up the flow (syn->floorplan->...) - * `targets/[platform]_orflow.py`: Parse config.mk files, and set default values in the Chip object. - ** `util/parse_*.py`: Helper functions to parse platform/design config.mk fragments. - * `tools/openroad/sc_apr.tcl`: Wrapper TCL script to handle task-specific pre/post-processing. - ''' - - parser = argparse.ArgumentParser(description='Run OR flow through SiliconCompiler.') - parser.add_argument('-DESIGN_CONFIG', required=True, help='Path to config.mk file configuring design') - args = vars(parser.parse_args()) - - # Parse values out of provided "config.mk" file - config = parse_config_mk.parse(args['DESIGN_CONFIG']) - # We'll use 'design' for finding the config.mk file in the target setup method, and - # there is inconsistency between whether that corresponds to 'DESIGN_NAME' or 'DESIGN_NICKNAME'. - # So, set design name based on file path. - design_name_match = re.search(f'\/[a-zA-Z0-9_]+\/config.mk', args['DESIGN_CONFIG']).group(0) - design = design_name_match[1:-len('/config.mk')] - platform = config['PLATFORM'] - - # Create a Chip object. - chip = siliconcompiler.Chip(design) - chip.set('option', 'scpath', scdir) - chip.set('option', 'jobname', f'{design}_{platform}') - - # Load PDK, flow, and libs. - if platform == 'nangate45': - chip.load_target('nangate45_orflow') - elif platform == 'sky130hd': - chip.load_target('sky130hd_orflow') - elif platform == 'sky130hs': - chip.load_target('sky130hs_orflow') - elif platform == 'asap7': - chip.load_target('asap7_orflow') - - # Set KLayout export options. - tool = 'klayout' - step = 'or_export' - if 'FILL_CONFIG' in chip.getkeys('tool', tool, 'env', step, '0'): - fill_cfg = chip.get('tool', tool, 'env', step, '0', 'FILL_CONFIG') - else: - fill_cfg = '' - if 'SEAL_GDS' in chip.getkeys('tool', tool, 'env', step, '0'): - seal_gds = chip.get('tool', tool, 'env', step, '0', 'SEAL_GDS') - else: - seal_gds = '' - gdsoas_in = ' '.join([os.path.abspath(gdsf) for gdsf in chip.get('tool', tool, 'env', step, '0', 'GDS_FILES').split()]) - out_file = os.path.join('outputs', f'{chip.get("design")}.{chip.get("tool", tool, "env", step, "0", "STREAM_SYSTEM_EXT")}') - techf = '../../klayout.lyt' # TODO: objects_dir is currently top-level build root dir. - layermap = chip.get('tool', tool, 'env', step, '0', 'GDS_LAYER_MAP') - klayout_options = ['-zz', - '-rd', f'design_name={chip.get("design")}', - '-rd', 'in_def=inputs/6_final.def', - '-rd', f'in_files="{gdsoas_in}"', - '-rd', f'config_file={fill_cfg}', - '-rd', f'seal_file={seal_gds}', - '-rd', f'out_file={out_file}', - '-rd', f'tech_file={techf}', - '-rd', f'layer_map={layermap}', - '-rm'] - chip.set('tool', tool, 'option', step, '0', klayout_options) - - # For testing - # TODO: put in run logic - #chip.write_manifest(f'{design}.json') - - # Setup input/output file paths for individual tasks. - WORKDIR_NAME = 'or_work' - flow = chip.get('option', 'flow') - for step in chip.getkeys('flowgraph', flow): - for index in chip.getkeys('flowgraph', flow, step): - tool = chip.get('flowgraph', flow, step, index, 'tool') - if not tool in ['openroad', 'yosys', 'klayout']: - continue - taskdir = chip._getworkdir(step=step) - chip.set('tool', tool, 'env', step, '0', 'RESULTS_DIR', os.path.join(taskdir, WORKDIR_NAME)) - # TODO: decide what to do about objects directory. - - # Build the design. - chip.run() - - # Print results summary. - chip.summary() - - # Symlink 'or_export/' task directory to 'export/' for sc-show viewing. - or_export_dir = chip._getworkdir(step = 'or_export')[:-2] - export_dir = or_export_dir.replace('or_export', 'export') - os.symlink(or_export_dir, export_dir) - -if __name__ == '__main__': - # Usage: python Makefile.py -DESIGN_CONFIG=designs/[platform]/[design]/config.mk - main() diff --git a/flow/scripts/sc/README.md b/flow/scripts/sc/README.md deleted file mode 100644 index 34f03a1337..0000000000 --- a/flow/scripts/sc/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# SiliconCompiler OpenROAD-flow-scripts build scripts - -This is a collection of build scripts for use with SiliconCompiler. They are intented to be called by a Python-based build script. - -To use them, install the `siliconcompiler` Python module and add this directory to your `$SCPATH` environment variable: - - pip3 install siliconcompiler - export SCPATH=[OpenROAD-flow-scripts]/flow/scripts/sc - -To run the OpenROAD reference flow using SiliconCompiler, navigate to your `OpenROAD-flow-scripts/flow` directory and run: - - python3 Makefile.py -DESIGN_CONFIG=./designs/[platform]/[design]/config.mk - -Once the build completes, you can find the results and build artifacts in `build/[design]/job0/`. Most files are sorted into directories named after the task associated with them. - -For example, you can find the post-synthesis netlist under `build/[design]/job0/or_yosys/0/outputs/1_synth.v`. Likewise, the final GDS result can be found under `build/[design]/job0/or_export/0/outputs/[design].gds` - -You can view a completed design in KLayout with the appropriate platform's layer map using the `sc-show` helper script: - - sc-show -design [design] - -# Example: GCD on nangate45 - -(First time only) install: - - pip3 install siliconcompiler - export SCPATH=[OpenROAD-flow-scripts]/flow/scripts/sc - -Build: - - cd [OpenROAD-flow-scripts]/flow - python3 Makefile.py -DESIGN_CONFIG=./designs/nangate45/gcd/config.mk - -View: - - sc-show -design gcd diff --git a/flow/scripts/sc/flows/orflow.py b/flow/scripts/sc/flows/orflow.py deleted file mode 100644 index 91383dd2a2..0000000000 --- a/flow/scripts/sc/flows/orflow.py +++ /dev/null @@ -1,121 +0,0 @@ -import os -import siliconcompiler -import re - -openroad_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) - -def make_docs(): - # TODO: Docs - - chip = siliconcompiler.Chip('') - chip.set('option', 'flow', 'orflow') - setup(chip) - - return chip - -########################################################################### -# Flowgraph Setup -############################################################################ -def setup(chip, flowname='orflow'): - ''' - Setup function for 'orflow' implementation of the OpenROAD-flow-scripts build process. - - Args: - chip (object): SC Chip object - - TODO: Fully support all environment variables used by the scripts - ''' - - # Set mandatory mode - chip.set('option', 'mode', 'asic') - - # Set showtools for sc-show - chip.set('option', 'showtool', 'def', 'klayout') - chip.set('option', 'showtool', 'gds', 'klayout') - - # Setup empty 'import' stage with a single-node OpenROAD task to run 'run_all.tcl' - # TODO: Use the 'import' step to parse config.mk file env vars. - # TODO: Split up individual TCL scripts into sc tasks? - flow = 'orflow' - - flow_groups = { - #'presynth': [ - # ('or_synth_hier_report', 'yosys'), - #], - 'synthesis': [ - ('or_synth', 'yosys'), # (synthesis is done via OpenROAD TCL that calls yosys) - ], - 'floorplan': [ - ('or_floorplan', 'openroad'), - ('or_io_placement_random', 'openroad'), - ('or_tdms_place', 'openroad'), - ('or_macro_place', 'openroad'), - ('or_tapcell', 'openroad'), - ('or_pdn', 'openroad'), - ], - 'place': [ - ('or_global_place_skip_io', 'openroad'), - ('or_io_placement', 'openroad'), - ('or_global_place', 'openroad'), - ('or_resize', 'openroad'), - ('or_detail_place', 'openroad'), - ], - 'cts': [ - ('or_cts', 'openroad'), - ('or_fillcell', 'openroad'), - ], - 'route': [ - ('or_global_route', 'openroad'), - ('or_detail_route', 'openroad'), - ], - 'finish': [ - ('or_final_report', 'openroad'), - # Like yosys, KLayout GDS-streaming script is run through an OpenROAD tcl script - ('or_export', 'klayout') - ] - } - #flowpipe = ['presynth', 'synthesis', 'floorplan', 'place', 'cts', 'route', 'finish'] - flowpipe = ['synthesis', 'floorplan', 'place', 'cts', 'route', 'finish'] - - # Additional dependencies defined here - extra_deps = { - 'or_detail_route': ['or_fillcell'], # reads 4_cts.odb - } - - chip.node(flow, 'import', 'nop') - last_step = 'import' - last_sdc_step = '' - for group in flowpipe: - for step, tool in flow_groups[group]: - chip.node(flow, step, tool) - - if last_step: - chip.edge(flow, last_step, step) - if last_sdc_step and last_sdc_step != last_step: - chip.edge(flow, last_sdc_step, step) - if step in extra_deps: - for dep in extra_deps[step]: - chip.edge(flow, dep, step) - - last_step = step - - if step == 'or_export': - chip.set('tool', tool, 'script', step, '0', 'def2stream.py') - chip.set('tool', tool, 'refdir', step, '0', os.path.join(openroad_dir, 'flow', 'util')) - else: - chip.set('tool', tool, 'script', step, '0', 'sc_apr.tcl') - chip.set('tool', tool, 'refdir', step, '0', os.path.join(openroad_dir, 'flow', 'scripts', 'sc', 'tools', 'openroad')) - - # Each step in a flow group relies on an SDC produced by (or copied - # into) the first step of the previous flow group. - last_sdc_step, _ = flow_groups[group][0] - - # Set default goal - for step in chip.getkeys('flowgraph', flow): - chip.set('flowgraph', flow, step, '0', 'goal', 'errors', 0) - -if __name__ == '__main__': - chip = siliconcompiler.Chip('') - setup(chip) - chip.set('option', 'flow', 'orflow') - chip.write_flowgraph('orflow.png') diff --git a/flow/scripts/sc/targets/asap7_orflow.py b/flow/scripts/sc/targets/asap7_orflow.py deleted file mode 100644 index b1f6964983..0000000000 --- a/flow/scripts/sc/targets/asap7_orflow.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -import siliconcompiler -import sys - -openroad_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) - -mydir = os.path.dirname(__file__) -scdir = os.path.join(mydir, '..') -sys.path.append(os.path.join(scdir, 'util')) -import parse_target_config - -def make_docs(): - # TODO: Docs - chip = siliconcompiler.Chip('') - -#################################################### -# PDK and Flow Setup -#################################################### -def setup(chip): - # Collect basic values. - design = chip.get('design') - platform = 'asap7' - - # Set the target name. - chip.set('option', 'target', 'asap7_orflow') - - # Load PDK, flow, and libs. - chip.load_flow('orflow') - chip.set('option', 'flow', 'orflow') - - # Set PDK/liberty values which cannot be inferred from platform config.mk - # (stackup, libtype, naming consistency, etc) - process = 'asap7' - stackup = '10M' - libtype = '7p5t' - group = 'asap7sc7p5t' - libname = f'{group}_rvt' - chip.set('option', 'pdk', process) - chip.set('asic', 'libarch', libtype) - chip.set('asic', 'logiclib', libname) - chip.set('asic', 'stackup', stackup) - chip.set('asic', 'delaymodel', 'nldm') - foundry = 'virtual' - wafersize = 300 - chip.set('pdk', process, 'foundry', foundry) - chip.set('pdk', process, 'stackup', stackup) - chip.set('pdk', process, 'wafersize', wafersize) - - # Load design and platform config values. - chip = parse_target_config.parse(chip, platform) - - # Set default environment variables for the OpenROAD flow (asap7 platform). - platform_dir = os.path.join(openroad_dir, 'flow', 'platforms', 'asap7') - job_dir = os.path.join(chip.get('option', 'builddir'), - chip.get('design'), - chip.get('option', 'jobname')) - env_vars = { - 'SCRIPTS_DIR': os.path.join(openroad_dir, 'flow', 'scripts'), - 'UTILS_DIR': os.path.join(openroad_dir, 'flow', 'util'), - 'PLATFORM_DIR': platform_dir, - - # Default values not set in platform config.mk - 'STREAM_SYSTEM_EXT': 'gds', - 'SYNTH_ARGS': '-flatten', - 'PLACE_PINS_ARGS': '', - 'GPL_ROUTABILITY_DRIVEN': '1', - 'GPL_TIMING_DRIVEN': '1', - 'GDS_LAYER_MAP': '', - 'ABC_AREA': '0', - 'NUM_CORES': f'{len(os.sched_getaffinity(0))}', - - # Project-specific - 'DESIGN_NAME': chip.get('design'), - 'VERILOG_FILES': ' '.join(chip.get('input', 'verilog')), - 'SDC_FILE': ' '.join(chip.get('input', 'sdc')), - - # Default location for generated files: job root directory. May be overridden later. - 'OBJECTS_DIR': os.path.abspath(job_dir), - 'REPORTS_DIR': os.path.abspath(job_dir), - 'RESULTS_DIR': os.path.abspath(job_dir), - 'SYNTH_STOP_MODULE_SCRIPT': os.path.join(job_dir, 'mark_hier_stop_modules.tcl'), - } - - # Set default environment variables for every step in the flow. - for step in chip.getkeys('flowgraph', 'orflow'): - index = '0' - for key, val in env_vars.items(): - tool = chip.get('flowgraph', 'orflow', step, index, 'tool') - chip.set('tool', tool, 'env', step, index, key, val) - - -######################### -if __name__ == "__main__": - chip = make_docs() diff --git a/flow/scripts/sc/targets/nangate45_orflow.py b/flow/scripts/sc/targets/nangate45_orflow.py deleted file mode 100644 index b00b574fc6..0000000000 --- a/flow/scripts/sc/targets/nangate45_orflow.py +++ /dev/null @@ -1,94 +0,0 @@ -import os -import siliconcompiler -import sys - -openroad_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) - -mydir = os.path.dirname(__file__) -scdir = os.path.join(mydir, '..') -sys.path.append(os.path.join(scdir, 'util')) -import parse_target_config - -def make_docs(): - # TODO: Docs - chip = siliconcompiler.Chip('') - setup(chip) - return chip - -#################################################### -# PDK and Flow Setup -#################################################### -def setup(chip): - # Collect basic values. - design = chip.get('design') - platform = 'nangate45' - - # Set the target name. - chip.set('option', 'target', 'nangate45_orflow') - - # Load flow graph and PDK/liberty manifest values. - chip.load_flow('orflow') - chip.set('option', 'flow', 'orflow') - - # Set PDK/liberty values which cannot be inferred from platform config.mk - # (stackup, libtype, naming consistency, etc) - process = 'freepdk45' - stackup = '10M' - libtype = '10t' - chip.set('option', 'pdk', process) - chip.set('asic', 'libarch', libtype) - chip.set('asic', 'logiclib', platform) - chip.set('asic', 'stackup', stackup) - chip.set('asic', 'delaymodel', 'nldm') - foundry = 'virtual' - wafersize = 300 - chip.set('pdk', process, 'foundry', foundry) - chip.set('pdk', process, 'stackup', stackup) - chip.set('pdk', process, 'wafersize', wafersize) - - # Load design and platform config values. - chip = parse_target_config.parse(chip, platform) - - # Set some default environment variables for the OpenROAD flow (nangate45 platform). - platform_dir = os.path.join(openroad_dir, 'flow', 'platforms', 'nangate45') - job_dir = os.path.join(chip.get('option', 'builddir'), - chip.get('design'), - chip.get('option', 'jobname')) - env_vars = { - 'SCRIPTS_DIR': os.path.join(openroad_dir, 'flow', 'scripts'), - 'UTILS_DIR': os.path.join(openroad_dir, 'flow', 'util'), - 'PLATFORM_DIR': platform_dir, - - # Default values not set in platform config.mk - 'STREAM_SYSTEM_EXT': 'gds', - 'SYNTH_ARGS': '-flatten', - 'PLACE_PINS_ARGS': '', - 'GPL_ROUTABILITY_DRIVEN': '1', - 'GPL_TIMING_DRIVEN': '1', - 'GDS_LAYER_MAP': '', - 'ABC_AREA': '0', - 'NUM_CORES': f'{len(os.sched_getaffinity(0))}', - - # Project-specific - 'DESIGN_NAME': chip.get('design'), - 'VERILOG_FILES': ' '.join(chip.get('input', 'verilog')), - 'SDC_FILE': ' '.join(chip.get('input', 'sdc')), - - # Default location for generated files: job root directory. May be overridden later. - 'OBJECTS_DIR': os.path.abspath(job_dir), - 'REPORTS_DIR': os.path.abspath(job_dir), - 'RESULTS_DIR': os.path.abspath(job_dir), - 'SYNTH_STOP_MODULE_SCRIPT': os.path.join(job_dir, 'mark_hier_stop_modules.tcl'), - } - - # Set default environment variables for every step in the flow. - for step in chip.getkeys('flowgraph', 'orflow'): - index = '0' - for key, val in env_vars.items(): - tool = chip.get('flowgraph', 'orflow', step, index, 'tool') - chip.set('tool', tool, 'env', step, index, key, val) - - -######################### -if __name__ == "__main__": - chip = make_docs() diff --git a/flow/scripts/sc/targets/sky130hd_orflow.py b/flow/scripts/sc/targets/sky130hd_orflow.py deleted file mode 100644 index 9aeab08422..0000000000 --- a/flow/scripts/sc/targets/sky130hd_orflow.py +++ /dev/null @@ -1,92 +0,0 @@ -import os -import siliconcompiler -import sys - -openroad_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) - -mydir = os.path.dirname(__file__) -scdir = os.path.join(mydir, '..') -sys.path.append(os.path.join(scdir, 'util')) -import parse_target_config - -def make_docs(): - # TODO: Docs - chip = siliconcompiler.Chip('') - setup(chip) - return chip - -#################################################### -# PDK and Flow Setup -#################################################### -def setup(chip): - # Collect basic values. - design = chip.get('design') - platform = 'sky130hd' - - # Set the target name. - chip.set('option', 'target', 'sky130hd_orflow') - - # Load PDK, flow, and libs. - chip.load_flow('orflow') - chip.set('option', 'flow', 'orflow') - - # Set PDK/liberty values which cannot be inferred from platform config.mk - # (stackup, libtype, naming consistency, etc) - process = 'skywater130' - stackup = '5M1LI' - libtype = 'unithd' - chip.set('option', 'pdk', process) - chip.set('asic', 'libarch', libtype) - chip.set('asic', 'logiclib', platform) - chip.set('asic', 'stackup', stackup) - chip.set('asic', 'delaymodel', 'nldm') - foundry = 'skywater' - wafersize = 300 - chip.set('pdk', process, 'foundry', foundry) - chip.set('pdk', process, 'stackup', stackup) - chip.set('pdk', process, 'wafersize', wafersize) - - # Load design and platform config values. - chip = parse_target_config.parse(chip, platform) - - # Set default environment variables for the OpenROAD flow (sky130hd platform). - platform_dir = os.path.join(openroad_dir, 'flow', 'platforms', 'sky130hd') - job_dir = os.path.join(chip.get('option', 'builddir'), - chip.get('design'), - chip.get('option', 'jobname')) - env_vars = { - # Defaults - 'SCRIPTS_DIR': os.path.join(openroad_dir, 'flow', 'scripts'), - 'UTILS_DIR': os.path.join(openroad_dir, 'flow', 'util'), - 'PLATFORM_DIR': platform_dir, - - # Default values not set in platform config.mk - 'STREAM_SYSTEM_EXT': 'gds', - 'SYNTH_ARGS': '-flatten', - 'PLACE_PINS_ARGS': '', - 'GPL_ROUTABILITY_DRIVEN': '1', - 'GPL_TIMING_DRIVEN': '1', - 'GDS_LAYER_MAP': '', - 'ABC_AREA': '0', - 'NUM_CORES': f'{len(os.sched_getaffinity(0))}', - - # Project-specific - 'DESIGN_NAME': chip.get('design'), - 'VERILOG_FILES': ' '.join(chip.get('input', 'verilog')), - 'SDC_FILE': ' '.join(chip.get('input', 'sdc')), - - # Default location for generated files: job root directory. May be overridden later. - 'OBJECTS_DIR': os.path.abspath(job_dir), - 'REPORTS_DIR': os.path.abspath(job_dir), - 'RESULTS_DIR': os.path.abspath(job_dir), - 'SYNTH_STOP_MODULE_SCRIPT': os.path.join(job_dir, 'mark_hier_stop_modules.tcl'), - } - for step in chip.getkeys('flowgraph', 'orflow'): - index = '0' - for key, val in env_vars.items(): - tool = chip.get('flowgraph', 'orflow', step, index, 'tool') - chip.set('tool', tool, 'env', step, index, key, val) - -######################### -if __name__ == "__main__": - chip = make_docs() diff --git a/flow/scripts/sc/targets/sky130hs_orflow.py b/flow/scripts/sc/targets/sky130hs_orflow.py deleted file mode 100644 index be96c0faa9..0000000000 --- a/flow/scripts/sc/targets/sky130hs_orflow.py +++ /dev/null @@ -1,93 +0,0 @@ -import os -import siliconcompiler -import sys - -openroad_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', '..', '..')) - -mydir = os.path.dirname(__file__) -scdir = os.path.join(mydir, '..') -sys.path.append(os.path.join(scdir, 'util')) -import parse_target_config - -def make_docs(): - # TODO: Docs - chip = siliconcompiler.Chip('') - setup(chip) - return chip - -#################################################### -# PDK and Flow Setup -#################################################### -def setup(chip): - # Collect basic values. - design = chip.get('design') - platform = 'sky130hs' - - # Set the target name. - chip.set('option', 'target', 'sky130hs_orflow') - - # Load PDK, flow, and libs. - chip.load_flow('orflow') - chip.set('option', 'flow', 'orflow') - - # Set PDK/liberty values which cannot be inferred from platform config.mk - # (stackup, libtype, naming consistency, etc) - process = 'skywater130' - stackup = '5M1LI' - libname = 'sky130hs' - libtype = 'unit' - chip.set('option', 'pdk', process) - chip.set('asic', 'libarch', libtype) - chip.set('asic', 'logiclib', libname) - chip.set('asic', 'stackup', stackup) - chip.set('asic', 'delaymodel', 'nldm') - foundry = 'skywater' - wafersize = 300 - chip.set('pdk', process, 'foundry', foundry) - chip.set('pdk', process, 'stackup', stackup) - chip.set('pdk', process, 'wafersize', wafersize) - - # Load design and platform config values. - chip = parse_target_config.parse(chip, platform) - - # Set default environment variables for the OpenROAD flow (sky130hs platform). - platform_dir = os.path.join(openroad_dir, 'flow', 'platforms', 'sky130hs') - job_dir = os.path.join(chip.get('option', 'builddir'), - chip.get('design'), - chip.get('option', 'jobname')) - env_vars = { - # Defaults - 'SCRIPTS_DIR': os.path.join(openroad_dir, 'flow', 'scripts'), - 'UTILS_DIR': os.path.join(openroad_dir, 'flow', 'util'), - 'PLATFORM_DIR': platform_dir, - - # Default values not set in platform config.mk - 'STREAM_SYSTEM_EXT': 'gds', - 'SYNTH_ARGS': '-flatten', - 'PLACE_PINS_ARGS': '', - 'GPL_ROUTABILITY_DRIVEN': '1', - 'GPL_TIMING_DRIVEN': '1', - 'GDS_LAYER_MAP': '', - 'ABC_AREA': '0', - 'NUM_CORES': f'{len(os.sched_getaffinity(0))}', - - # Project-specific - 'DESIGN_NAME': chip.get('design'), - 'VERILOG_FILES': ' '.join(chip.get('input', 'verilog')), - 'SDC_FILE': ' '.join(chip.get('input', 'sdc')), - - # Default location for generated files: job root directory. May be overridden later. - 'OBJECTS_DIR': os.path.abspath(job_dir), - 'REPORTS_DIR': os.path.abspath(job_dir), - 'RESULTS_DIR': os.path.abspath(job_dir), - 'SYNTH_STOP_MODULE_SCRIPT': os.path.join(job_dir, 'mark_hier_stop_modules.tcl'), - } - for step in chip.getkeys('flowgraph', 'orflow'): - index = '0' - for key, val in env_vars.items(): - tool = chip.get('flowgraph', 'orflow', step, index, 'tool') - chip.set('tool', tool, 'env', step, index, key, val) - -######################### -if __name__ == "__main__": - chip = make_docs() diff --git a/flow/scripts/sc/tools/openroad/sc_apr.tcl b/flow/scripts/sc/tools/openroad/sc_apr.tcl deleted file mode 100644 index f31074848c..0000000000 --- a/flow/scripts/sc/tools/openroad/sc_apr.tcl +++ /dev/null @@ -1,129 +0,0 @@ -######################################################################### -# "sc_apr.tcl" -# This is a wrapper script which sits between SiliconCompiler and the -# TCL scripts which get called by the OpenROAD-flow-scripts Makefile. -# -# This wrapper script simplifies the implementation of some pre- -# and post-processing steps, such as copying files between steps -# or modifying default liberty/tech/etc files. -# -# Although it is located in 'scripts/sc/tools/openroad', this script is -# also run through yosys during the synthesis step. -######################################################################### - -# Populate $sc_cfg value with the current sc manifest. -source sc_manifest.tcl - -# Set widely-used variables related to the current task. -set sc_step [dict get $sc_cfg arg step] -set sc_index [dict get $sc_cfg arg index] -set sc_tool [dict get $sc_cfg flowgraph orflow $sc_step $sc_index tool] -set sc_refdir [dict get $sc_cfg tool $sc_tool refdir $sc_step $sc_index] -set sc_design [dict get $sc_cfg design] - -set results_dir $::env(RESULTS_DIR) -set inputs [list] - -# Step-specific pre-processing step(s) -#if {$sc_step == "or_synth_hier_report"} { -if {$sc_step == "or_synth"} { - # Pre-synthesis: mark dont-use cells in liberty files, and merge them. - foreach f [split $::env(LIB_FILES)] { - exec $::env(UTILS_DIR)/preprocessLib.py -i $f -o "../../[file tail $f]-mod.lib" - } - set merge_cmd $::env(UTILS_DIR)/mergeLib.pl - lappend merge_cmd $::env(PLATFORM)_merged - foreach ff [regexp -all -inline {\S+} $::env(DONT_USE_LIBS)] { - lappend merge_cmd $ff - } - exec {*}$merge_cmd > ../../merged.lib -} elseif {$sc_step == "or_detail_route"} { - # Pre-export: Generate KLayout tech file with references to all LEFs in the design.. - set sc_process [dict get $sc_cfg option pdk] - set sc_stackup [dict get $sc_cfg pdk $sc_process stackup] - set base_lyt [dict get $sc_cfg pdk $sc_process layermap klayout def gds $sc_stackup] - set base_lyp [dict get $sc_cfg pdk $sc_process display klayout $sc_stackup] - set llib [dict get $sc_cfg asic logiclib] - set tlef [dict get $sc_cfg library $llib model layout lef $sc_stackup] - set replace_str "$tlef" - if {[info exists ::env(ADDITIONAL_LEFS)]} { - foreach f $::env(ADDITIONAL_LEFS) { - set replace_str "$replace_str$f" - } - } - - # Put KLayout tech files in job dir root to avoid modifying original tech file. - # klayout.lyt = base_lyt w/ lef-files tag replaced. - exec sed "s,.*,$replace_str,g" $base_lyt > ../../klayout.lyt - # klayout.lyp = base_lyp - file copy -force $base_lyp ../../klayout.lyp -} - -# Pre-run: copy from inputs/ into OpenROAD work directory -file mkdir $results_dir -foreach f [glob -directory inputs/ -tails -nocomplain *] { - file copy -force inputs/$f $results_dir - lappend inputs $f -} - -# Determine OR script name based on step name -if {$sc_step == "or_tdms_place" && [info exists ::env(MACRO_PLACEMENT)]} { - # Skip TDMS placement step if MACRO_PLACEMENT is set. - set script "" -} else { - # Strip or_ prefix to get the name of the script to run. - set script ../../../[string replace $sc_step 0 2 ""].tcl -} - -# Run the script for this step. -if {$script != ""} { - source $sc_refdir/$script -} - -# Post-run: copy anything from work dir that was not an input into outputs/ -foreach f [glob -directory $results_dir -tails -nocomplain *] { - if {[lsearch $inputs $f] == -1} { - file copy -force $results_dir/$f outputs/$f - } -} - -# Step-specific post-processing step(s) -if {$sc_step == "or_synth_hier_report"} { - # Copy inputs forward. - foreach f $inputs { - file copy -force "inputs/$f" "outputs/$f" - } -} elseif {$sc_step == "or_synth"} { - # Synthesis: Copy/rename RTL/SDC files - file copy -force outputs/1_1_yosys.v outputs/1_synth.v - file copy -force [lindex [dict get $sc_cfg input sdc] 0] outputs/1_synth.sdc -} elseif {$sc_step == "or_tdms_place" && [info exists ::env(MACRO_PLACEMENT)]} { - # TDMS Placement: copy .odb input if this step was skipped. - file copy -force inputs/2_2_floorplan_io.odb outputs/2_3_floorplan_tdms.odb -} elseif {$sc_step == "or_pdn"} { - # Last floorplan step: copy .odb file. - file copy -force outputs/2_6_floorplan_pdn.odb outputs/2_floorplan.odb -} elseif {$sc_step == "or_detail_place"} { - # Last placement step: copy .odb and .sdc files. - file copy -force outputs/3_5_place_dp.odb outputs/3_place.odb - foreach f $inputs { - if {[string last ".sdc" $f] == [expr [string length $f] - 4]} { - file copy -force "inputs/$f" outputs/3_place.sdc - } - } -} elseif {$sc_step == "or_cts"} { - # First CTS step: copy/rename SDC file for compatibility with following step. - file copy -force outputs/4_cts.sdc outputs/3_place.sdc -} elseif {$sc_step == "or_fillcell"} { - # Last CTS step: copy .odb file. - file copy -force outputs/4_2_cts_fillcell.odb outputs/4_cts.odb -} elseif {$sc_step == "or_detail_route"} { - # Last routing step: copy .odb and .sdc files. - file copy -force outputs/5_2_route.odb outputs/6_1_fill.odb - foreach f $inputs { - if {[string last ".sdc" $f] == [expr [string length $f] - 4]} { - file copy -force "inputs/$f" outputs/5_route.sdc - file copy -force "inputs/$f" outputs/6_1_fill.sdc - } - } -} diff --git a/flow/scripts/sc/util/parse_config_mk.py b/flow/scripts/sc/util/parse_config_mk.py deleted file mode 100644 index f36c958528..0000000000 --- a/flow/scripts/sc/util/parse_config_mk.py +++ /dev/null @@ -1,39 +0,0 @@ -import os -import subprocess -import tempfile - -def parse(path): - '''Parse env variables defined in a Makefile fragment''' - env_before = os.environ - - with tempfile.TemporaryDirectory() as tempdir: - makefile_path = os.path.join(tempdir, 'Makefile') - with open(makefile_path, 'w') as f: - print(f'include {path}', file=f) - print(f'all:', file=f) - print(f'\tprintenv', file=f) - - proc = subprocess.run(['make', '-s', '--no-print-directory', '-f', makefile_path], stdout=subprocess.PIPE) - output = proc.stdout.decode('utf-8') - - new_envvars = {} - assignments = output.split('\n') - for assignment in assignments: - if (not assignment) or (not '=' in assignment): - # skip blank lines - # only process lines with an assignment. (Ignore lines produced by e.g. `$(info [...])`) - continue - - var, val = assignment.split('=', 1) - if var in ('MAKEFLAGS', 'MFLAGS', 'MAKE_TERMERR', 'MAKE_TERMERR', 'MAKELEVEL'): - # skip envvars that Make adds - continue - - if var not in env_before: - new_envvars[var] = val - - return new_envvars - -if __name__ == '__main__': - vars = parse_config_mk('./designs/nangate45/bp_fe_top/config.mk') - print(vars) diff --git a/flow/scripts/sc/util/parse_target_config.py b/flow/scripts/sc/util/parse_target_config.py deleted file mode 100644 index e6592ce350..0000000000 --- a/flow/scripts/sc/util/parse_target_config.py +++ /dev/null @@ -1,190 +0,0 @@ -import glob -import os -import siliconcompiler -import sys - -import parse_config_mk - -mydir = os.path.dirname(__file__) -designs_root = os.path.abspath(os.path.join(mydir, '..', '..', '..', 'designs')) -platforms_root = os.path.abspath(os.path.join(mydir, '..', '..', '..', 'platforms')) - -def parse(chip, platform): - '''Parse platform and design env variables to prepare for building a design.''' - - design = chip.get('design') - design_cfg = os.path.join(designs_root, platform, design, 'config.mk') - platform_cfg = os.path.join(platforms_root, platform, 'config.mk') - - # Initial pass: Read design config. - config = parse_config_mk.parse(design_cfg) - # Substitutions for some values which may not be set. - repls = {} - # Set DESIGN_NICKNAME = DESIGN if not already set. - if not 'DESIGN_NICKNAME' in config: - repls['DESIGN_NICKNAME'] = config['DESIGN_NAME'] - # Set PLATFORM_DIR if not already set. - if not 'PLATFORM_DIR' in config: - repls['PLATFORM_DIR'] = os.path.join(platforms_root, config['PLATFORM']) - if not 'CORNER' in config: - if config['PLATFORM'] == 'asap7': - repls['CORNER'] = 'BC' - else: - repls['CORNER'] = 'typical' - - # Second pass: Re-read design config. - # Set replacement value in os.environ so that the Makefile parser uses it. - for k, v in repls.items(): - os.environ[k] = v - # Re-parse the design's config.mk - config = parse_config_mk.parse(design_cfg) - # Update 'config' dictionary with the substitutions used to generate it. - for k, v in repls.items(): - config[k] = v - - # Read in default platform configs - for k, v in config.items(): - os.environ[k] = v - os.environ['PLATFORM_DIR'] = os.path.join(platforms_root, platform) - # We'll calculate ABC_CLOCK_PERIOD_IN_PS later, and its shell call appears to mess with 'make -s' - os.environ['ABC_CLOCK_PERIOD_IN_PS'] = '0' - platform_config = parse_config_mk.parse(platform_cfg) - - # Convert to absolute paths where necessary. - if 'RCX_RULES' in platform_config: - platform_config['RCX_RULES'] = os.path.abspath(platform_config['RCX_RULES']) - for key, val in platform_config.items(): - if key.endswith('_DFF_LIB_FILE'): - platform_config[key] = os.path.abspath(val) - elif key.endswith('LIB_FILES'): - platform_config[key] = ' '.join([os.path.abspath(vf) for vf in val.split()]) - - # Final pass: Read design config with default platform values and previous replacements. - for k, v in config.items(): - os.environ.pop(k) - for k, v in repls.items(): - os.environ[k] = v - for k, v in platform_config.items(): - os.environ[k] = v - config = parse_config_mk.parse(design_cfg) - for k, v in repls.items(): - config[k] = v - - # Convert source files to absolute paths b/c sc commands run in a different build dir. - abs_sources = ['VERILOG_INCLUDE_DIRS', 'ADDITIONAL_LEFS', 'ADDITIONAL_LIBS', - 'LIB_FILES', 'ADDITIONAL_GDS', 'MACRO_PLACEMENT'] - for skey in abs_sources: - if skey in config.keys(): - src_list = [os.path.abspath(vf) for vf in config[skey].split()] - config[skey] = ' '.join(src_list) - # Special cases: Verilog sources and constraint file. - if 'SDC_FILE' in config.keys(): - sdc_in = os.path.abspath(config.pop('SDC_FILE')) - chip.set('input', 'sdc', sdc_in) - if 'VERILOG_FILES' in config.keys(): - v_in_list = [] - for vf in config.pop('VERILOG_FILES').split(): - if '*' in vf: - for gf in glob.glob(vf): - v_in_list.append(os.path.abspath(gf)) - else: - v_in_list.append(os.path.abspath(vf)) - chip.set('input', 'verilog', v_in_list) - if 'VERILOG_FILES_BLACKBOX' in config.keys(): - v_in_list = [] - for vf in config.pop('VERILOG_FILES_BLACKBOX').split(): - if '*' in vf: - for gf in glob.glob(vf): - v_in_list.append(os.path.abspath(gf)) - else: - v_in_list.append(os.path.abspath(vf)) - config['VERILOG_FILES_BLACKBOX'] = ' '.join(v_in_list) - - # Merge design and platform configs. If a value is in both, design has the correct value - # due to the way that the Makefile parser discards 'before' environment variables. - merged_config = config - for k, v in platform_config.items(): - if not k in merged_config: - merged_config[k] = v - - # Calculate clock period to use for yosys abc. Should be first clock entry in the constraints file. - ps_scale = 1 if platform == 'asap7' else 1000 - if (not 'ABC_CLOCK_PERIOD_IN_PS' in merged_config) and (os.path.isfile(chip.get('input', 'sdc')[0])): - with open(chip.get('input', 'sdc')[0], 'r') as sdcf: - for l in sdcf.readlines(): - if l.startswith('set clk_period '): - # "set clk_period x.yz \n": extract "x.yz" as float - p = float(l[len('set clk_period ') : ].strip()) - merged_config['ABC_CLOCK_PERIOD_IN_PS'] = f'{p * ps_scale}' - break - elif '-period ' in l: - # "create_clock ... -period x.yz ... \n": extract "x.yz" as float. - lv = l.split() - p = float(lv[lv.index('-period') + 1]) - merged_config['ABC_CLOCK_PERIOD_IN_PS'] = f'{p * ps_scale}' - break - - for step in chip.getkeys('flowgraph', 'orflow'): - index = '0' - tool = chip.get('flowgraph', 'orflow', step, index, 'tool') - # "Don't use" libraries get pre-processed. TODO: Currently placed in build dir root. - # Also, 'preprocessLib.py' is called from TCL; might be easier to do that pp here. - mod_lib_base = os.path.abspath(os.path.join(chip.get('option', 'builddir'), - config['DESIGN_NAME'], - chip.get('option', 'jobname'))) - libs = merged_config['LIB_FILES'].split() - dontuse_l = [] - for lf in libs: - dontuse_l.append(os.path.join(mod_lib_base, f'{os.path.split(lf)[1]}-mod.lib')) - merged_config['DONT_USE_LIBS'] = ' '.join(dontuse_l) - merged_config['DONT_USE_SC_LIB'] = os.path.join('..', '..', 'merged.lib') - - # Set config environment values to be set during sc flow. - for key, val in merged_config.items(): - chip.set('tool', tool, 'env', step, index, key, val.strip()) - # TODO: Update remaining PDK/lib values from environment variables in the Chip manifest. - schema_repls = { - 'PLACE_DENSITY': 'place_density', - 'CELL_PAD_IN_SITES_GLOBAL_PLACEMENT': 'pad_global_place', - 'CELL_PAD_IN_SITES_DETAIL_PLACEMENT': 'pad_detail_place', - 'MACRO_PLACE_HALO': 'macro_place_halo', - 'MACRO_PLACE_CHANNEL': 'macro_place_channel', - } - if key in schema_repls.keys(): - chip.set('tool', tool, 'var', step, index, schema_repls[key], val) - - # Debug: print final environment variables. - chip.logger.debug(merged_config) - - # TODO: Update remaining PDK/lib values from environment variables in the Chip manifest. - chip.set('option', 'mode', 'asic') - chip.set('design', merged_config['DESIGN_NAME']) - stackup = chip.get('asic', 'stackup') - libtype = chip.get('asic', 'libarch') - process = chip.get('option', 'pdk') - - # Read minimal PDK values into sc manifest. - chip.set('pdk', process, 'node', merged_config['PROCESS']) - for tool in ('openroad', 'klayout'): - chip.add('pdk', process, 'aprtech', tool, stackup, libtype, 'lef', - os.path.abspath(merged_config['TECH_LEF'])) - chip.set('pdk', process, 'layermap', 'klayout', 'def', 'gds', stackup, - os.path.abspath(merged_config['KLAYOUT_TECH_FILE'])) - # TODO: Assuming that .lyp file prefix matches .lyt - chip.set('pdk', process, 'display', 'klayout', stackup, - os.path.abspath(f'{merged_config["KLAYOUT_TECH_FILE"][:-1]}p')) - - # Read minimal liberty values into sc manifest. - plib_name = chip.get('asic', 'logiclib')[0] - platform_lib = siliconcompiler.Chip(plib_name) - platform_lib.set('asic', 'libarch', libtype) - platform_lib.set('asic', 'footprint', merged_config['PLACE_SITE'], 'symmetry', 'Y') - platform_lib.add('model', 'layout', 'lef', stackup, os.path.abspath(merged_config['SC_LEF'])) - for lf in merged_config['GDS_FILES'].split(): - platform_lib.add('model', 'layout', 'gds', stackup, os.path.abspath(lf)) - for lf in merged_config['LIB_FILES'].split(): - platform_lib.add('model', 'timing', 'nldm', merged_config['CORNER'], - os.path.abspath(lf)) - chip.import_library(platform_lib) - - return chip