mirror of
https://github.com/The-OpenROAD-Project/OpenLane.git
synced 2026-05-29 00:23:55 +08:00
More Usability Tweaks (#984)
+ `-verbose` flag added with multiple levels, replacing `-disable_output` (which is now the default behavior) + New command `puts_verbose` added, to be used for extra pieces of information + ./flow.tcl header now includes version, copyright and licensing information + Added `-last_run` flag allowing you to quickly resume the last run (useful with -interactive) + Added `open_in_klayout` command that lets you open the CURRENT_DEF in Klayout ~ `env.py issue-survey` now detects whether it's running inside the container and warns accordingly ~ RUN_KLAYOUT, RUN_KLAYOUT_DRC, RUN_MAGIC_DRC, RUN_LVS now only control noninteractive flows ~ Full git hash added to containers ~ Various Documentation Updates ~ Changed verbosity of various output messages - Removed `-disable_output` (now the default behavior) - Removed OpenLane ASCII art - Removed various "chatty" messages, including things succeeding (shut up unless something fails)
This commit is contained in:
3
.flake8
3
.flake8
@@ -4,4 +4,5 @@ exclude =
|
||||
.git,
|
||||
__pycache__,
|
||||
scripts/klayout,
|
||||
docker/tar
|
||||
docker/tar,
|
||||
install/
|
||||
@@ -1,19 +1,31 @@
|
||||
# How to Contribute
|
||||
|
||||
We'd love to accept your patches and contributions to this project. There are
|
||||
just a few small guidelines you need to follow.
|
||||
|
||||
## Submission and Testing Process
|
||||
# Branching
|
||||
For various reasons, it's recommended to call working branches, even in your forks, something else other than `master` or `main`, as those two branch names do have some special behavior associated with them.
|
||||
|
||||
- Submit a Pull Request to the [master](https://github.com/The-OpenROAD-Project/openlane/tree/master) branch only. Check [Code Reviews](#code_reviews) for more details.
|
||||
- Our CI that would test your PR once submitted, yet it would be nice for you to run a couple of tests from your end to shorten the cycle of reviews. For that purpose, you can use:
|
||||
- `make fastest_test_set`: to run the same test set that the basic CI uses, which will be used to evaluate your Pull Request.
|
||||
- [This](./regression_results/README.md) for custom test sets. (check the `-b` flag).
|
||||
- `make test`: tests the flow against one design `$TEST_DESIGN`. The default is `spm`.
|
||||
# Testing and Code Standards
|
||||
Before you submit your changes, it's prudent to perform some kind of smoke test. `make test` tests a simple spm design to ensure nothing has gone horribly wrong.
|
||||
|
||||
## Code reviews
|
||||
You will also need to ensure that your Python code passes linting with two tools: `black` and `flake8`. The commands are simply `black .` and `flake8 .`. Please fix all warnings.
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
Try to write all major code in Python. Writing some Tcl is usually a necessity because this project's backbone is unfortunately written in Tcl, but just keep the Tcl to as close to a Python shim as possible.
|
||||
|
||||
Please do not write new shell scripts.
|
||||
|
||||
# Submissions
|
||||
Make your changes and then submit them as a pull requests to the `master` branch.
|
||||
|
||||
Consult [GitHub Help](https://help.github.com/articles/about-pull-requests/) for more information on using pull requests.
|
||||
|
||||
## The Approval Process
|
||||
For a PR to be merged, there are two requirements:
|
||||
|
||||
- There are two automated checks, one for linting and the other for functionality. Both must pass.
|
||||
- An OpenLane team member must inspect and approve the PR.
|
||||
|
||||
# Licensing and Copyright
|
||||
Please add you (or your employer's) copyright headers to any files to which you have made major edits.
|
||||
|
||||
Please note all code contributions must have the same license as OpenLane, i.e., the Apache License, version 2.0.
|
||||
2
Makefile
2
Makefile
@@ -133,7 +133,7 @@ issue_regression_all:
|
||||
.PHONY: test
|
||||
test:
|
||||
cd $(OPENLANE_DIR) && \
|
||||
$(ENV_COMMAND) sh -c "./flow.tcl -design $(TEST_DESIGN) -tag openlane_test -disable_output -overwrite"
|
||||
$(ENV_COMMAND) sh -c "./flow.tcl -design $(TEST_DESIGN) -tag openlane_test -overwrite"
|
||||
@[ -f $(OPENLANE_DIR)/designs/$(TEST_DESIGN)/runs/openlane_test/results/finishing/$(TEST_DESIGN).gds ] && \
|
||||
echo "Basic test passed" || \
|
||||
echo "Basic test failed"
|
||||
|
||||
14
README.md
14
README.md
@@ -33,15 +33,17 @@ This documentation is also available at [ReadTheDocs](https://openlane.readthedo
|
||||
# Prerequisites
|
||||
At a minimum:
|
||||
|
||||
- Docker 19.03.12+
|
||||
- GNU Make
|
||||
- Python 3.6+ with PIP
|
||||
- Click, Pyyaml: `python3 -m pip install pyyaml click>=7`
|
||||
- Python 3.6 with PIP
|
||||
- Click 7.0+, Pyyaml: `python3 -m pip install pyyaml click>=7`
|
||||
|
||||
For building Sky130 PDK you also need:
|
||||
- Git 2.35+: `git --version`
|
||||
To build the Sky130 PDK you also need:
|
||||
- Git 2.35+
|
||||
|
||||
## Containerless Install
|
||||
## Using the Docker Image
|
||||
- Docker 19.03.12+
|
||||
|
||||
## Containerless/Local Installations
|
||||
Please see [here](./docs/source/local_installs.md).
|
||||
|
||||
# Setting Up OpenLane
|
||||
|
||||
@@ -88,7 +88,8 @@ FORCE:
|
||||
openlane: merge
|
||||
merge: run_base_image ./tar/build ./tar/openlane ../dependencies/tool_metadata.yml
|
||||
cat ../dependencies/tool_metadata.yml > ./tar/tool_metadata.yml
|
||||
printf "$(shell git rev-parse --short=7 HEAD)" > ./tar/git_version
|
||||
printf "$(shell git rev-parse HEAD)" > ./tar/git_version
|
||||
printf "$(shell git rev-parse --short=7 HEAD)" > ./tar/git_version_short
|
||||
mkdir -p logs/tar
|
||||
$(BUILD_COMMAND)\
|
||||
--build-arg CACHE_INVALIDATOR=$(shell date +%s)\
|
||||
|
||||
@@ -39,6 +39,7 @@ ADD ./tool_metadata.yml /tool_metadata.yml
|
||||
|
||||
## Copy Version
|
||||
ADD ./git_version /git_version
|
||||
ADD ./git_version_short /git_version_short
|
||||
|
||||
## Artifacts
|
||||
COPY ./build /build
|
||||
|
||||
3
docker/run_base/.gitignore
vendored
3
docker/run_base/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
/*.tar.gz
|
||||
/*.yml
|
||||
/*.txt
|
||||
/git_version
|
||||
/git_version
|
||||
/git_version_short
|
||||
@@ -2,6 +2,6 @@
|
||||
# Source global definitions
|
||||
alias ll='ls -lAFh';
|
||||
|
||||
export OL_GIT_VERSION=$(cat /git_version);
|
||||
export OL_GIT_VERSION=$(cat /git_version_short);
|
||||
|
||||
export PS1="\[\033[1;31m\]OpenLane Container ($OL_GIT_VERSION)\[\033[0m\]:\[\033[4;32m\]\w\[\033[0m\]$ ";
|
||||
1
docker/tar/.gitignore
vendored
1
docker/tar/.gitignore
vendored
@@ -2,5 +2,6 @@
|
||||
/*.yml
|
||||
/*.txt
|
||||
/git_version
|
||||
/git_version_short
|
||||
/build
|
||||
/openlane
|
||||
@@ -39,7 +39,8 @@ Most of the following commands' implementation exists in this [file][0]
|
||||
| | `[-src <verilog_source>]` | Sets the verilog source code file(s) in case of using `-init_design_config`. The default is that the source code files are under <code>design_path/src/</code>, where the design path is the one passed to <code>-design</code>. <br> Optional flag. |
|
||||
| | `[-config_tag <config_tag>]` | Specifies the design's configuration file for running the flow. <br> For example, to run the flow using <code>designs/spm/config2.tcl</code> <br> Use run <code>./flow.tcl -design spm -config_tag config2.tcl</code> <br> By default <code>config.tcl</code> is used. <br> Optional flag. |
|
||||
| | `[-config_file <config_file>]` | Specifies the design's configuration file for running the flow. <br> For example, to run the flow using <code>/spm/config2.tcl</code> <br> Use run <code>./flow.tcl -design /spm -config_file /spm/config2.tcl</code> <br> By default <code>config.tcl</code> is used. <br> Optional flag. |
|
||||
| | `[-disable_output]` | Disables outputing to the terminal. <br> Optional flag.|
|
||||
| | `[-verbose <level>]` | Sets a verbose output level. 0 disables verbose information and tool outputs. 1 enables verbose information but disables tool outputs. 2 and greater outputs everything. More verbose levels may be added over time, so if you want absolutely all output, set it to something like 99.|
|
||||
| | `[-disable_output]` | **Removed: Default Behavior** Disables outputing to the terminal. <br> Optional flag.|
|
||||
| `padframe_gen` | | Generates the padframe for a design based on the files and configurations under `padframe_folder`. Also, it generates a padframe.cfg if it's not present. The padframe.cfg is a file that describes the order of the pads and their relative location on the chip.|
|
||||
| | `-folder <padframe_folder>` | specifies the `<padframe_folder>` for the padframe generator. The folder should contain the following: `./mag/<mag files>`, `./verilog/<verilog files>`, and optionally `./mag/padframe.cfg`|
|
||||
| `save_views` | | Saves the views of a given `run_tag` into the specifies `path`(s).|
|
||||
@@ -281,6 +282,9 @@ Most of the following commands' implementation exists in this [file][17]
|
||||
| | `[-layout2 <gds_file>]` | The input GDS file, the default is the klayout generated GDS-II under `<run_path>/results/klayout/<design_name>.gds`. |
|
||||
| | `[-output_gds <gds_file>]` | The output GDS file with the xor result, the default under `<run_path>/results/klayout/<design_name>.xor.gds`. |
|
||||
| | `[-output_xml <xml_file>]` | The output XML file with the xor result, the default under `<run_path>/results/klayout/<design_name>.xor.xml`. |
|
||||
| `open_in_klayout` | | Opens a design in the Klayout GUI with MERGED_LEF for the cell/macro definitions. Useful as it works around Klayout's LEF import peculiarities. |
|
||||
| | `[-layout <def_file>]` | The input DEF file, the default is `::env(CURRENT_DEF)`. |
|
||||
|
||||
## LVS Commands
|
||||
|
||||
Most of the following commands' implementation exists in this [file][5]
|
||||
|
||||
@@ -10,7 +10,7 @@ When working with a proprietary PDK, also inspect the folder and ensure no propr
|
||||
If you're using OpenLane 2021.12.17_05.07.41 or later, chances are, `or_issue.py` was automatically run for you if OpenROAD failed. You'll find a message in the log that says something along the lines of: `Reproducible packaged: Please tarball and upload <PATH> if you're going to submit an issue.` The path will be under the current run_path, i.e., ./designs/<design>/runs/<run_tag>/openroad_issue_reproducible. You can then tarball/zip and upload that file.
|
||||
|
||||
## Running or_issue.py manually
|
||||
You'll have to extract three key elements from the logs:
|
||||
You'll have to extract three key elements from the **verbose** logs (i.e. ./flow.tcl must be run with `-verbose`):
|
||||
* The Script Where The Failure Occurred -> script
|
||||
* The Final Layout Before The Failure Occurred -> input
|
||||
* The Run Path -> run_path
|
||||
|
||||
38
env.py
38
env.py
@@ -129,20 +129,32 @@ def issue_survey():
|
||||
"""
|
||||
% (os_info.container_info.engine, container_version, container_message)
|
||||
)
|
||||
elif os.path.exists(
|
||||
"/git_version"
|
||||
): # i.e. if running inside the OpenLane container
|
||||
print("Alert: Running in container.", file=alerts)
|
||||
final_report = (
|
||||
textwrap.dedent(
|
||||
"""\
|
||||
WARNING: issue-survey appears to be running inside the OpenLane
|
||||
container.
|
||||
|
||||
This makes it difficult to rule out issues with your
|
||||
environment.
|
||||
|
||||
Unless instructed specifically to do so, please run this command
|
||||
outside the OpenLane container.
|
||||
---\n
|
||||
"""
|
||||
)
|
||||
+ final_report
|
||||
)
|
||||
else:
|
||||
try:
|
||||
subprocess.check_output(
|
||||
["systemd-detect-virt", "-c"]
|
||||
) # Check if running inside container
|
||||
if not os.path.exists("/openlane"):
|
||||
raise Exception()
|
||||
alert = "Alert: Running in container."
|
||||
final_report += "%s\n" % alert
|
||||
print(alert, file=alerts)
|
||||
except Exception:
|
||||
alert = "Critical Alert: No Docker or Docker-compatible container engine was found: {e}."
|
||||
final_report += "%s\n" % alert
|
||||
print(alert, file=alerts)
|
||||
alert = (
|
||||
"Critical Alert: No Docker or Docker-compatible container engine was found."
|
||||
)
|
||||
final_report += "%s\n" % alert
|
||||
print(alert, file=alerts)
|
||||
|
||||
if python_ok:
|
||||
from dependencies.get_tag import get_tag
|
||||
|
||||
50
flow.tcl
50
flow.tcl
@@ -89,8 +89,12 @@ proc run_drc_step {{ drc_enabled 1 }} {
|
||||
set ::env(CURRENT_DEF) $::env(DRC_CURRENT_DEF)
|
||||
}
|
||||
if { $drc_enabled } {
|
||||
run_magic_drc
|
||||
run_klayout_drc
|
||||
if { $::env(RUN_MAGIC_DRC) } {
|
||||
run_magic_drc
|
||||
}
|
||||
if {$::env(RUN_KLAYOUT_DRC)} {
|
||||
run_klayout_drc
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +116,15 @@ proc run_eco_step {args} {
|
||||
}
|
||||
}
|
||||
|
||||
proc run_klayout_step {args} {
|
||||
if {$::env(RUN_KLAYOUT)} {
|
||||
run_klayout
|
||||
}
|
||||
if {$::env(RUN_KLAYOUT_XOR)} {
|
||||
run_klayout_gds_xor
|
||||
}
|
||||
}
|
||||
|
||||
proc save_final_views {args} {
|
||||
set options {
|
||||
{-save_path optional}
|
||||
@@ -177,8 +190,8 @@ proc run_non_interactive_mode {args} {
|
||||
# signal trap SIGINT save_state;
|
||||
|
||||
if { [info exists flags_map(-gui)] } {
|
||||
or_gui
|
||||
return
|
||||
or_gui
|
||||
return
|
||||
}
|
||||
if { [info exists arg_values(-override_env)] } {
|
||||
set env_overrides [split $arg_values(-override_env) ',']
|
||||
@@ -204,8 +217,7 @@ proc run_non_interactive_mode {args} {
|
||||
"eco" {run_eco_step ""} \
|
||||
"diode_insertion" {run_diode_insertion_2_5_step ""} \
|
||||
"gds_magic" {run_magic ""} \
|
||||
"gds_drc_klayout" {run_klayout ""} \
|
||||
"gds_xor_klayout" {run_klayout_gds_xor ""} \
|
||||
"gds_klayout" {run_klayout_step ""} \
|
||||
"lvs" "run_lvs_step $LVS_ENABLED" \
|
||||
"drc" "run_drc_step $DRC_ENABLED" \
|
||||
"antenna_check" "run_antenna_check_step $ANTENNACHECK_ENABLED" \
|
||||
@@ -388,30 +400,20 @@ set flags {-interactive -it -drc -lvs -synth_explore -run_hooks}
|
||||
|
||||
parse_key_args "flow.tcl" argv arg_values $options flags_map $flags -no_consume
|
||||
|
||||
puts_info {
|
||||
___ ____ ___ ____ _ ____ ____ ___
|
||||
/ \ | \ / _]| \ | | / || \ / _]
|
||||
| | | o ) [_ | _ || | | o || _ | / [_
|
||||
| O | | _/ _]| | || |___ | || | || _]
|
||||
| | | | | [_ | | || || _ || | || [_
|
||||
\___/ |__| |_____||__|__||_____||__|__||__|__||_____|
|
||||
|
||||
}
|
||||
|
||||
if {[catch {exec cat $::env(OPENLANE_ROOT)/installed_version} ::env(OPENLANE_VERSION)]} {
|
||||
if {[catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git describe --tags} ::env(OPENLANE_VERSION)]} {
|
||||
# if no tags yet
|
||||
if {[catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git log --pretty=format:'%h' -n 1} ::env(OPENLANE_VERSION)]} {
|
||||
if {[catch {exec cat $::env(OPENLANE_ROOT)/install/installed_version} ::env(OPENLANE_VERSION)]} {
|
||||
if {[catch {exec git --git-dir $::env(OPENLANE_ROOT)/.git rev-parse HEAD} ::env(OPENLANE_VERSION)]} {
|
||||
if {[catch {exec cat /git_version} ::env(OPENLANE_VERSION)]} {
|
||||
set ::env(OPENLANE_VERSION) "N/A"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
puts_info "Version: $::env(OPENLANE_VERSION)"
|
||||
puts "OpenLane $::env(OPENLANE_VERSION)"
|
||||
puts "All rights reserved. (c) 2020-2022 Efabless Corporation and contributors."
|
||||
puts "Available under the Apache License, version 2.0. See the LICENSE file for more details."
|
||||
puts ""
|
||||
|
||||
if { [info exists flags_map(-interactive)] || [info exists flags_map(-it)] } {
|
||||
puts_info "Running interactively"
|
||||
puts_info "Note, that post_run_hooks.tcl will not be sourced automatically"
|
||||
if { [info exists arg_values(-file)] } {
|
||||
run_file [file normalize $arg_values(-file)] {*}$argv
|
||||
} else {
|
||||
@@ -425,7 +427,5 @@ if { [info exists flags_map(-interactive)] || [info exists flags_map(-it)] } {
|
||||
prep {*}$argv
|
||||
run_synth_exploration
|
||||
} else {
|
||||
puts_info "Running non-interactively"
|
||||
|
||||
run_non_interactive_mode {*}$argv
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# Variables information
|
||||
|
||||
# Datapoint Definitions
|
||||
***NOTE:** The value `-1`, if not meaningful, indicates that the report/log from which the information is extracted wasn't found (the stage responsible for it was skipped or failed).
|
||||
|
||||
## Default Printed Information Variables
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2020 Efabless Corporation
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -249,7 +249,7 @@ def cli(
|
||||
"-overwrite",
|
||||
"-no_save",
|
||||
"-run_hooks",
|
||||
] + ([] if show_log_output else ["-disable_output"])
|
||||
] + (["-verbose", "99"] if show_log_output else [])
|
||||
skip_rm_from_rems = False
|
||||
try:
|
||||
if show_log_output:
|
||||
|
||||
66
scripts/klayout/open_design.py
Normal file
66
scripts/klayout/open_design.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
# Copyright 2021 The American University in Cairo and the Cloud V Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pya
|
||||
|
||||
app = pya.Application.instance()
|
||||
|
||||
try:
|
||||
win = app.main_window()
|
||||
|
||||
layout = os.getenv("LAYOUT")
|
||||
if layout is None:
|
||||
raise Exception("LAYOUT environment variable is not set.")
|
||||
|
||||
pdk_root = os.getenv("PDK_ROOT")
|
||||
if pdk_root is None:
|
||||
raise Exception("PDK_ROOT environment variable is not set.")
|
||||
|
||||
pdk_name = os.getenv("PDK")
|
||||
if pdk_name is None:
|
||||
raise Exception("PDK environment variable is not set.")
|
||||
|
||||
# Relative to the layout path, ':' delimited. If not provided, all LEFs
|
||||
# in the same folder as the layout will be loaded.
|
||||
explicitly_listed_lefs_raw = os.getenv("EXPLICITLY_LISTED_LEFS")
|
||||
|
||||
use_explicitly_listed_lefs = explicitly_listed_lefs_raw is not None
|
||||
|
||||
tech_file_path = os.path.join(
|
||||
pdk_root, pdk_name, "libs.tech", "klayout", f"{pdk_name}.lyt"
|
||||
)
|
||||
|
||||
tech = pya.Technology()
|
||||
tech.load(tech_file_path)
|
||||
|
||||
layout_options = tech.load_layout_options
|
||||
|
||||
layout_options.keep_other_cells = True
|
||||
|
||||
layout_options = tech.load_layout_options
|
||||
layout_options.lefdef_config.macro_resolution_mode = 1
|
||||
|
||||
if use_explicitly_listed_lefs:
|
||||
explicitly_listed_lefs = explicitly_listed_lefs_raw.split(":")
|
||||
layout_options.lefdef_config.read_lef_with_def = False
|
||||
layout_options.lefdef_config.lef_files = explicitly_listed_lefs
|
||||
|
||||
cell_view = win.load_layout(layout, layout_options, 0)
|
||||
|
||||
except Exception as e:
|
||||
print(e, file=sys.stderr)
|
||||
app.exit(-1)
|
||||
61
scripts/klayout/open_design_cmd.py
Normal file
61
scripts/klayout/open_design_cmd.py
Normal file
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import click
|
||||
import subprocess
|
||||
|
||||
|
||||
@click.command("open_design")
|
||||
@click.option(
|
||||
"-l",
|
||||
"--input-lef",
|
||||
default=os.getenv("MERGED_LEF"),
|
||||
help="Input merged technology/cells LEF file",
|
||||
)
|
||||
@click.option(
|
||||
"-P",
|
||||
"--pdk-root",
|
||||
default=os.getenv("PDK_ROOT"),
|
||||
required=not os.getenv("PDK_ROOT"),
|
||||
help="PDK Root",
|
||||
)
|
||||
@click.option("-p", "--pdk", default="sky130A", help="Name of the PDK")
|
||||
@click.argument("input_def")
|
||||
def open_design(input_lef, pdk_root, pdk, input_def):
|
||||
"""
|
||||
Opens a design in Klayout.
|
||||
"""
|
||||
dir = os.path.dirname(__file__)
|
||||
klayout_script_path = os.path.join(dir, "open_design.py")
|
||||
env = os.environ.copy()
|
||||
|
||||
env["EXPLICITLY_LISTED_LEFS"] = input_lef
|
||||
env["PDK_ROOT"] = pdk_root
|
||||
env["PDK"] = pdk
|
||||
env["LAYOUT"] = input_def
|
||||
|
||||
subprocess.check_call(
|
||||
[
|
||||
"klayout",
|
||||
"-rm",
|
||||
klayout_script_path,
|
||||
],
|
||||
env=env,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
open_design()
|
||||
45
scripts/most_recent_run.py
Normal file
45
scripts/most_recent_run.py
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2022 Efabless Corporation
|
||||
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import click
|
||||
|
||||
|
||||
@click.command("most_recent_run")
|
||||
@click.argument("runs_directory")
|
||||
def main(runs_directory):
|
||||
max_time = 0
|
||||
latest_run_name = None
|
||||
if not os.path.isdir(runs_directory):
|
||||
print(f"No runs found at '{runs_directory}'.", file=sys.stderr)
|
||||
exit(os.EX_NOINPUT)
|
||||
for run in os.listdir(runs_directory):
|
||||
run_folder_path = os.path.join(runs_directory, run)
|
||||
if not os.path.isdir(run_folder_path):
|
||||
continue
|
||||
time = os.stat(run_folder_path).st_mtime
|
||||
if time > max_time:
|
||||
latest_run_name = run
|
||||
|
||||
if latest_run_name is not None:
|
||||
print(latest_run_name, end="")
|
||||
else:
|
||||
print(f"No runs found at '{runs_directory}'.", file=sys.stderr)
|
||||
exit(os.EX_NOINPUT)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2020-2021 Efabless Corporation
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -41,7 +41,7 @@ proc set_netlist {netlist args} {
|
||||
|
||||
set netlist_relative [relpath . $netlist]
|
||||
|
||||
puts_info "Changing netlist to '$netlist_relative'..."
|
||||
puts_verbose "Changing netlist to '$netlist_relative'..."
|
||||
|
||||
set ::env(PREV_NETLIST) $::env(CURRENT_NETLIST)
|
||||
set ::env(CURRENT_NETLIST) $netlist
|
||||
@@ -59,7 +59,7 @@ proc set_netlist {netlist args} {
|
||||
|
||||
proc set_def {def} {
|
||||
set def_relative [relpath . $def]
|
||||
puts_info "Changing layout to '$def_relative'..."
|
||||
puts_verbose "Changing layout to '$def_relative'..."
|
||||
set ::env(CURRENT_DEF) $def
|
||||
set replace [string map {/ \\/} $def]
|
||||
exec sed -i -e "s/\\(set ::env(CURRENT_DEF)\\).*/\\1 $replace/" "$::env(GLB_CFG_FILE)"
|
||||
@@ -67,21 +67,21 @@ proc set_def {def} {
|
||||
|
||||
proc set_guide {guide} {
|
||||
set guide_relative [relpath . $guide]
|
||||
puts_info "Changing guide to '$guide_relative'..."
|
||||
puts_verbose "Changing guide to '$guide_relative'..."
|
||||
set ::env(CURRENT_GUIDE) $guide
|
||||
set replace [string map {/ \\/} $guide]
|
||||
exec sed -i -e "s/\\(set ::env(CURRENT_GUIDE)\\).*/\\1 $replace/" "$::env(GLB_CFG_FILE)"
|
||||
}
|
||||
|
||||
proc prep_lefs {args} {
|
||||
puts_info "Preparing LEF Files"
|
||||
puts_info "Extracting the number of available metal layers from $::env(TECH_LEF)"
|
||||
puts_info "Preparing LEF Files..."
|
||||
puts_verbose "Extracting the number of available metal layers from $::env(TECH_LEF)"
|
||||
|
||||
set ::env(TECH_METAL_LAYERS) [exec python3 $::env(SCRIPTS_DIR)/extract_metal_layers.py $::env(TECH_LEF)]
|
||||
set ::env(MAX_METAL_LAYER) [llength $::env(TECH_METAL_LAYERS)]
|
||||
|
||||
puts_info "The available metal layers ($::env(MAX_METAL_LAYER)) are $::env(TECH_METAL_LAYERS)"
|
||||
puts_info "Merging LEF Files..."
|
||||
puts_verbose "The available metal layers ($::env(MAX_METAL_LAYER)) are $::env(TECH_METAL_LAYERS)"
|
||||
puts_verbose "Merging LEF Files..."
|
||||
|
||||
try_catch $::env(SCRIPTS_DIR)/mergeLef.py -i $::env(TECH_LEF) $::env(CELLS_LEF) -o $::env(TMP_DIR)/merged_unpadded.lef |& tee $::env(TERMINAL_OUTPUT)
|
||||
|
||||
@@ -91,13 +91,13 @@ proc prep_lefs {args} {
|
||||
|
||||
if { [info exist ::env(EXTRA_LEFS)] } {
|
||||
try_catch $::env(SCRIPTS_DIR)/mergeLef.py -i $::env(MERGED_LEF_UNPADDED) {*}$::env(EXTRA_LEFS) -o $::env(MERGED_LEF_UNPADDED) |& tee $::env(TERMINAL_OUTPUT)
|
||||
puts_info "Merging the following extra LEFs: $::env(EXTRA_LEFS)"
|
||||
puts_verbose "Merging the following extra LEFs: $::env(EXTRA_LEFS)"
|
||||
}
|
||||
|
||||
# merge optimization library lef if it is different from the STD_CELL_LIBRARY
|
||||
if { [info exist ::env(STD_CELL_LIBRARY_OPT)] && $::env(STD_CELL_LIBRARY_OPT) != $::env(STD_CELL_LIBRARY) } {
|
||||
try_catch $::env(SCRIPTS_DIR)/mergeLef.py -i $::env(MERGED_LEF_UNPADDED) $::env(TECH_LEF_OPT) {*}$::env(CELLS_LEF_OPT) -o $::env(MERGED_LEF_UNPADDED) |& tee $::env(TERMINAL_OUTPUT)
|
||||
puts_info "Merging the optimization library LEFs: $::env(TECH_LEF_OPT) $::env(CELLS_LEF_OPT)"
|
||||
puts_verbose "Merging the optimization library LEFs: $::env(TECH_LEF_OPT) $::env(CELLS_LEF_OPT)"
|
||||
}
|
||||
|
||||
file copy -force $::env(CELLS_LEF_UNPADDED) $::env(TMP_DIR)/merged.lef
|
||||
@@ -106,7 +106,7 @@ proc prep_lefs {args} {
|
||||
if { [info exists ::env(USE_GPIO_ROUTING_LEF)] && $::env(USE_GPIO_ROUTING_LEF)} {
|
||||
set ::env(GPIO_PADS_LEF) $::env(GPIO_PADS_LEF_CORE_SIDE)
|
||||
}
|
||||
puts_info "Merging the following GPIO LEF views: $::env(GPIO_PADS_LEF)"
|
||||
puts_verbose "Merging the following GPIO LEF views: $::env(GPIO_PADS_LEF)"
|
||||
|
||||
file copy $::env(CELLS_LEF) $::env(CELLS_LEF).old
|
||||
try_catch $::env(SCRIPTS_DIR)/mergeLef.py -i $::env(CELLS_LEF).old {*}$::env(GPIO_PADS_LEF) -o $::env(CELLS_LEF)
|
||||
@@ -125,7 +125,7 @@ proc prep_lefs {args} {
|
||||
}
|
||||
|
||||
proc gen_exclude_list {args} {
|
||||
puts_info "Generating Exclude List..."
|
||||
puts_verbose "Generating cell exclude list..."
|
||||
set options {
|
||||
{-lib required}
|
||||
{-drc_exclude_list optional}
|
||||
@@ -163,7 +163,7 @@ proc gen_exclude_list {args} {
|
||||
}
|
||||
|
||||
if { [file exists $arg_values(-output)] && [info exists flags_map(-create_dont_use_list)] } {
|
||||
puts_info "Creating ::env(DONT_USE_CELLS)..."
|
||||
puts_verbose "Creating ::env(DONT_USE_CELLS)..."
|
||||
set fp [open "$arg_values(-output)" r]
|
||||
set x [read $fp]
|
||||
set y [split $x]
|
||||
@@ -175,7 +175,7 @@ proc gen_exclude_list {args} {
|
||||
}
|
||||
|
||||
proc trim_lib {args} {
|
||||
puts_info "Trimming Liberty..."
|
||||
puts_verbose "Trimming Liberty..."
|
||||
set options {
|
||||
{-input optional}
|
||||
{-output optional}
|
||||
@@ -248,12 +248,13 @@ proc prep {args} {
|
||||
{-run_path optional}
|
||||
{-src optional}
|
||||
{-override_env optional}
|
||||
{-verbose optional}
|
||||
}
|
||||
|
||||
set flags {
|
||||
-init_design_config
|
||||
-disable_output
|
||||
-overwrite
|
||||
-last_run
|
||||
}
|
||||
|
||||
set args_copy $args
|
||||
@@ -293,19 +294,30 @@ proc prep {args} {
|
||||
exit 0
|
||||
}
|
||||
|
||||
if { ! [info exists flags_map(-disable_output)] } {
|
||||
set_if_unset arg_values(-verbose) "0"
|
||||
set ::env(OPENLANE_VERBOSE) $arg_values(-verbose)
|
||||
|
||||
|
||||
set ::env(TERMINAL_OUTPUT) "/dev/null"
|
||||
if { $::env(OPENLANE_VERBOSE) >= 2 } {
|
||||
set ::env(TERMINAL_OUTPUT) ">&@stdout"
|
||||
} else {
|
||||
set ::env(TERMINAL_OUTPUT) "/dev/null"
|
||||
}
|
||||
|
||||
set ::env(datetime) [clock format [clock seconds] -format %Y.%m.%d_%H.%M.%S ]
|
||||
if { [lsearch -exact $args_copy -tag ] >= 0} {
|
||||
set tag "$arg_values(-tag)"
|
||||
} else {
|
||||
set tag "RUN_$::env(datetime)"
|
||||
set ::env(START_TIME) [clock format [clock seconds] -format %Y.%m.%d_%H.%M.%S ]
|
||||
|
||||
if { [info exists flags_map(-last_run)] } {
|
||||
if { [info exists arg_values(-tag)] } {
|
||||
puts_err "Cannot specify a tag with -last_run set."
|
||||
return -code error
|
||||
}
|
||||
|
||||
set arg_values(-tag) [exec python3 ./scripts/most_recent_run.py $::env(DESIGN_DIR)/runs]
|
||||
}
|
||||
|
||||
set_if_unset arg_values(-tag) "RUN_$::env(START_TIME)"
|
||||
set tag $arg_values(-tag)
|
||||
|
||||
|
||||
set ::env(CONFIGS) [glob $::env(OPENLANE_ROOT)/configuration/*.tcl]
|
||||
|
||||
if { [info exists arg_values(-config_file)] } {
|
||||
@@ -431,7 +443,7 @@ proc prep {args} {
|
||||
puts_warn "Removing exisiting run $::env(RUN_DIR)"
|
||||
after 1000
|
||||
file delete -force $::env(RUN_DIR)
|
||||
} else {
|
||||
} elseif { ![info exists flags_map(-last_run)] } {
|
||||
puts_warn "A run for $::env(DESIGN_NAME) with tag '$tag' already exists. Pass -overwrite option to overwrite it"
|
||||
puts_info "Now you can run commands that pick up where '$tag' left off"
|
||||
after 1000
|
||||
@@ -490,7 +502,7 @@ proc prep {args} {
|
||||
set density $::env(PL_TARGET_DENSITY)
|
||||
|
||||
# Fill config file
|
||||
puts_info "Storing configs into config.tcl ..."
|
||||
puts_verbose "Storing configs into config.tcl ..."
|
||||
exec echo "# Run configs" > $::env(GLB_CFG_FILE)
|
||||
set_log ::env(PDK_ROOT) $::env(PDK_ROOT) $::env(GLB_CFG_FILE) 1
|
||||
foreach index [lsort [array names ::env]] {
|
||||
@@ -633,7 +645,6 @@ proc prep {args} {
|
||||
}
|
||||
}
|
||||
|
||||
puts_info "Preparation complete"
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "openlane design prep"
|
||||
return -code ok
|
||||
|
||||
@@ -31,8 +31,6 @@ proc check_synthesis_failure {args} {
|
||||
if { ! $checker } {
|
||||
puts_err "Synthesis failed"
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "Synthesis was successful"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,8 +166,6 @@ proc check_cts_clock_nets {args} {
|
||||
puts_err $error
|
||||
puts_err "TritonCTS failed to find clock nets and/or sinks in the design; check whether the synthesized netlist contains flip-flops."
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "Clock Tree Synthesis was successful"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,8 +176,6 @@ proc check_replace_divergence {args} {
|
||||
puts_err "Global placement failed"
|
||||
puts_err $error
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "Global placement was successful"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,8 +186,6 @@ proc check_macro_placer_num_solns {args} {
|
||||
puts_err "Macro placement failed"
|
||||
puts_err "$error; you may need to adjust the HALO"
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "Macro placement was successful"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,10 +231,8 @@ proc quit_on_lvs_error {args} {
|
||||
set checker [catch {exec grep -E -o "Total errors = 0" $arg_values(-log)} error]
|
||||
|
||||
if { $checker != 0 } {
|
||||
puts_err "There are LVS errors in the design according to Netgen LVS."
|
||||
puts_err "There are LVS errors in the design.."
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "No LVS mismatches."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -259,8 +249,6 @@ proc quit_on_illegal_overlaps {args} {
|
||||
puts_err "There are illegal overlaps (e.g., routes over obstructions) in your design."
|
||||
puts_err "See $arg_values(-log) for more."
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "No illegal overlaps detected during extraction."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,8 +263,6 @@ proc quit_on_unconnected_pdn_nodes {args} {
|
||||
offsets/pitches to power all standard cell rails (or other PDN stripes) \
|
||||
in your design."
|
||||
flow_fail
|
||||
} else {
|
||||
puts_info "PDN generation was successful."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -36,8 +36,8 @@ proc init_floorplan_or {args} {
|
||||
}
|
||||
|
||||
proc init_floorplan {args} {
|
||||
puts_info "Running Initial Floorplanning..."
|
||||
increment_index
|
||||
puts_info "Running Initial Floorplanning..."
|
||||
TIMER::timer_start
|
||||
set ::env(SAVE_DEF) [index_file $::env(floorplan_tmpfiles)/initial_fp.def]
|
||||
set ::env(SAVE_SDC) [index_file $::env(floorplan_tmpfiles)/initial_fp.sdc]
|
||||
@@ -61,8 +61,8 @@ proc init_floorplan {args} {
|
||||
set core_width [expr {[lindex $::env(CORE_AREA) 2] - [lindex $::env(CORE_AREA) 0]}]
|
||||
set core_height [expr {[lindex $::env(CORE_AREA) 3] - [lindex $::env(CORE_AREA) 1]}]
|
||||
|
||||
puts_info "Core area width: $core_width"
|
||||
puts_info "Core area height: $core_height"
|
||||
puts_verbose "Core area width: $core_width"
|
||||
puts_verbose "Core area height: $core_height"
|
||||
|
||||
if { $::env(FP_PDN_AUTO_ADJUST) } {
|
||||
if { $core_width <= [expr {$::env(FP_PDN_VOFFSET) + $::env(FP_PDN_VPITCH)}] ||\
|
||||
@@ -77,11 +77,12 @@ proc init_floorplan {args} {
|
||||
}
|
||||
|
||||
}
|
||||
puts_info "Final Vertical PDN Offset: $::env(FP_PDN_VOFFSET)"
|
||||
puts_info "Final Horizontal PDN Offset: $::env(FP_PDN_HOFFSET)"
|
||||
|
||||
puts_info "Final Vertical PDN Pitch: $::env(FP_PDN_VPITCH)"
|
||||
puts_info "Final Horizontal PDN Pitch: $::env(FP_PDN_HPITCH)"
|
||||
puts_verbose "Final Vertical PDN Offset: $::env(FP_PDN_VOFFSET)"
|
||||
puts_verbose "Final Horizontal PDN Offset: $::env(FP_PDN_HOFFSET)"
|
||||
|
||||
puts_verbose "Final Vertical PDN Pitch: $::env(FP_PDN_VPITCH)"
|
||||
puts_verbose "Final Horizontal PDN Pitch: $::env(FP_PDN_HPITCH)"
|
||||
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "floorplan initialization - openroad"
|
||||
@@ -301,9 +302,7 @@ proc run_power_grid_generation {args} {
|
||||
set ::env(GND_NETS) $::env(GND_PIN)
|
||||
}
|
||||
|
||||
puts_info "Power planning the following nets"
|
||||
puts_info "Power: $::env(VDD_NETS)"
|
||||
puts_info "Ground: $::env(GND_NETS)"
|
||||
puts_info "Power planning with power {$::env(VDD_NETS)} and ground {$::env(GND_NETS)}..."
|
||||
|
||||
if { [llength $::env(VDD_NETS)] != [llength $::env(GND_NETS)] } {
|
||||
puts_err "VDD_NETS and GND_NETS must be of equal lengths"
|
||||
@@ -368,73 +367,72 @@ proc run_power_grid_generation {args} {
|
||||
|
||||
set ::env(FP_PDN_CORE_RING_VOFFSET)\
|
||||
[expr $::env(FP_PDN_CORE_RING_VOFFSET)\
|
||||
+2*($::env(FP_PDN_CORE_RING_VWIDTH)\
|
||||
+max($::env(FP_PDN_CORE_RING_VSPACING), $::env(FP_PDN_CORE_RING_HSPACING)))]
|
||||
set ::env(FP_PDN_CORE_RING_HOFFSET) \
|
||||
[expr $::env(FP_PDN_CORE_RING_HOFFSET)\
|
||||
+2*($::env(FP_PDN_CORE_RING_HWIDTH)+\
|
||||
max($::env(FP_PDN_CORE_RING_VSPACING), $::env(FP_PDN_CORE_RING_HSPACING)))]
|
||||
}
|
||||
set ::env(FP_PDN_ENABLE_RAILS) 1
|
||||
}
|
||||
+2*($::env(FP_PDN_CORE_RING_VWIDTH)\
|
||||
+max($::env(FP_PDN_CORE_RING_VSPACING), $::env(FP_PDN_CORE_RING_HSPACING)))]
|
||||
set ::env(FP_PDN_CORE_RING_HOFFSET) \
|
||||
[expr $::env(FP_PDN_CORE_RING_HOFFSET)\
|
||||
+2*($::env(FP_PDN_CORE_RING_HWIDTH)+\
|
||||
max($::env(FP_PDN_CORE_RING_VSPACING), $::env(FP_PDN_CORE_RING_HSPACING)))]
|
||||
}
|
||||
set ::env(FP_PDN_ENABLE_RAILS) 1
|
||||
}
|
||||
|
||||
proc run_floorplan {args} {
|
||||
puts_info "Running Floorplanning..."
|
||||
# |----------------------------------------------------|
|
||||
# |---------------- 2. FLOORPLAN ------------------|
|
||||
# |----------------------------------------------------|
|
||||
#
|
||||
# intial fp
|
||||
init_floorplan
|
||||
proc run_floorplan {args} {
|
||||
# |----------------------------------------------------|
|
||||
# |---------------- 2. FLOORPLAN ------------------|
|
||||
# |----------------------------------------------------|
|
||||
#
|
||||
# intial fp
|
||||
init_floorplan
|
||||
|
||||
# check for deprecated io variables
|
||||
if { [info exists ::env(FP_IO_HMETAL)]} {
|
||||
set ::env(FP_IO_HLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_HMETAL) - 1}]]
|
||||
puts_warn "You're using FP_IO_HMETAL in your configuration, which is a deprecated variable that will be removed in the future."
|
||||
puts_warn "We recommend you update your configuration as follows:"
|
||||
puts_warn "\tset ::env(FP_IO_HLAYER) {$::env(FP_IO_HLAYER)}"
|
||||
}
|
||||
|
||||
if { [info exists ::env(FP_IO_VMETAL)]} {
|
||||
set ::env(FP_IO_VLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_VMETAL) - 1}]]
|
||||
puts_warn "You're using FP_IO_VMETAL in your configuration, which is a deprecated variable that will be removed in the future."
|
||||
puts_warn "We recommend you update your configuration as follows:"
|
||||
puts_warn "\tset ::env(FP_IO_VLAYER) {$::env(FP_IO_VLAYER)}"
|
||||
}
|
||||
|
||||
|
||||
# place io
|
||||
if { [info exists ::env(FP_PIN_ORDER_CFG)] } {
|
||||
place_io_ol
|
||||
} else {
|
||||
if { [info exists ::env(FP_CONTEXT_DEF)] && [info exists ::env(FP_CONTEXT_LEF)] } {
|
||||
place_io
|
||||
global_placement_or
|
||||
place_contextualized_io \
|
||||
-lef $::env(FP_CONTEXT_LEF) \
|
||||
-def $::env(FP_CONTEXT_DEF)
|
||||
} else {
|
||||
place_io
|
||||
}
|
||||
}
|
||||
|
||||
apply_def_template
|
||||
|
||||
if { [info exist ::env(EXTRA_LEFS)] } {
|
||||
if { [info exist ::env(MACRO_PLACEMENT_CFG)] } {
|
||||
file copy -force $::env(MACRO_PLACEMENT_CFG) $::env(placement_tmpfiles)/macro_placement.cfg
|
||||
manual_macro_placement f
|
||||
} else {
|
||||
global_placement_or
|
||||
basic_macro_placement
|
||||
}
|
||||
}
|
||||
|
||||
tap_decap_or
|
||||
|
||||
scrot_klayout -layout $::env(CURRENT_DEF) -log $::env(floorplan_logs)/screenshot.log
|
||||
|
||||
run_power_grid_generation
|
||||
# check for deprecated io variables
|
||||
if { [info exists ::env(FP_IO_HMETAL)]} {
|
||||
set ::env(FP_IO_HLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_HMETAL) - 1}]]
|
||||
puts_warn "You're using FP_IO_HMETAL in your configuration, which is a deprecated variable that will be removed in the future."
|
||||
puts_warn "We recommend you update your configuration as follows:"
|
||||
puts_warn "\tset ::env(FP_IO_HLAYER) {$::env(FP_IO_HLAYER)}"
|
||||
}
|
||||
|
||||
package provide openlane 0.9
|
||||
if { [info exists ::env(FP_IO_VMETAL)]} {
|
||||
set ::env(FP_IO_VLAYER) [lindex $::env(TECH_METAL_LAYERS) [expr {$::env(FP_IO_VMETAL) - 1}]]
|
||||
puts_warn "You're using FP_IO_VMETAL in your configuration, which is a deprecated variable that will be removed in the future."
|
||||
puts_warn "We recommend you update your configuration as follows:"
|
||||
puts_warn "\tset ::env(FP_IO_VLAYER) {$::env(FP_IO_VLAYER)}"
|
||||
}
|
||||
|
||||
|
||||
# place io
|
||||
if { [info exists ::env(FP_PIN_ORDER_CFG)] } {
|
||||
place_io_ol
|
||||
} else {
|
||||
if { [info exists ::env(FP_CONTEXT_DEF)] && [info exists ::env(FP_CONTEXT_LEF)] } {
|
||||
place_io
|
||||
global_placement_or
|
||||
place_contextualized_io \
|
||||
-lef $::env(FP_CONTEXT_LEF) \
|
||||
-def $::env(FP_CONTEXT_DEF)
|
||||
} else {
|
||||
place_io
|
||||
}
|
||||
}
|
||||
|
||||
apply_def_template
|
||||
|
||||
if { [info exist ::env(EXTRA_LEFS)] } {
|
||||
if { [info exist ::env(MACRO_PLACEMENT_CFG)] } {
|
||||
file copy -force $::env(MACRO_PLACEMENT_CFG) $::env(placement_tmpfiles)/macro_placement.cfg
|
||||
manual_macro_placement f
|
||||
} else {
|
||||
global_placement_or
|
||||
basic_macro_placement
|
||||
}
|
||||
}
|
||||
|
||||
tap_decap_or
|
||||
|
||||
scrot_klayout -layout $::env(CURRENT_DEF) $::env(floorplan_logs)/screenshot.log
|
||||
|
||||
run_power_grid_generation
|
||||
}
|
||||
|
||||
package provide openlane 0.9
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2020-2021 Efabless Corporation
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -13,64 +13,58 @@
|
||||
# limitations under the License.
|
||||
|
||||
proc run_klayout {args} {
|
||||
if {$::env(RUN_KLAYOUT)} {
|
||||
TIMER::timer_start
|
||||
set ::env(CURRENT_STAGE) finishing
|
||||
puts_info "Generting GDS II with Klayout..."
|
||||
if {[ info exists ::env(KLAYOUT_TECH)] } {
|
||||
increment_index
|
||||
puts_info "Streaming out GDS II..."
|
||||
set gds_files_in ""
|
||||
if { [info exist ::env(EXTRA_GDS_FILES)] } {
|
||||
set gds_files_in $::env(EXTRA_GDS_FILES)
|
||||
}
|
||||
if { $::env(STD_CELL_LIBRARY_OPT) != $::env(STD_CELL_LIBRARY) } {
|
||||
set cells_gds "$::env(GDS_FILES) $::env(GDS_FILES_OPT)"
|
||||
} else {
|
||||
set cells_gds $::env(GDS_FILES)
|
||||
}
|
||||
|
||||
set klayout_out $::env(finishing_results)/$::env(DESIGN_NAME).klayout.gds
|
||||
try_catch klayout -b\
|
||||
-rm $::env(SCRIPTS_DIR)/klayout/def2gds.py\
|
||||
-rd out_gds=$klayout_out\
|
||||
-rd tech_file=$::env(KLAYOUT_TECH)\
|
||||
-rd design_name=$::env(DESIGN_NAME)\
|
||||
-rd in_def=$::env(CURRENT_DEF)\
|
||||
-rd "in_gds=$cells_gds $gds_files_in"\
|
||||
-rd "config_file="\
|
||||
-rd "seal_gds="\
|
||||
-rd lef_file=$::env(MERGED_LEF)\
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/gdsii-klayout.log]
|
||||
|
||||
if { $::env(PRIMARY_SIGNOFF_TOOL) == "klayout" } {
|
||||
set ::env(CURRENT_GDS) $::env(finishing_results)/$::env(DESIGN_NAME).gds
|
||||
file copy -force $klayout_out $::env(CURRENT_GDS)
|
||||
}
|
||||
|
||||
if {[info exists ::env(KLAYOUT_PROPERTIES)]} {
|
||||
file copy -force $::env(KLAYOUT_PROPERTIES) $::env(finishing_results)/$::env(DESIGN_NAME).lyp
|
||||
} else {
|
||||
puts_warn "::env(KLAYOUT_PROPERTIES) is not defined. So, it won't be copied to the run directory."
|
||||
}
|
||||
puts_info "Back-up GDS-II streamed out."
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "gdsii - klayout"
|
||||
scrot_klayout -layout $::env(finishing_results)/$::env(DESIGN_NAME).gds -log $::env(finishing_logs)/screenshot.klayout.log
|
||||
if { [info exists ::env(KLAYOUT_DRC_KLAYOUT_GDS)] && $::env(KLAYOUT_DRC_KLAYOUT_GDS) } {
|
||||
set conf_save $::env(RUN_KLAYOUT_DRC)
|
||||
set ::env(RUN_KLAYOUT_DRC) 1
|
||||
run_klayout_drc -gds $::env(finishing_results)/$::env(DESIGN_NAME).gds -stage klayout
|
||||
set ::env(RUN_KLAYOUT_DRC) $conf_save
|
||||
}
|
||||
} elseif { $::env(PRIMARY_SIGNOFF_TOOL) != "klayout" } {
|
||||
puts_warn "::env(KLAYOUT_TECH) is not defined for the current PDK. So, GDS-II streaming out using Klayout will be skipped."
|
||||
puts_warn "This warning can be turned off by setting ::env(RUN_KLAYOUT) to 0, or defining a tech file."
|
||||
} else {
|
||||
puts_err "::env(KLAYOUT_TECH) is not defined for the current PDK, however Klayout is set as the primary signoff tool. This is a critical error."
|
||||
flow_fail
|
||||
TIMER::timer_start
|
||||
set ::env(CURRENT_STAGE) finishing
|
||||
if {[ info exists ::env(KLAYOUT_TECH)] } {
|
||||
increment_index
|
||||
puts_info "Streaming out GDS-II with Klayout..."
|
||||
set gds_files_in ""
|
||||
if { [info exist ::env(EXTRA_GDS_FILES)] } {
|
||||
set gds_files_in $::env(EXTRA_GDS_FILES)
|
||||
}
|
||||
if { $::env(STD_CELL_LIBRARY_OPT) != $::env(STD_CELL_LIBRARY) } {
|
||||
set cells_gds "$::env(GDS_FILES) $::env(GDS_FILES_OPT)"
|
||||
} else {
|
||||
set cells_gds $::env(GDS_FILES)
|
||||
}
|
||||
|
||||
set klayout_out $::env(finishing_results)/$::env(DESIGN_NAME).klayout.gds
|
||||
try_catch klayout -b\
|
||||
-rm $::env(SCRIPTS_DIR)/klayout/def2gds.py\
|
||||
-rd out_gds=$klayout_out\
|
||||
-rd tech_file=$::env(KLAYOUT_TECH)\
|
||||
-rd design_name=$::env(DESIGN_NAME)\
|
||||
-rd in_def=$::env(CURRENT_DEF)\
|
||||
-rd "in_gds=$cells_gds $gds_files_in"\
|
||||
-rd "config_file="\
|
||||
-rd "seal_gds="\
|
||||
-rd lef_file=$::env(MERGED_LEF)\
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/gdsii-klayout.log]
|
||||
|
||||
|
||||
if {[info exists ::env(KLAYOUT_PROPERTIES)]} {
|
||||
file copy -force $::env(KLAYOUT_PROPERTIES) $::env(finishing_results)/$::env(DESIGN_NAME).lyp
|
||||
} else {
|
||||
puts_warn "::env(KLAYOUT_PROPERTIES) is not defined. So, it won't be copied to the run directory."
|
||||
}
|
||||
|
||||
|
||||
if { $::env(PRIMARY_SIGNOFF_TOOL) == "klayout" } {
|
||||
set ::env(CURRENT_GDS) $::env(finishing_results)/$::env(DESIGN_NAME).gds
|
||||
file copy -force $klayout_out $::env(CURRENT_GDS)
|
||||
}
|
||||
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "gdsii - klayout"
|
||||
scrot_klayout -layout $::env(finishing_results)/$::env(DESIGN_NAME).gds -log $::env(finishing_logs)/screenshot.klayout.log
|
||||
} elseif { $::env(PRIMARY_SIGNOFF_TOOL) != "klayout" } {
|
||||
puts_warn "::env(KLAYOUT_TECH) is not defined for the current PDK. So, GDS-II streaming out using Klayout will be skipped."
|
||||
puts_warn "This warning can be turned off by setting ::env(RUN_KLAYOUT) to 0, or defining a tech file."
|
||||
} else {
|
||||
puts_err "::env(KLAYOUT_TECH) is not defined for the current PDK, however Klayout is set as the primary signoff tool. This is a critical error."
|
||||
flow_fail
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
proc scrot_klayout {args} {
|
||||
@@ -103,85 +97,91 @@ proc scrot_klayout {args} {
|
||||
}
|
||||
|
||||
proc run_klayout_drc {args} {
|
||||
if {$::env(RUN_KLAYOUT_DRC)} {
|
||||
TIMER::timer_start
|
||||
TIMER::timer_start
|
||||
if {[ info exists ::env(KLAYOUT_DRC_TECH_SCRIPT)] && [file exists $::env(KLAYOUT_DRC_TECH_SCRIPT)]} {
|
||||
increment_index
|
||||
puts_info "Running DRC on the layout using Klayout..."
|
||||
if {[ info exists ::env(KLAYOUT_DRC_TECH_SCRIPT)] } {
|
||||
increment_index
|
||||
set options {
|
||||
{-gds optional}
|
||||
{-stage optional}
|
||||
}
|
||||
parse_key_args "run_klayout_drc" args arg_values $options
|
||||
if {[info exists ::env(CURRENT_GDS)]} {
|
||||
set_if_unset arg_values(-gds) $::env(CURRENT_GDS)
|
||||
}
|
||||
set_if_unset arg_values(-stage) magic
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/run_drc.sh $::env(KLAYOUT_DRC_TECH_SCRIPT) $arg_values(-gds) $arg_values(-gds).lydrc |& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$arg_values(-stage).drc.log]
|
||||
file copy -force $arg_values(-gds).lydrc [index_file $::env(finishing_reports)/$arg_values(-stage).lydrc]
|
||||
puts_info "Klayout DRC Complete"
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "drc - klayout"
|
||||
} elseif { $::env(PRIMARY_SIGNOFF_TOOL) != "klayout" } {
|
||||
puts_warn "::env(KLAYOUT_DRC_TECH_SCRIPT) is not defined for the current PDK. So, GDS-II streaming out using Klayout will be skipped."
|
||||
puts_warn "This warning can be turned off by setting ::env(RUN_KLAYOUT_DRC) to 0, or designating a tech file."
|
||||
} else {
|
||||
puts_err "::env(KLAYOUT_DRC_TECH_SCRIPT) is not defined for the current PDK, however Klayout is set as the primary signoff tool. This is a critical error."
|
||||
flow_fail
|
||||
set options {
|
||||
{-gds optional}
|
||||
{-stage optional}
|
||||
}
|
||||
parse_key_args "run_klayout_drc" args arg_values $options
|
||||
if {[info exists ::env(CURRENT_GDS)]} {
|
||||
set_if_unset arg_values(-gds) $::env(CURRENT_GDS)
|
||||
}
|
||||
set_if_unset arg_values(-stage) magic
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/run_drc.sh $::env(KLAYOUT_DRC_TECH_SCRIPT) $arg_values(-gds) $arg_values(-gds).lydrc |& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$arg_values(-stage).drc.log]
|
||||
file copy -force $arg_values(-gds).lydrc [index_file $::env(finishing_reports)/$arg_values(-stage).lydrc]
|
||||
puts_info "Klayout DRC Complete"
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "drc - klayout"
|
||||
} elseif { $::env(PRIMARY_SIGNOFF_TOOL) != "klayout" } {
|
||||
puts_warn "::env(KLAYOUT_DRC_TECH_SCRIPT) is not defined or doesn't exist for the current PDK. So, GDS-II streaming out using Klayout will be skipped."
|
||||
puts_warn "This warning can be turned off by setting ::env(RUN_KLAYOUT_DRC) to 0, or designating a tech file."
|
||||
} else {
|
||||
puts_err "::env(KLAYOUT_DRC_TECH_SCRIPT) is not defined or doesn't exist for the current PDK, however Klayout is set as the primary signoff tool. This is a critical error."
|
||||
flow_fail
|
||||
}
|
||||
}
|
||||
|
||||
proc run_klayout_gds_xor {args} {
|
||||
if {$::env(RUN_KLAYOUT_XOR)} {
|
||||
increment_index
|
||||
index_file $::env(finishing_logs)/xor.log
|
||||
TIMER::timer_start
|
||||
puts_info "Running XOR on the layouts using Klayout..."
|
||||
set options {
|
||||
{-layout1 optional}
|
||||
{-layout2 optional}
|
||||
{-output_xml optional}
|
||||
{-output_gds optional}
|
||||
}
|
||||
parse_key_args "run_klayout_gds_xor" args arg_values $options
|
||||
set_if_unset arg_values(-layout1) $::env(finishing_results)/$::env(DESIGN_NAME).gds
|
||||
set_if_unset arg_values(-layout2) $::env(finishing_results)/$::env(DESIGN_NAME).klayout.gds
|
||||
set_if_unset arg_values(-output_xml) $::env(finishing_reports)/$::env(DESIGN_NAME).xor.xml
|
||||
set_if_unset arg_values(-output_gds) $::env(finishing_reports)/$::env(DESIGN_NAME).xor.gds
|
||||
if { [file exists $arg_values(-layout1)]} {
|
||||
if { [file exists $arg_values(-layout2)] } {
|
||||
if { $::env(KLAYOUT_XOR_GDS) } {
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/xor.sh \
|
||||
$arg_values(-layout1) $arg_values(-layout2) $::env(DESIGN_NAME) \
|
||||
$arg_values(-output_gds) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/xor.log]
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
|
||||
-l [index_file $::env(finishing_logs)/xor.log] \
|
||||
-o [index_file $::env(finishing_reports)/xor.rpt]
|
||||
scrot_klayout -layout $arg_values(-output_gds) -log $::env(finishing_logs)/screenshot.klayout.xor.log
|
||||
}
|
||||
increment_index
|
||||
index_file $::env(finishing_logs)/xor.log
|
||||
TIMER::timer_start
|
||||
puts_info "Running XOR on the layouts using Klayout..."
|
||||
set options {
|
||||
{-layout1 optional}
|
||||
{-layout2 optional}
|
||||
{-output_xml optional}
|
||||
{-output_gds optional}
|
||||
}
|
||||
parse_key_args "run_klayout_gds_xor" args arg_values $options
|
||||
set_if_unset arg_values(-layout1) $::env(finishing_results)/$::env(DESIGN_NAME).gds
|
||||
set_if_unset arg_values(-layout2) $::env(finishing_results)/$::env(DESIGN_NAME).klayout.gds
|
||||
set_if_unset arg_values(-output_xml) $::env(finishing_reports)/$::env(DESIGN_NAME).xor.xml
|
||||
set_if_unset arg_values(-output_gds) $::env(finishing_reports)/$::env(DESIGN_NAME).xor.gds
|
||||
if { [file exists $arg_values(-layout1)]} {
|
||||
if { [file exists $arg_values(-layout2)] } {
|
||||
if { $::env(KLAYOUT_XOR_GDS) } {
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/xor.sh \
|
||||
$arg_values(-layout1) $arg_values(-layout2) $::env(DESIGN_NAME) \
|
||||
$arg_values(-output_gds) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/xor.log]
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
|
||||
-l [index_file $::env(finishing_logs)/xor.log] \
|
||||
-o [index_file $::env(finishing_reports)/xor.rpt]
|
||||
scrot_klayout -layout $arg_values(-output_gds) -log $::env(finishing_logs)/screenshot.klayout.xor.log
|
||||
}
|
||||
|
||||
if { $::env(KLAYOUT_XOR_XML) } {
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/xor.sh \
|
||||
$arg_values(-layout1) $arg_values(-layout2) $::env(DESIGN_NAME) \
|
||||
$arg_values(-output_xml) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/xor.log]
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
|
||||
-l [index_file $::env(finishing_logs)/xor.log] \
|
||||
-o [index_file $::env(finishing_reports)/xor.rpt]
|
||||
}
|
||||
|
||||
puts_info "Klayout XOR Complete"
|
||||
} else {
|
||||
puts_warn "$arg_values(-layout2) wasn't found. Skipping GDS XOR."
|
||||
if { $::env(KLAYOUT_XOR_XML) } {
|
||||
try_catch bash $::env(SCRIPTS_DIR)/klayout/xor.sh \
|
||||
$arg_values(-layout1) $arg_values(-layout2) $::env(DESIGN_NAME) \
|
||||
$arg_values(-output_xml) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/xor.log]
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/parse_klayout_xor_log.py \
|
||||
-l [index_file $::env(finishing_logs)/xor.log] \
|
||||
-o [index_file $::env(finishing_reports)/xor.rpt]
|
||||
}
|
||||
} else {
|
||||
puts_warn "$arg_values(-layout1) wasn't found. Skipping GDS XOR."
|
||||
puts_warn "$arg_values(-layout2) wasn't found. Skipping GDS XOR."
|
||||
}
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "xor - klayout"
|
||||
} else {
|
||||
puts_warn "$arg_values(-layout1) wasn't found. Skipping GDS XOR."
|
||||
}
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "xor - klayout"
|
||||
}
|
||||
|
||||
proc open_in_klayout {args} {
|
||||
set options {
|
||||
{-layout optional}
|
||||
}
|
||||
parse_key_args "open_in_klayout" args arg_values $options
|
||||
|
||||
set_if_unset arg_values(-layout) $::env(CURRENT_DEF)
|
||||
|
||||
try_catch python3 $::env(SCRIPTS_DIR)/klayout/open_design_cmd.py\
|
||||
$arg_values(-layout)
|
||||
}
|
||||
|
||||
package provide openlane 0.9
|
||||
|
||||
@@ -32,10 +32,10 @@ proc verilog_to_verilogPower {args} {
|
||||
set lef $arg_values(-lef)
|
||||
|
||||
try_catch $bin \
|
||||
-v $power \
|
||||
-g $gnd \
|
||||
-l $lef \
|
||||
$in |& tee $out
|
||||
-v $power \
|
||||
-g $gnd \
|
||||
-l $lef \
|
||||
$in |& tee $out
|
||||
}
|
||||
|
||||
# WORKS ON DEF FILES
|
||||
@@ -71,13 +71,13 @@ proc write_powered_verilog {args} {
|
||||
}
|
||||
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/write_powered_def.py \
|
||||
-d $arg_values(-def) \
|
||||
-l $arg_values(-lef) \
|
||||
--power-port $arg_values(-power) \
|
||||
--ground-port $arg_values(-ground) \
|
||||
--powered-netlist $arg_values(-powered_netlist) \
|
||||
-o $arg_values(-output_def) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $arg_values(-def_log)]
|
||||
-d $arg_values(-def) \
|
||||
-l $arg_values(-lef) \
|
||||
--power-port $arg_values(-power) \
|
||||
--ground-port $arg_values(-ground) \
|
||||
--powered-netlist $arg_values(-powered_netlist) \
|
||||
-o $arg_values(-output_def) \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $arg_values(-def_log)]
|
||||
|
||||
write_verilog $arg_values(-output_verilog) -def $arg_values(-output_def) -log [index_file $arg_values(-log)] -canonical
|
||||
TIMER::timer_stop
|
||||
@@ -87,93 +87,91 @@ proc write_powered_verilog {args} {
|
||||
# "layout": a spice netlist
|
||||
# "schematic": a verilog netlist
|
||||
proc run_lvs {{layout "$::env(EXT_NETLIST)"}} {
|
||||
if { $::env(RUN_LVS) } {
|
||||
# LEF LVS output to lvs.lef.log, design.lvs.lef.log, design.lvs.lef.json, design.lvs.lef.log
|
||||
# GDS LVS output to lvs.gds.log, design.lvs.gds.log, design.lvs.gds.json, design.lvs.gds.log
|
||||
# GDS LVS uses STD_CELL_LIBRARY spice and
|
||||
# if defined, additional LVS_EXTRA_STD_CELL_LIBRARY spice and LVS_EXTRA_GATE_LEVEL_VERILOG files
|
||||
# Write Netlist
|
||||
if { $::env(LVS_INSERT_POWER_PINS) } {
|
||||
set powered_netlist_name [index_file $::env(finishing_tmpfiles)/powered_netlist.v]
|
||||
set powered_def_name [index_file $::env(finishing_tmpfiles)/powered_def.def]
|
||||
write_powered_verilog\
|
||||
-output_verilog $powered_netlist_name\
|
||||
-output_def $powered_def_name\
|
||||
-log $::env(finishing_logs)/write_verilog.log\
|
||||
-def_log $::env(finishing_logs)/write_powered_def.log
|
||||
# LEF LVS output to lvs.lef.log, design.lvs.lef.log, design.lvs.lef.json, design.lvs.lef.log
|
||||
# GDS LVS output to lvs.gds.log, design.lvs.gds.log, design.lvs.gds.json, design.lvs.gds.log
|
||||
# GDS LVS uses STD_CELL_LIBRARY spice and
|
||||
# if defined, additional LVS_EXTRA_STD_CELL_LIBRARY spice and LVS_EXTRA_GATE_LEVEL_VERILOG files
|
||||
# Write Netlist
|
||||
if { $::env(LVS_INSERT_POWER_PINS) } {
|
||||
set powered_netlist_name [index_file $::env(finishing_tmpfiles)/powered_netlist.v]
|
||||
set powered_def_name [index_file $::env(finishing_tmpfiles)/powered_def.def]
|
||||
write_powered_verilog\
|
||||
-output_verilog $powered_netlist_name\
|
||||
-output_def $powered_def_name\
|
||||
-log $::env(finishing_logs)/write_verilog.log\
|
||||
-def_log $::env(finishing_logs)/write_powered_def.log
|
||||
|
||||
set_netlist $powered_netlist_name
|
||||
set_netlist $powered_netlist_name
|
||||
|
||||
if { $::env(LEC_ENABLE) } {
|
||||
logic_equiv_check -rhs $::env(PREV_NETLIST) -lhs $::env(CURRENT_NETLIST)
|
||||
}
|
||||
if { $::env(LEC_ENABLE) } {
|
||||
logic_equiv_check -rhs $::env(PREV_NETLIST) -lhs $::env(CURRENT_NETLIST)
|
||||
}
|
||||
|
||||
increment_index
|
||||
TIMER::timer_start
|
||||
if { [info exist ::env(MAGIC_EXT_USE_GDS)] && $::env(MAGIC_EXT_USE_GDS) } {
|
||||
set extract_type gds
|
||||
puts_info "Running GDS LVS..."
|
||||
} else {
|
||||
set extract_type lef
|
||||
puts_info "Running LEF LVS..."
|
||||
}
|
||||
|
||||
|
||||
set schematic $::env(CURRENT_NETLIST)
|
||||
|
||||
set layout [subst $layout]
|
||||
|
||||
set setup_file $::env(NETGEN_SETUP_FILE)
|
||||
set module_name $::env(DESIGN_NAME)
|
||||
#writes setup_file_*_lvs to tmp directory.
|
||||
set lvs_file_path [index_file $::env(finishing_tmpfiles)/setup_file.$extract_type.lvs]
|
||||
set lvs_file [open $lvs_file_path w]
|
||||
if { "$extract_type" == "gds" } {
|
||||
if { [info exist ::env(LVS_EXTRA_STD_CELL_LIBRARY)] } {
|
||||
set libs_in $::env(LVS_EXTRA_STD_CELL_LIBRARY)
|
||||
foreach lib_file $libs_in {
|
||||
puts $lvs_file "puts \"Reading spice netlist file $lib_file\""
|
||||
puts $lvs_file "readnet spice $lib_file 1"
|
||||
}
|
||||
} else {
|
||||
if { [info exist ::env(STD_CELL_LIBRARY)] } {
|
||||
set std_cell_source $::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/spice/$::env(STD_CELL_LIBRARY).spice
|
||||
} else {
|
||||
set std_cell_source $::env(PDK_ROOT)/$::env(PDK)/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice
|
||||
}
|
||||
puts $lvs_file "puts \"Reading spice netlist file $std_cell_source\""
|
||||
puts $lvs_file "readnet spice $std_cell_source 1"
|
||||
}
|
||||
if { [info exist ::env(LVS_EXTRA_GATE_LEVEL_VERILOG)] } {
|
||||
set libs_in $::env(LVS_EXTRA_GATE_LEVEL_VERILOG)
|
||||
foreach lib_file $libs_in {
|
||||
puts $lvs_file "puts \"Reading verilog netlist file $lib_file\""
|
||||
puts $lvs_file "readnet verilog $lib_file 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set extraction_prefix [index_file $::env(finishing_logs)/$::env(DESIGN_NAME).$extract_type]
|
||||
|
||||
puts $lvs_file "lvs {$layout $module_name} {$schematic $module_name} $setup_file $extraction_prefix.log -json"
|
||||
close $lvs_file
|
||||
|
||||
puts_info "$layout against $schematic"
|
||||
|
||||
try_catch netgen -batch source $lvs_file_path \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$extract_type.log]
|
||||
|
||||
set count_lvs_log [index_file $::env(finishing_logs)/$::env(DESIGN_NAME).lvs.$extract_type.log]
|
||||
|
||||
exec python3 $::env(SCRIPTS_DIR)/count_lvs.py \
|
||||
-f $extraction_prefix.json \
|
||||
|& tee $::env(TERMINAL_OUTPUT) $count_lvs_log
|
||||
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "lvs - netgen"
|
||||
quit_on_lvs_error -log $count_lvs_log
|
||||
}
|
||||
|
||||
increment_index
|
||||
TIMER::timer_start
|
||||
if { [info exist ::env(MAGIC_EXT_USE_GDS)] && $::env(MAGIC_EXT_USE_GDS) } {
|
||||
set extract_type gds
|
||||
puts_info "Running GDS LVS..."
|
||||
} else {
|
||||
set extract_type lef
|
||||
puts_info "Running LEF LVS..."
|
||||
}
|
||||
|
||||
|
||||
set schematic $::env(CURRENT_NETLIST)
|
||||
|
||||
set layout [subst $layout]
|
||||
|
||||
set setup_file $::env(NETGEN_SETUP_FILE)
|
||||
set module_name $::env(DESIGN_NAME)
|
||||
#writes setup_file_*_lvs to tmp directory.
|
||||
set lvs_file_path [index_file $::env(finishing_tmpfiles)/setup_file.$extract_type.lvs]
|
||||
set lvs_file [open $lvs_file_path w]
|
||||
if { "$extract_type" == "gds" } {
|
||||
if { [info exist ::env(LVS_EXTRA_STD_CELL_LIBRARY)] } {
|
||||
set libs_in $::env(LVS_EXTRA_STD_CELL_LIBRARY)
|
||||
foreach lib_file $libs_in {
|
||||
puts $lvs_file "puts \"Reading spice netlist file $lib_file\""
|
||||
puts $lvs_file "readnet spice $lib_file 1"
|
||||
}
|
||||
} else {
|
||||
if { [info exist ::env(STD_CELL_LIBRARY)] } {
|
||||
set std_cell_source $::env(PDK_ROOT)/$::env(PDK)/libs.ref/$::env(STD_CELL_LIBRARY)/spice/$::env(STD_CELL_LIBRARY).spice
|
||||
} else {
|
||||
set std_cell_source $::env(PDK_ROOT)/$::env(PDK)/libs.ref/sky130_fd_sc_hd/spice/sky130_fd_sc_hd.spice
|
||||
}
|
||||
puts $lvs_file "puts \"Reading spice netlist file $std_cell_source\""
|
||||
puts $lvs_file "readnet spice $std_cell_source 1"
|
||||
}
|
||||
if { [info exist ::env(LVS_EXTRA_GATE_LEVEL_VERILOG)] } {
|
||||
set libs_in $::env(LVS_EXTRA_GATE_LEVEL_VERILOG)
|
||||
foreach lib_file $libs_in {
|
||||
puts $lvs_file "puts \"Reading verilog netlist file $lib_file\""
|
||||
puts $lvs_file "readnet verilog $lib_file 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set extraction_prefix [index_file $::env(finishing_logs)/$::env(DESIGN_NAME).$extract_type]
|
||||
|
||||
puts $lvs_file "lvs {$layout $module_name} {$schematic $module_name} $setup_file $extraction_prefix.log -json"
|
||||
close $lvs_file
|
||||
|
||||
puts_verbose "$layout against $schematic"
|
||||
|
||||
try_catch netgen -batch source $lvs_file_path \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$extract_type.log]
|
||||
|
||||
set count_lvs_log [index_file $::env(finishing_logs)/$::env(DESIGN_NAME).lvs.$extract_type.log]
|
||||
|
||||
exec python3 $::env(SCRIPTS_DIR)/count_lvs.py \
|
||||
-f $extraction_prefix.json \
|
||||
|& tee $::env(TERMINAL_OUTPUT) $count_lvs_log
|
||||
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "lvs - netgen"
|
||||
quit_on_lvs_error -log $count_lvs_log
|
||||
}
|
||||
|
||||
proc run_netgen {args} {
|
||||
|
||||
@@ -20,7 +20,7 @@ proc run_magic {args} {
|
||||
# |----------------------------------------------------|
|
||||
# |---------------- 6. TAPE-OUT ---------------------|
|
||||
# |----------------------------------------------------|
|
||||
puts_info "Streaming out GDS II..."
|
||||
puts_info "Streaming out GDS-II with Magic..."
|
||||
set ::env(CURRENT_STAGE) finishing
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)"
|
||||
# the following MAGTYPE better be mag for clean GDS generation
|
||||
@@ -29,14 +29,14 @@ proc run_magic {args} {
|
||||
set ::env(MAGTYPE) mag
|
||||
# Generate GDS and MAG views
|
||||
set ::env(MAGIC_GDS) $::env(finishing_results)/$::env(DESIGN_NAME).magic.gds
|
||||
|
||||
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/mag_gds.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/gdsii.log]
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/mag_gds.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/gdsii.log]
|
||||
|
||||
if { $::env(PRIMARY_SIGNOFF_TOOL) == "magic" } {
|
||||
set ::env(CURRENT_GDS) $::env(finishing_results)/$::env(DESIGN_NAME).gds
|
||||
@@ -72,22 +72,22 @@ proc run_magic {args} {
|
||||
# Generate LEF view
|
||||
set ::env(MAGTYPE) maglef
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/lef.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/lef.log]
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/lef.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/lef.log]
|
||||
if { $::env(MAGIC_GENERATE_MAGLEF) } {
|
||||
# Generate MAGLEF view
|
||||
set ::env(MAGTYPE) maglef
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/maglef.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/maglef.log]
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/maglef.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/maglef.log]
|
||||
# By default, copy the GDS properties into the maglef/ view
|
||||
copy_gds_properties $::env(finishing_tmpfiles)/gds_ptrs.mag $::env(finishing_results)/$::env(DESIGN_NAME).lef.mag
|
||||
}
|
||||
@@ -99,52 +99,51 @@ proc run_magic {args} {
|
||||
|
||||
|
||||
proc run_magic_drc {args} {
|
||||
if { $::env(RUN_MAGIC_DRC) } {
|
||||
increment_index
|
||||
TIMER::timer_start
|
||||
puts_info "Running Magic DRC..."
|
||||
increment_index
|
||||
TIMER::timer_start
|
||||
puts_info "Running Magic DRC..."
|
||||
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)"
|
||||
set ::env(drc_prefix) $::env(finishing_reports)/drc
|
||||
# Has to be maglef for DRC Checking
|
||||
set ::env(MAGTYPE) maglef
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)"
|
||||
set ::env(drc_prefix) $::env(finishing_reports)/drc
|
||||
# Has to be maglef for DRC Checking
|
||||
set ::env(MAGTYPE) maglef
|
||||
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/drc.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/drc.log]
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$::env(SCRIPTS_DIR)/magic/drc.tcl \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/drc.log]
|
||||
|
||||
puts_info "Converting Magic DRC Violations to Magic Readable Format..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_tcl.py \
|
||||
-i $::env(drc_prefix).rpt \
|
||||
-o $::env(drc_prefix).tcl
|
||||
puts_info "Converting Magic DRC Violations to Magic Readable Format..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_tcl.py \
|
||||
-i $::env(drc_prefix).rpt \
|
||||
-o $::env(drc_prefix).tcl
|
||||
|
||||
puts_info "Converting Magic DRC Violations to Klayout XML Database..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_tr_drc.py \
|
||||
-i $::env(drc_prefix).rpt \
|
||||
-o $::env(drc_prefix).tr
|
||||
puts_info "Converting Magic DRC Violations to Klayout XML Database..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_tr_drc.py \
|
||||
-i $::env(drc_prefix).rpt \
|
||||
-o $::env(drc_prefix).tr
|
||||
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/tr_drc_to_klayout_drc.py \
|
||||
-i $::env(drc_prefix).tr \
|
||||
-o $::env(drc_prefix).klayout.xml \
|
||||
--design-name $::env(DESIGN_NAME)
|
||||
puts_info "Converting TritonRoute DRC Violations to Klayout XML Database..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/tr_drc_to_klayout_drc.py \
|
||||
-i $::env(drc_prefix).tr \
|
||||
-o $::env(drc_prefix).klayout.xml \
|
||||
--design-name $::env(DESIGN_NAME)
|
||||
|
||||
if { $::env(MAGIC_CONVERT_DRC_TO_RDB) == 1 } {
|
||||
puts_info "Converting DRC Violations to RDB Format..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_rdb.py \
|
||||
--magic_drc_in $::env(drc_prefix).rpt \
|
||||
--rdb_out $::env(drc_prefix).rdb
|
||||
puts_info "Converted DRC Violations to RDB Format"
|
||||
}
|
||||
file copy -force $::env(MAGIC_MAGICRC) $::env(finishing_results)/.magicrc
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "drc - magic"
|
||||
if { $::env(MAGIC_CONVERT_DRC_TO_RDB) == 1 } {
|
||||
puts_info "Converting DRC Violations to RDB Format..."
|
||||
try_catch $::env(OPENROAD_BIN) -python $::env(SCRIPTS_DIR)/magic_drc_to_rdb.py \
|
||||
--magic_drc_in $::env(drc_prefix).rpt \
|
||||
--rdb_out $::env(drc_prefix).rdb
|
||||
}
|
||||
|
||||
quit_on_magic_drc -log $::env(drc_prefix).tr
|
||||
}
|
||||
file copy -force $::env(MAGIC_MAGICRC) $::env(finishing_results)/.magicrc
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "drc - magic"
|
||||
|
||||
quit_on_magic_drc -log $::env(drc_prefix).tr
|
||||
}
|
||||
|
||||
proc run_magic_spice_export {args} {
|
||||
@@ -165,7 +164,7 @@ proc run_magic_spice_export {args} {
|
||||
set ::env(EXT_NETLIST) $::env(finishing_results)/$::env(DESIGN_NAME).$extract_type
|
||||
set magic_export $::env(finishing_tmpfiles)/$extract_type.tcl
|
||||
set commands \
|
||||
"
|
||||
"
|
||||
if { \[info exist ::env(MAGIC_EXT_USE_GDS)\] && \$::env(MAGIC_EXT_USE_GDS) } {
|
||||
gds read \$::env(CURRENT_GDS)
|
||||
} else {
|
||||
@@ -196,42 +195,42 @@ ext2spice -o $::env(EXT_NETLIST) $::env(DESIGN_NAME).ext
|
||||
feedback save $::env(magic_extract_prefix)$extract_type.feedback.txt
|
||||
# exec cp $::env(DESIGN_NAME).spice $::env(finishing_results)/$::env(DESIGN_NAME).spice
|
||||
"
|
||||
set magic_export_file [open $magic_export w]
|
||||
puts $magic_export_file $commands
|
||||
close $magic_export_file
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
# the following MAGTYPE has to be maglef for the purpose of LVS
|
||||
# otherwise underlying device circuits would be considered
|
||||
set ::env(MAGTYPE) maglef
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$magic_export \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$extract_type.log]
|
||||
set magic_export_file [open $magic_export w]
|
||||
puts $magic_export_file $commands
|
||||
close $magic_export_file
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
# the following MAGTYPE has to be maglef for the purpose of LVS
|
||||
# otherwise underlying device circuits would be considered
|
||||
set ::env(MAGTYPE) maglef
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$magic_export \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/$extract_type.log]
|
||||
|
||||
if { $extract_type == "spice" } {
|
||||
file copy -force $::env(finishing_results)/$::env(DESIGN_NAME).spice $::env(finishing_results)/$::env(DESIGN_NAME).lef.spice
|
||||
}
|
||||
file rename -force {*}[glob $::env(finishing_results)/*.ext] $::env(finishing_tmpfiles)
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "$extract_type extraction - magic"
|
||||
if { $extract_type == "spice" } {
|
||||
file copy -force $::env(finishing_results)/$::env(DESIGN_NAME).spice $::env(finishing_results)/$::env(DESIGN_NAME).lef.spice
|
||||
}
|
||||
file rename -force {*}[glob $::env(finishing_results)/*.ext] $::env(finishing_tmpfiles)
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "$extract_type extraction - magic"
|
||||
|
||||
quit_on_illegal_overlaps -log [index_file $::env(finishing_logs)/ext2$extract_type.feedback.txt]
|
||||
quit_on_illegal_overlaps -log [index_file $::env(finishing_logs)/ext2$extract_type.feedback.txt]
|
||||
}
|
||||
|
||||
proc export_magic_view {args} {
|
||||
TIMER::timer_start
|
||||
set options {
|
||||
{-def required}
|
||||
{-output required}
|
||||
{-def required}
|
||||
{-output required}
|
||||
}
|
||||
set flags {}
|
||||
parse_key_args "export_magic_views" args arg_values $options flags_map $flags
|
||||
set script_dir $::env(finishing_tmpfiles)/magic_mag_save.tcl
|
||||
set commands \
|
||||
"
|
||||
"
|
||||
lef read $::env(TECH_LEF)
|
||||
if { \[info exist ::env(EXTRA_LEFS)\] } {
|
||||
set lefs_in \$::env(EXTRA_LEFS)
|
||||
@@ -243,19 +242,19 @@ def read $arg_values(-def)
|
||||
save $arg_values(-output)
|
||||
puts \"\[INFO\]: Done exporting $arg_values(-output)\"
|
||||
"
|
||||
set stream [open $script_dir w]
|
||||
puts $stream $commands
|
||||
close $stream
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$script_dir \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/save_mag.log]
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "mag export - magic"
|
||||
set stream [open $script_dir w]
|
||||
puts $stream $commands
|
||||
close $stream
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$script_dir \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) [index_file $::env(finishing_logs)/save_mag.log]
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "mag export - magic"
|
||||
}
|
||||
|
||||
proc run_magic_antenna_check {args} {
|
||||
@@ -265,7 +264,7 @@ proc run_magic_antenna_check {args} {
|
||||
set feedback_file [index_file $::env(finishing_logs)/ext2spice.antenna.feedback.txt]
|
||||
set magic_export $::env(finishing_tmpfiles)/magic_antenna.tcl
|
||||
set commands \
|
||||
"
|
||||
"
|
||||
lef read \$::env(TECH_LEF)
|
||||
if { \[info exist ::env(EXTRA_LEFS)\] } {
|
||||
set lefs_in \$::env(EXTRA_LEFS)
|
||||
@@ -296,30 +295,30 @@ if { ! \[file exists \$::env(DESIGN_NAME).ext\] } {
|
||||
antennacheck debug
|
||||
antennacheck
|
||||
"
|
||||
set magic_export_file [open $magic_export w]
|
||||
puts $magic_export_file $commands
|
||||
close $magic_export_file
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
# the following MAGTYPE has to be mag; antennacheck needs to know
|
||||
# about the underlying devices, layers, etc.
|
||||
set ::env(MAGTYPE) mag
|
||||
set magic_export_file [open $magic_export w]
|
||||
puts $magic_export_file $commands
|
||||
close $magic_export_file
|
||||
set ::env(PDKPATH) "$::env(PDK_ROOT)/$::env(PDK)/"
|
||||
# the following MAGTYPE has to be mag; antennacheck needs to know
|
||||
# about the underlying devices, layers, etc.
|
||||
set ::env(MAGTYPE) mag
|
||||
|
||||
set antenna_log [index_file $::env(finishing_logs)/antenna.log]
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$magic_export \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) $antenna_log
|
||||
set antenna_log [index_file $::env(finishing_logs)/antenna.log]
|
||||
try_catch magic \
|
||||
-noconsole \
|
||||
-dnull \
|
||||
-rcfile $::env(MAGIC_MAGICRC) \
|
||||
$magic_export \
|
||||
</dev/null \
|
||||
|& tee $::env(TERMINAL_OUTPUT) $antenna_log
|
||||
|
||||
# process the log
|
||||
try_catch awk "/Cell:/ {print \$2}" $antenna_log > $antenna_log
|
||||
# process the log
|
||||
try_catch awk "/Cell:/ {print \$2}" $antenna_log > $antenna_log
|
||||
|
||||
set ::env(ANTENNA_CHECKER_LOG) $antenna_log
|
||||
set ::env(ANTENNA_CHECKER_LOG) $antenna_log
|
||||
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "antenna check - magic"
|
||||
TIMER::timer_stop
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "antenna check - magic"
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -131,7 +131,6 @@ proc basic_macro_placement {args} {
|
||||
}
|
||||
|
||||
proc run_placement {args} {
|
||||
puts_info "Running Placement..."
|
||||
# |----------------------------------------------------|
|
||||
# |---------------- 3. PLACEMENT ------------------|
|
||||
# |----------------------------------------------------|
|
||||
|
||||
@@ -148,8 +148,6 @@ proc global_routing {args} {
|
||||
TIMER::timer_stop
|
||||
|
||||
exec echo "[TIMER::get_runtime]" | python3 $::env(SCRIPTS_DIR)/write_runtime.py "global routing - $tool"
|
||||
puts_info "Current Def is $::env(CURRENT_DEF)"
|
||||
puts_info "Current Guide is $::env(CURRENT_GUIDE)"
|
||||
}
|
||||
|
||||
proc detailed_routing_tritonroute {args} {
|
||||
@@ -413,14 +411,12 @@ proc run_routing {args} {
|
||||
file mkdir $sdf_path
|
||||
file mkdir $arc_def_path
|
||||
}
|
||||
if { $::env(ECO_ENABLE) == 1 && $::env(ECO_ITER) != 0 } {
|
||||
if { $::env(ECO_ENABLE) == 1 && $::env(ECO_ITER) != 0 } {
|
||||
set ::env(CURRENT_DEF) $::env(eco_results)/def/eco_$::env(ECO_ITER).def
|
||||
set ::env(CURRENT_NETLIST) $::env(eco_results)/net/eco_$::env(ECO_ITER).v
|
||||
}
|
||||
set ::env(ROUTING_CURRENT_DEF) $::env(CURRENT_DEF)
|
||||
|
||||
puts "Current DEF: $::env(CURRENT_DEF)"
|
||||
puts "Routing Current DEF: $::env(ROUTING_CURRENT_DEF)"
|
||||
# |----------------------------------------------------|
|
||||
# |---------------- 5. ROUTING ----------------------|
|
||||
# |----------------------------------------------------|
|
||||
|
||||
@@ -165,11 +165,11 @@ proc verilog_elaborate {args} {
|
||||
|
||||
proc yosys_rewrite_verilog {filename} {
|
||||
if { !$::env(LEC_ENABLE) } {
|
||||
puts_info "Skipping Verilog rewrite (logic equivalency checks are disabled)..."
|
||||
puts_verbose "Skipping Verilog rewrite (logic equivalency checks are disabled)..."
|
||||
return
|
||||
}
|
||||
if { $::env(YOSYS_REWRITE_VERILOG) } {
|
||||
puts_info "Skipping Verilog rewrite."
|
||||
if { !$::env(YOSYS_REWRITE_VERILOG) } {
|
||||
puts_verbose "Skipping Verilog rewrite."
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright 2020-2021 Efabless Corporation
|
||||
# Copyright 2020-2022 Efabless Corporation
|
||||
# ECO Flow Copyright 2021 The University of Michigan
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -200,7 +200,7 @@ proc run_openroad_script {args} {
|
||||
|
||||
set script_relative [relpath . $script]
|
||||
|
||||
puts_info "Executing OpenROAD with script '$script_relative'..."
|
||||
puts_verbose "Executing OpenROAD with script '$script_relative'..."
|
||||
|
||||
set exit_code [catch {exec {*}$args |& tee $::env(TERMINAL_OUTPUT) $arg_values(-indexed_log)} error_msg]
|
||||
|
||||
@@ -241,8 +241,8 @@ proc run_openroad_script {args} {
|
||||
}
|
||||
|
||||
proc increment_index {args} {
|
||||
puts_info "Incremented step index to $::env(CURRENT_INDEX)."
|
||||
set ::env(CURRENT_INDEX) [expr 1 + $::env(CURRENT_INDEX)]
|
||||
puts "\[STEP $::env(CURRENT_INDEX)\]"
|
||||
}
|
||||
|
||||
proc index_file {args} {
|
||||
@@ -277,8 +277,8 @@ proc flow_fail {args} {
|
||||
|
||||
proc calc_total_runtime {args} {
|
||||
## Calculate Total Runtime
|
||||
if {[info exists ::env(timer_start)] && [info exists ::env(datetime)]} {
|
||||
puts_info "Calculating Runtime From the Start..."
|
||||
if {[info exists ::env(timer_start)] && [info exists ::env(START_TIME)]} {
|
||||
puts_verbose "Calculating runtime..."
|
||||
set ::env(timer_end) [clock seconds]
|
||||
set options {
|
||||
{-report optional}
|
||||
@@ -345,6 +345,16 @@ proc puts_info {txt} {
|
||||
}
|
||||
}
|
||||
|
||||
proc puts_verbose {txt} {
|
||||
if { $::env(OPENLANE_VERBOSE) } {
|
||||
set message "\[INFO\]: $txt"
|
||||
puts "[color_text 6 "$message"]"
|
||||
if { [info exists ::env(RUN_DIR)] } {
|
||||
exec echo $message >> $::env(RUN_DIR)/openlane.log
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc show_warnings {msg} {
|
||||
if { [info exists ::env(RUN_DIR)] && [file exists $::env(RUN_DIR)/warnings.log] } {
|
||||
puts_info $msg
|
||||
|
||||
Reference in New Issue
Block a user