-
Notifications
You must be signed in to change notification settings - Fork 391
Leveraging SiliconCompiler to run OpenROAD-flow-scripts builds #501
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
maliberty
merged 36 commits into
The-OpenROAD-Project:master
from
siliconcompiler:master
Jul 11, 2022
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
83924ed
WIP sc / orfs build scripts. Currently runs up to 'final_report', deb…
WRansohoff 7021fe0
klayout.lyt: Fix minor quotation bug, add missing layer_map property
WRansohoff 5364bc9
Add the correct LEF file to klayout.lyt in the example build script.
WRansohoff a8b3ed7
Add empty 'GDS_LAYER_MAP' property to orfs flow
WRansohoff ef4f685
Fix fragile relative file paths.
WRansohoff e59c13c
Add __init__ files fro libs/pdks directory
WRansohoff 1395382
Add required 'refdir' parameter, and rename 'cts' step to avoid tool …
WRansohoff 0220b4c
Update file paths and step names in example build script.
WRansohoff 65f2991
Add config.mk parser utility
nmoroze 932abe3
Add demo of single "Makefile.py" entry point
nmoroze 76929eb
Add __pycache__ to gitignore
nmoroze e319d54
Pass env vars through instead of using schema
nmoroze 5b471c7
Initial 'Makefile.py' nangate45 build flow. Works with gcd/jpeg/ibex …
WRansohoff 7289b23
Move 'orflow.py' to platform-specific 'nangate45_orflow.py'
WRansohoff 4f6631b
Add sky130hd targets. Might be time to create targets and merge the f…
WRansohoff 8b2bda2
Generalize default variable substitution, add 'PLATFORM_DIR' alongsid…
WRansohoff 718cfee
Move platform-specific logic into target scripts.
WRansohoff 9d0a6b8
Minor re-ordering / cleanup
WRansohoff be9ed5d
Move pre-processing steps until after 'import' task
WRansohoff 96f7377
Process additional lef/lib/gds configs, skip tdms_place step if macro…
WRansohoff 8153bea
Map step results into inputs/outputs directories
nmoroze 669a390
Comment sc_apr.tcl
nmoroze c7d99f4
Move per-task pre/post-processing into TCL wrapper, instead of Python…
WRansohoff fa3c8a7
Update build scripts to populate and set default macro spacing
WRansohoff eecd9b0
Fixes for sky130hd AES/Chameleon examples, fixes and workaround for n…
WRansohoff 57df58f
Generalize the nangate45 black_parrot workaround
WRansohoff ecb9e57
Use applicable schema values in platform target scripts, and remove c…
WRansohoff 70b0c9e
Update flow to use yosys/klayout tools, move and comment sc_apr, remo…
WRansohoff 3c3c576
Revert unnecessary changes to klayout.tcl
WRansohoff c184b5b
Move ABC_CLOCK_PERIOD_IN_PS logic to finally fix the black_parrot exa…
WRansohoff 46d50ed
Add asap7 target, bug fixes.
WRansohoff 98c2f8e
Add sky130hs flow, and set NUM_CORES based on system specs
WRansohoff c2eb3f8
Use full filename when copying in sc_apr.tcl
WRansohoff 0b5b06b
Add pdk/lib files for sky130hs target
WRansohoff 38df4f0
Source platform-specific configurations from their 'config.mk' files,…
WRansohoff 1ed1640
Update top-level comments and README
WRansohoff File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,3 +69,6 @@ core | |
| core.* | ||
|
|
||
| *~ | ||
|
|
||
| # Python bytecode | ||
| __pycache__/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,129 @@ | ||
| 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) | ||
|
|
||
| # 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([chip.get('tool', tool, 'env', step, '0', 'GDS_FILES')]) | ||
| 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() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # 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.mki | ||
|
|
||
| View: | ||
|
|
||
| sc-show -design gcd |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| 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('<topmodule>') | ||
| 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('<design>') | ||
| setup(chip) | ||
| chip.set('option', 'flow', 'orflow') | ||
| chip.write_flowgraph('orflow.png') |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| 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('<design>') | ||
|
|
||
| #################################################### | ||
| # 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() |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some explanatory comments would be helpful to make clear how this is intended to be used. Perhaps a fuller README
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, thanks. I'll add some comments to explain the argument parsing and expand the README in flow/scripts/sc.