Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
f3aa9354aThis file is pinned to the selected release. Download the original to open it in your design tool.
# Copyright 2023-2025 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
from glob import glob
from typing import Any, Dict, List, Mapping
def migrate_old_config(config: Mapping[str, Any]) -> Dict[str, Any]:
new = dict(config)
# 1. Migrate SYNTH_DRIVING_CELL
if "SYNTH_DRIVING_CELL_PIN" in new:
del new["SYNTH_DRIVING_CELL"]
del new["SYNTH_DRIVING_CELL_PIN"]
new["SYNTH_DRIVING_CELL"] = (
f"{config['SYNTH_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}"
)
# 2. Migrate SYNTH_TIE{HI,LO}_CELL
if "SYNTH_TIEHI_PORT" in new:
del new["SYNTH_TIEHI_PORT"]
new["SYNTH_TIEHI_CELL"] = "/".join(config["SYNTH_TIEHI_PORT"].split(" "))
if "SYNTH_TIELO_PORT" in new:
del new["SYNTH_TIELO_PORT"]
new["SYNTH_TIELO_CELL"] = "/".join(config["SYNTH_TIELO_PORT"].split(" "))
# 3. Migrate SYNTH_BUFFER_CELL
if "SYNTH_MIN_BUF_PORT" in new:
del new["SYNTH_MIN_BUF_PORT"]
new["SYNTH_BUFFER_CELL"] = "/".join(config["SYNTH_MIN_BUF_PORT"].split(" "))
# 4. Migrate DIODE_CELL
if "DIODE_CELL_PIN" in new:
new["DIODE_CELL"] = f"{config['DIODE_CELL']}/{config['DIODE_CELL_PIN']}"
del new["DIODE_CELL_PIN"]
# 5. Interconnect Corners
if "RCX_RULESETS" not in new and config.get("RCX_RULES") is not None:
new["RCX_RULESETS"] = f"nom_* \"{config['RCX_RULES']}\""
if config.get("RCX_RULES_MIN") is not None:
new["RCX_RULESETS"] += f" min_* \"{config['RCX_RULES_MIN']}\""
if config.get("RCX_RULES_MAX") is not None:
new["RCX_RULESETS"] += f" max_* \"{config['RCX_RULES_MAX']}\""
if "RCX_RULES" in new:
del new["RCX_RULES"]
if "RCX_RULES_MIN" in new:
del new["RCX_RULES_MIN"]
if "RCX_RULES_MAX" in new:
del new["RCX_RULES_MAX"]
if "TECH_LEFS" not in new and config.get("TECH_LEF") is not None:
new["TECH_LEFS"] = f"nom_* \"{config['TECH_LEF']}\""
if config.get("TECH_LEF_MIN") is not None:
new["TECH_LEFS"] += f" min_* \"{config['TECH_LEF_MIN']}\""
if config.get("TECH_LEF_MAX") is not None:
new["TECH_LEFS"] += f" max_* \"{config['TECH_LEF_MAX']}\""
if "TECH_LEF" in new:
del new["TECH_LEF"]
if "TECH_LEF_MIN" in new:
del new["TECH_LEF_MIN"]
if "TECH_LEF_MAX" in new:
del new["TECH_LEF_MAX"]
# 7. RC
if "SYNTH_CAP_LOAD" in config:
new["OUTPUT_CAP_LOAD"] = config["SYNTH_CAP_LOAD"]
del new["SYNTH_CAP_LOAD"]
if "DATA_WIRE_RC_LAYER" in config:
del new["DATA_WIRE_RC_LAYER"]
if "CLOCK_WIRE_RC_LAYER" in config:
del new["CLOCK_WIRE_RC_LAYER"]
# 8. Implicit Open PDK Dependencies
if "CELL_VERILOG_MODELS" not in config:
model_glob = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.ref",
config["STD_CELL_LIBRARY"],
"verilog",
"*.v",
)
new["CELL_VERILOG_MODELS"] = sorted(
[path for path in glob(model_glob) if "_blackbox" not in path]
)
if "CELL_BB_VERILOG_MODELS" not in config:
bb_glob = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.ref",
config["STD_CELL_LIBRARY"],
"verilog",
"*__blackbox*.v",
)
if blackbox_models := glob(bb_glob):
new["CELL_BB_VERILOG_MODELS"] = sorted(blackbox_models)
if "CELL_SPICE_MODELS" not in config:
spice_glob = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.ref",
config["STD_CELL_LIBRARY"],
"spice",
"*.spice",
)
new["CELL_SPICE_MODELS"] = sorted(glob(spice_glob))
if "CELL_MAGS" not in config:
mag_glob = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.ref",
config["STD_CELL_LIBRARY"],
"mag",
"*.mag",
)
new["CELL_MAGS"] = sorted(glob(mag_glob))
if "CELL_MAGLEFS" not in config:
maglef_glob = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.ref",
config["STD_CELL_LIBRARY"],
"maglef",
"*.mag",
)
new["CELL_MAGLEFS"] = sorted(glob(maglef_glob))
if "MAGIC_PDK_SETUP" not in config:
new["MAGIC_PDK_SETUP"] = os.path.join(
config["PDK_ROOT"],
config["PDK"],
"libs.tech",
"magic",
f"{config['PDK']}.tcl",
)
# x1. Disconnected Modules (sky130)
if new["PDK"].startswith("sky130"):
new["IGNORE_DISCONNECTED_MODULES"] = "sky130_fd_sc_hd__conb_1"
# x2. Invalid Variables (gf180mcu)
if new["PDK"].startswith("gf180mcu"):
del new["GPIO_PADS_LEF"]
del new["GPIO_PADS_VERILOG"]
del new["CARRY_SELECT_ADDER_MAP"]
del new["FULL_ADDER_MAP"]
del new["RIPPLE_CARRY_ADDER_MAP"]
del new["SYNTH_LATCH_MAP"]
del new["TRISTATE_BUFFER_MAP"]
del new["KLAYOUT_DRC_TECH_SCRIPT"]
new["SYNTH_CLK_DRIVING_CELL"] = (
f"{config['SYNTH_CLK_DRIVING_CELL']}/{config['SYNTH_DRIVING_CELL_PIN']}"
)
# x3. Timing Corners
lib_sta: Dict[str, List[str]] = {}
ws = re.compile(r"\s+")
default_pvt = ""
def process_sta(key: str):
nonlocal new, default_pvt
lib_raw = new.pop(key, None)
if lib_raw is None:
return
lib = lib_raw.strip()
lib_list = ws.split(lib)
first_lib = os.path.basename(lib_list[0])[:-4]
pvt = first_lib.split("__")[1]
if default_pvt == "":
default_pvt = pvt
corner = f"*_{pvt}"
lib_sta[corner] = lib_list
if (
new["PDK"].startswith("sky130") or new["PDK"].startswith("gf180mcu")
) and "LIB" not in config:
process_sta("LIB_SYNTH")
process_sta("LIB_SLOWEST")
process_sta("LIB_FASTEST")
if new["PDK"].startswith("sky130"):
new["STA_CORNERS"] = [
"nom_tt_025C_1v80",
"nom_ss_100C_1v60",
"nom_ff_n40C_1v95",
"min_tt_025C_1v80",
"min_ss_100C_1v60",
"min_ff_n40C_1v95",
"max_tt_025C_1v80",
"max_ss_100C_1v60",
"max_ff_n40C_1v95",
]
# Code below adapted from OpenROAD Flow Scripts under the following license:
#
# BSD 3-Clause License
#
# Copyright (c) 2018-2023, The Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# new["LAYERS_RC"] = {
# "*tt*": {
# "li1": {"res": 7.176e-02, "cap": 1.499e-04},
# "met1": {"res": 8.929e-04, "cap": 1.72375e-04},
# "met2": {"res": 8.929e-04, "cap": 1.36233e-04},
# "met3": {"res": 1.567e-04, "cap": 2.14962e-04},
# "met4": {"res": 1.567e-04, "cap": 1.54087e-04},
# "met5": {"res": 1.781e-05, "cap": 1.54087e-04},
# },
# "*ff*": {
# "li1": {"res": 0.050232, "cap": 0.00010493},
# "met1": {"res": 0.0006250299999999999, "cap": 0.0001206625},
# "met2": {"res": 0.0006250299999999999, "cap": 9.53631e-05},
# "met3": {
# "res": 0.00010968999999999999,
# "cap": 0.00015047339999999998,
# },
# "met4": {
# "res": 0.00010968999999999999,
# "cap": 0.00010786089999999998,
# },
# "met5": {"res": 1.2467e-05, "cap": 0.00010786089999999998},
# },
# "*ss*": {
# "li1": {"res": 0.09328800000000001, "cap": 0.00019487},
# "met1": {"res": 0.00116077, "cap": 0.00022408750000000002},
# "met2": {"res": 0.00116077, "cap": 0.0001771029},
# "met3": {"res": 0.00020370999999999999, "cap": 0.0002794506},
# "met4": {
# "res": 0.00020370999999999999,
# "cap": 0.00020031309999999998,
# },
# "met5": {"res": 2.3153e-05, "cap": 0.00020031309999999998},
# },
# }
# new["VIAS_RC"] = {
# "*": {
# "mcon": {"res": 9.249146e-3},
# "via": {"res": 4.5e-3},
# "via2": {"res": 3.368786e-3},
# "via3": {"res": 0.376635e-3},
# "via4": {"res": 0.00580e-3},
# }
# }
elif new["PDK"].startswith("gf180mcu"):
new["STA_CORNERS"] = [
"nom_tt_025C_5v00",
"nom_ss_125C_4v50",
"nom_ff_n40C_5v50",
"min_tt_025C_5v00",
"min_ss_125C_4v50",
"min_ff_n40C_5v50",
"max_tt_025C_5v00",
"max_ss_125C_4v50",
"max_ff_n40C_5v50",
]
new["DEFAULT_CORNER"] = f"nom_{default_pvt}"
new["TIMING_VIOLATION_CORNERS"] = ["*tt*"]
new["LIB"] = lib_sta
# x4. Constraints (sky130/gf180mcu)
if new["PDK"].startswith("sky130") or new["PDK"].startswith("gf180mcu"):
new["MAX_FANOUT_CONSTRAINT"] = 10
new["CLOCK_UNCERTAINTY_CONSTRAINT"] = 0.25
new["CLOCK_TRANSITION_CONSTRAINT"] = 0.15
new["TIME_DERATING_CONSTRAINT"] = 5
new["IO_DELAY_CONSTRAINT"] = 20
new["FP_IO_MIN_DISTANCE"] = 3
new["FP_IO_HLENGTH"] = 4
new["FP_IO_VLENGTH"] = 4
# x5. Primary Signoff Tool
if new["PDK"].startswith("sky130") or new["PDK"].startswith("gf180mcu"):
new["PRIMARY_GDSII_STREAMOUT_TOOL"] = "magic"
# x6. Heuristic Antenna Thresholds
if new["PDK"].startswith("sky130"):
new["HEURISTIC_ANTENNA_THRESHOLD"] = 90
elif new["PDK"].startswith("gf180mcu"):
new["HEURISTIC_ANTENNA_THRESHOLD"] = 130
return new