mirror of
https://github.com/The-OpenROAD-Project/OpenLane.git
synced 2026-05-29 00:23:55 +08:00
+ Added optional multiple **process corner** technology lef support (min/max/nom), in addition to the already existing multiple **timing corner** support (ss/tt/ff). This will also be our nomenclature going fwd. + Parasitics extraction now run at all process corners, and multi-corner analysis is run at all three process corners ~ `finishing` -> `signoff` ~ Parasitics extraction and STA are now an independent step instead of being lumped in routing, as part of the signoff block ~ Update OpenROAD ~ Update Open_PDKs, Sky130, and Magic ~ PDK verification made more PDK agnostic outside of env.py ~ Made RCX use LEF files instead of multiple configuration variables/set_rc.tcl ~ `prep_lefs` more or less rewritten - Removed redundant RCX variables - Removed `-order_wires` from various `read_def`s in OpenROAD- deprecated, apparently
148 lines
4.1 KiB
Python
148 lines
4.1 KiB
Python
# Copyright 2021 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 re
|
|
import sys
|
|
import yaml
|
|
import click
|
|
from typing import List, Optional
|
|
|
|
|
|
def timestamp_to_seconds(runtime: str) -> Optional[float]:
|
|
pattern = re.compile(r"\s*([\d+]+)h([\d+]+)m([\d+]+)s(?:([\d+]+)+ms)?")
|
|
m = pattern.match(runtime)
|
|
if m is None:
|
|
return None
|
|
time = (
|
|
int(m.group(1)) * 60 * 60
|
|
+ int(m.group(2)) * 60
|
|
+ int(m.group(3))
|
|
+ int(m.group(4) or 0) / 1000.0
|
|
)
|
|
return time
|
|
|
|
|
|
def seconds_to_timestamp(runtime: float) -> str:
|
|
hours = int(runtime // 3600)
|
|
minutes_and_seconds_and_milliseconds = runtime % 3600
|
|
minutes = int(minutes_and_seconds_and_milliseconds // 60)
|
|
seconds_and_milliseconds = minutes_and_seconds_and_milliseconds % 60
|
|
seconds = int(seconds_and_milliseconds // 1)
|
|
milliseconds = int((seconds_and_milliseconds % 1) * 1000)
|
|
return f"{hours}h{minutes}m{seconds}s{milliseconds}ms"
|
|
|
|
|
|
runtime_file_path: str = os.path.join(os.environ["RUN_DIR"], "runtime.yaml")
|
|
|
|
|
|
def read_runtime_yaml():
|
|
runtime_data_str: str = "[]"
|
|
try:
|
|
runtime_data_str = open(runtime_file_path).read()
|
|
except FileNotFoundError:
|
|
pass
|
|
|
|
yaml_docs: List[List] = list(yaml.safe_load_all(runtime_data_str))
|
|
|
|
return yaml_docs[0]
|
|
|
|
|
|
def write_runtime(status: str, time_in: float):
|
|
runtime_data = read_runtime_yaml()
|
|
|
|
obj = {}
|
|
obj["status"] = f"{os.environ['CURRENT_INDEX']} - {status}"
|
|
obj["runtime_s"] = round(time_in, 2)
|
|
obj["runtime_ts"] = seconds_to_timestamp(time_in)
|
|
|
|
runtime_data.append(obj)
|
|
|
|
with open(runtime_file_path, "w") as f:
|
|
f.write(yaml.safe_dump(runtime_data, sort_keys=False))
|
|
|
|
|
|
def conclude_run(status: str, time_in: float):
|
|
runtime_data = read_runtime_yaml()
|
|
|
|
final_runtime_data = []
|
|
|
|
timer_start = os.getenv("timer_start")
|
|
if timer_start is None:
|
|
raise Exception(
|
|
"Attempted to conclude a run without timer_start environment variable set"
|
|
)
|
|
timer_start = float(timer_start)
|
|
|
|
timer_routed = os.getenv("timer_routed")
|
|
routed_s = -1
|
|
routed_ts = "-1"
|
|
if timer_routed is not None:
|
|
timer_routed = float(timer_routed)
|
|
routed_s = timer_routed - timer_start
|
|
routed_ts = seconds_to_timestamp(routed_s)
|
|
|
|
obj = {}
|
|
obj["status"] = "routed"
|
|
obj["runtime_s"] = routed_s
|
|
obj["runtime_ts"] = routed_ts
|
|
final_runtime_data.append(obj)
|
|
|
|
done_s = time_in - timer_start
|
|
done_ts = seconds_to_timestamp(done_s)
|
|
|
|
obj = {}
|
|
obj["status"] = status
|
|
obj["runtime_s"] = done_s
|
|
obj["runtime_ts"] = done_ts
|
|
final_runtime_data.append(obj)
|
|
|
|
with open(runtime_file_path, "w") as f:
|
|
f.write(yaml.safe_dump_all([runtime_data, final_runtime_data], sort_keys=False))
|
|
|
|
|
|
@click.command("write_runtime")
|
|
@click.option("--conclude/--no-conclude", default=False)
|
|
@click.option(
|
|
"--seconds/--timestamp",
|
|
"seconds",
|
|
default=False,
|
|
help="Process the input string either as a timestamp or a floating point second value",
|
|
)
|
|
@click.option(
|
|
"--time-in",
|
|
default=None,
|
|
help="If this argument is not specified, time is read from stdin.",
|
|
)
|
|
@click.argument("status")
|
|
def cli(seconds, conclude, time_in, status):
|
|
if time_in is None:
|
|
time_in = sys.stdin.read().rstrip()
|
|
|
|
if seconds:
|
|
time_in = float(time_in)
|
|
else:
|
|
temp = timestamp_to_seconds(time_in)
|
|
if temp is None:
|
|
raise Exception(f"Invalid timestamp {time_in}")
|
|
time_in = temp
|
|
|
|
if conclude:
|
|
conclude_run(status, time_in)
|
|
else:
|
|
write_runtime(status, time_in)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
cli()
|