Skip to content
Merged
Show file tree
Hide file tree
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 Jun 13, 2022
7021fe0
klayout.lyt: Fix minor quotation bug, add missing layer_map property
WRansohoff Jun 14, 2022
5364bc9
Add the correct LEF file to klayout.lyt in the example build script.
WRansohoff Jun 14, 2022
a8b3ed7
Add empty 'GDS_LAYER_MAP' property to orfs flow
WRansohoff Jun 14, 2022
ef4f685
Fix fragile relative file paths.
WRansohoff Jun 14, 2022
e59c13c
Add __init__ files fro libs/pdks directory
WRansohoff Jun 14, 2022
1395382
Add required 'refdir' parameter, and rename 'cts' step to avoid tool …
WRansohoff Jun 14, 2022
0220b4c
Update file paths and step names in example build script.
WRansohoff Jun 14, 2022
65f2991
Add config.mk parser utility
nmoroze Jun 14, 2022
932abe3
Add demo of single "Makefile.py" entry point
nmoroze Jun 14, 2022
76929eb
Add __pycache__ to gitignore
nmoroze Jun 14, 2022
e319d54
Pass env vars through instead of using schema
nmoroze Jun 14, 2022
5b471c7
Initial 'Makefile.py' nangate45 build flow. Works with gcd/jpeg/ibex …
WRansohoff Jun 15, 2022
7289b23
Move 'orflow.py' to platform-specific 'nangate45_orflow.py'
WRansohoff Jun 15, 2022
4f6631b
Add sky130hd targets. Might be time to create targets and merge the f…
WRansohoff Jun 15, 2022
8b2bda2
Generalize default variable substitution, add 'PLATFORM_DIR' alongsid…
WRansohoff Jun 15, 2022
718cfee
Move platform-specific logic into target scripts.
WRansohoff Jun 16, 2022
9d0a6b8
Minor re-ordering / cleanup
WRansohoff Jun 16, 2022
be9ed5d
Move pre-processing steps until after 'import' task
WRansohoff Jun 16, 2022
96f7377
Process additional lef/lib/gds configs, skip tdms_place step if macro…
WRansohoff Jun 16, 2022
8153bea
Map step results into inputs/outputs directories
nmoroze Jun 17, 2022
669a390
Comment sc_apr.tcl
nmoroze Jun 17, 2022
c7d99f4
Move per-task pre/post-processing into TCL wrapper, instead of Python…
WRansohoff Jun 20, 2022
fa3c8a7
Update build scripts to populate and set default macro spacing
WRansohoff Jun 21, 2022
eecd9b0
Fixes for sky130hd AES/Chameleon examples, fixes and workaround for n…
WRansohoff Jun 22, 2022
57df58f
Generalize the nangate45 black_parrot workaround
WRansohoff Jun 22, 2022
ecb9e57
Use applicable schema values in platform target scripts, and remove c…
WRansohoff Jun 23, 2022
70b0c9e
Update flow to use yosys/klayout tools, move and comment sc_apr, remo…
WRansohoff Jun 24, 2022
3c3c576
Revert unnecessary changes to klayout.tcl
WRansohoff Jun 24, 2022
c184b5b
Move ABC_CLOCK_PERIOD_IN_PS logic to finally fix the black_parrot exa…
WRansohoff Jun 24, 2022
46d50ed
Add asap7 target, bug fixes.
WRansohoff Jun 27, 2022
98c2f8e
Add sky130hs flow, and set NUM_CORES based on system specs
WRansohoff Jun 27, 2022
c2eb3f8
Use full filename when copying in sc_apr.tcl
WRansohoff Jun 29, 2022
0b5b06b
Add pdk/lib files for sky130hs target
WRansohoff Jun 29, 2022
38df4f0
Source platform-specific configurations from their 'config.mk' files,…
WRansohoff Jul 8, 2022
1ed1640
Update top-level comments and README
WRansohoff Jul 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,6 @@ core
core.*

*~

# Python bytecode
__pycache__/
129 changes: 129 additions & 0 deletions flow/Makefile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import argparse
Copy link
Member

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

Copy link
Contributor Author

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.

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()
36 changes: 36 additions & 0 deletions flow/scripts/sc/README.md
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
121 changes: 121 additions & 0 deletions flow/scripts/sc/flows/orflow.py
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')
94 changes: 94 additions & 0 deletions flow/scripts/sc/targets/asap7_orflow.py
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()
Loading